Explorar o código

[Wip 0000] 可配置首页公共组件开发、看板模块数据修改

houzekong hai 10 meses
pai
achega
751cedbcc5

BIN=BIN
src/assets/images/vent/home/mini-board-1.png


+ 0 - 19
src/views/vent/home/billboard/components/ContentD.vue

@@ -1,19 +0,0 @@
-<!-- eslint-disable vue/multi-word-component-names -->
-<template>
-  <!-- <CommonTitle class="mb-10px" label="测试" value="是我啊" />
-  <CommonTable :columns="COLUMN_A" :data="[{ a: 1, b: 2, c: 3 }]" /> -->
-</template>
-<script lang="ts" setup>
-  // import { computed, ref } from 'vue';
-  // import BaseCard from './components/BaseCard.vue';
-  // import ArrowButton from './components/ArrowButton.vue';
-  // import CommonTable from './components/CommonTable.vue';
-  // import CommonTitle from './components/CommonTitle.vue';
-  // import { BILLBOARDS, COLUMN_A } from './billboard.data';
-  // import ListItemA from './components/ListItemA.vue';
-  // import ListItemB from './components/ListItemB.vue';
-  // import ListItemC from './components/ListItemC.vue';
-  // import FileOverview from './components/FileOverview.vue';
-  // import mapComponent from './components/3Dmap/index.vue';
-</script>
-<style lang="less" scoped></style>

+ 8 - 7
src/views/vent/home/billboard/components/LargeBoard.vue

@@ -1,10 +1,10 @@
 <!-- eslint-disable vue/multi-word-component-names -->
 <template>
-  <div class="list-item flex justify-around flex-col" :class="`list-item-${type}`">
+  <div class="large-board flex justify-around flex-col" :class="`large-board-${type}`">
     <div>
       <slot name="label">{{ label }}</slot>
     </div>
-    <div class="list-item__value">
+    <div class="large-board__value">
       <slot name="value">{{ value }}</slot>
     </div>
   </div>
@@ -31,8 +31,8 @@
     src: url('@/assets/font/douyuFont.otf');
   }
 
-  .list-item {
-    font-size: 20px;
+  .large-board {
+    font-size: 16px;
     height: 93px;
     width: 158px;
     padding: 10px;
@@ -40,14 +40,15 @@
     background-size: 100% 100%;
   }
 
-  .list-item-to-top-right {
+  .large-board-to-top-right {
     background: url('@/assets/images/company/list-item-7.png') no-repeat center;
   }
-  .list-item-to-bottom-right {
+  .large-board-to-bottom-right {
     background: url('@/assets/images/company/list-item-8.png') no-repeat center;
   }
 
-  .list-item__value {
+  .large-board__value {
+    font-size: 20px;
     font-family: douyuFont;
     color: @vent-gas-primary-text;
   }

+ 5 - 5
src/views/vent/home/billboard/components/ListItem.vue

@@ -1,6 +1,6 @@
 <!-- eslint-disable vue/multi-word-component-names -->
 <template>
-  <div class="list-item flex justify-between" :class="`list-item-${type}`">
+  <div class="my-list-item flex justify-between" :class="`my-list-item-${type}`">
     <div>
       <slot name="icon">
         <SvgIcon class="icon" size="18" :name="icon" />
@@ -9,7 +9,7 @@
         <span class="ml-30px">{{ label }}</span>
       </slot>
     </div>
-    <div class="list-item__value">
+    <div class="my-list-item__value">
       <slot name="value">{{ value }}</slot>
     </div>
   </div>
@@ -36,7 +36,7 @@
 <style lang="less" scoped>
   @import '@/design/vent/color.less';
 
-  .list-item {
+  .my-list-item {
     height: 34px;
     line-height: 34px;
     width: 364px;
@@ -45,10 +45,10 @@
     background-size: 100% 100%;
   }
 
-  .list-item-blue {
+  .my-list-item-blue {
     background: url('@/assets/images/company/list-item-1.png') no-repeat center;
   }
-  .list-item-green {
+  .my-list-item-green {
     background: url('@/assets/images/company/list-item-2.png') no-repeat center;
   }
 </style>

+ 7 - 7
src/views/vent/home/billboard/components/MiniBoard.vue

@@ -1,10 +1,10 @@
 <!-- eslint-disable vue/multi-word-component-names -->
 <template>
-  <div class="list-item flex justify-between" :class="`list-item-${type}`">
+  <div class="mini-board flex justify-between" :class="`mini-board-${type}`">
     <div>
       <slot name="label">{{ label }}</slot>
     </div>
-    <div class="list-item__value">
+    <div class="mini-board__value">
       <slot name="value">{{ value }}</slot>
     </div>
   </div>
@@ -28,7 +28,7 @@
 <style lang="less" scoped>
   @import '@/design/vent/color.less';
 
-  .list-item {
+  .mini-board {
     height: 62px;
     line-height: 62px;
     // width: 200px;
@@ -37,16 +37,16 @@
     background-size: 100% auto;
   }
 
-  .list-item-green-to-right {
+  .mini-board-green-to-right {
     background: url('@/assets/images/company/list-item-3.png') no-repeat center;
   }
-  .list-item-blue-to-right {
+  .mini-board-blue-to-right {
     background: url('@/assets/images/company/list-item-4.png') no-repeat center;
   }
-  .list-item-green-to-left {
+  .mini-board-green-to-left {
     background: url('@/assets/images/company/list-item-5.png') no-repeat center;
   }
-  .list-item-blue-to-left {
+  .mini-board-blue-to-left {
     background: url('@/assets/images/company/list-item-6.png') no-repeat center;
   }
 </style>

+ 11 - 2
src/views/vent/home/billboard/index.vue

@@ -7,10 +7,17 @@
     <a-row class="company-content" :gutter="10">
       <a-col v-for="(item, i) in shownBillboards" :key="`svvhbi-${i}`" :span="6">
         <BaseCard :title="item.title">
-          <component :is="COMPONENTS_MAP.get(item.type)" />
+          <component :is="COMPONENTS_MAP.get(billboardType)" />
         </BaseCard>
       </a-col>
     </a-row>
+    <div style="position: absolute; top: 0; left: 0">
+      <a-button @click="billboardType = 'dust'">切换粉尘看板</a-button>
+      <a-button @click="billboardType = 'fire'">切换火灾看板</a-button>
+      <a-button @click="billboardType = 'file'">切换文件看板</a-button>
+      <a-button @click="billboardType = 'ventilate'">切换风扇看板</a-button>
+      <a-button @click="billboardType = 'gas'">切换瓦斯看板</a-button>
+    </div>
     <ArrowButton point-to="left" class="company__arrow_left" @click="changeCurrentPage(-1)" />
     <ArrowButton point-to="right" class="company__arrow_right" @click="changeCurrentPage(1)" />
   </div>
@@ -37,6 +44,8 @@
   function changeCurrentPage(pagecount: number) {
     currentPage.value = Math.max((currentPage.value + pagecount) % totalPage, 1);
   }
+
+  const billboardType = ref('dust');
 </script>
 <style lang="less" scoped>
   @font-face {
@@ -72,7 +81,7 @@
     .company-content {
       width: 100%;
       height: calc(100% - 97px);
-      padding: 50px 100px 0 100px;
+      padding: 30px 100px 0 100px;
     }
     .company__arrow_left {
       position: absolute;

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

@@ -0,0 +1,79 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <CostumeHeader :api="fetchOptions" @change="selectDeviceByID">
+    <div class="w-200px flex flex-items-center">
+      <RightCircleOutlined class="w-30px" />
+      <div class="flex-grow-1">
+        {{ selectedDevice.strinstallpos }}
+      </div>
+    </div>
+  </CostumeHeader>
+  <Bar
+    series-prop-type="valueA"
+    x-axis-prop-type="x"
+    :chart-data="[
+      { valueA: 1, valueB: 1, x: 2 },
+      { valueA: 1, valueB: 1, x: 4 },
+    ]"
+    height="250px"
+  />
+  <!-- <div class="flex justify-around mt-10px">
+    <MiniBoard v-for="item in configs" :key="item.prop" :label="item.label" :value="selectedDevice[item.prop]" />
+  </div> -->
+</template>
+<script lang="ts" setup>
+  import { onMounted, ref } from 'vue';
+  import { list as cfgList } from '@/views/vent/deviceManager/configurationTable/configuration.api';
+  import { list } from '@/views/vent/deviceManager/deviceTable/device.api';
+  import CostumeHeader from './CostumeHeader.vue';
+  import { RightCircleOutlined } from '@ant-design/icons-vue';
+  import Bar from '/@/components/chart/Bar.vue';
+  // import MiniBoard from './MiniBoard.vue';
+  // import mapComponent from './components/3Dmap/index.vue';
+
+  // 设备类别,是个枚举 TODO: 将手动换为自动获取类别
+  const devicekind = 'fanlocal';
+
+  const configs = ref<{ prop: string; label: string }[]>([]);
+  function fetchConfig() {
+    cfgList({
+      deviceType: 'devicekind',
+    }).then(({ records }) => {
+      const moduleData = JSON.parse(records[0]?.moduleData);
+      configs.value = Object.keys(moduleData).map((k) => {
+        return {
+          prop: k,
+          label: moduleData[k],
+        };
+      });
+    });
+  }
+
+  const devices = ref<any[]>([]);
+  const selectedDevice = ref<any>({});
+  function selectDeviceByID(id: string) {
+    selectedDevice.value = devices.value.find((e) => {
+      return e.id === id;
+    });
+  }
+  // 获取全部局扇的数据,并以选项格式返回给 Header 消费
+  function fetchOptions() {
+    return list({
+      devicekind,
+    }).then(({ records }) => {
+      devices.value = records;
+      selectDeviceByID(records[0]?.id);
+      return records.map((e) => {
+        return {
+          label: e.strinstallpos,
+          key: e.id,
+        };
+      });
+    });
+  }
+
+  onMounted(() => {
+    fetchConfig();
+  });
+</script>
+<style scoped></style>

+ 21 - 18
src/views/vent/home/configurable/components/CostumeHeader.vue

@@ -1,23 +1,25 @@
 <template>
   <div class="w-100% flex costume-header__header">
     <!-- 选择下拉框,自动填充剩余空间,这种实现是因为 Select 不支持 suffix -->
-    <Dropdown class="flex-grow-1 costume-header__header_left" :trigger="['click']" :bordered="false" @open-change="visible = $event">
-      <div class="w-100% flex flex-items-center" @click.prevent>
-        <SwapOutlined class="w-30px" />
-        <div class="flex-grow-1">
-          {{ selectedLabel }}
+    <slot name="select">
+      <Dropdown class="flex-grow-1 costume-header__header_left" :trigger="['click']" :bordered="false" @open-change="visible = $event">
+        <div class="w-100% flex flex-items-center" @click.prevent>
+          <SwapOutlined class="w-30px" />
+          <div class="flex-grow-1">
+            {{ selectedLabel }}
+          </div>
+          <CaretUpOutlined class="w-30px" v-if="visible" />
+          <CaretDownOutlined class="w-30px" v-else />
         </div>
-        <CaretUpOutlined class="w-30px" v-if="visible" />
-        <CaretDownOutlined class="w-30px" v-else />
-      </div>
-      <template #overlay>
-        <Menu :selected-keys="[selectedKey]" @click="selectHandler">
-          <MenuItem v-for="item in options" :key="item.key" :title="item.label">
-            {{ item.label }}
-          </MenuItem>
-        </Menu>
-      </template>
-    </Dropdown>
+        <template #overlay>
+          <Menu :selected-keys="[selectedKey]" @click="selectHandler">
+            <MenuItem v-for="item in options" :key="item.key" :title="item.label">
+              {{ item.label }}
+            </MenuItem>
+          </Menu>
+        </template>
+      </Dropdown>
+    </slot>
     <slot class="costume-header__header_right"></slot>
   </div>
 </template>
@@ -27,7 +29,7 @@
   import { SwapOutlined, CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons-vue';
 
   const props = defineProps<{
-    api: () => Promise<{ label: any; key: any }[]>;
+    api?: () => Promise<{ label: any; key: any }[]>;
   }>();
   const emit = defineEmits(['change']);
 
@@ -48,6 +50,7 @@
 
   onMounted(() => {
     // 获取数据
+    if (!props.api) return;
     props.api().then((opts) => {
       options.value = opts;
       selectHandler({ key: opts[0]?.key, item: { title: opts[0]?.label } });
@@ -58,7 +61,7 @@
 </script>
 <style scoped>
   .costume-header__header {
-    /* height: 30px; */
+    height: 30px;
     background-image: linear-gradient(90deg, #3df6ff44, transparent 20%, transparent 80%, #3df6ff44);
   }
   .costume-header__header_left {

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

@@ -0,0 +1,73 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <CostumeHeader>
+    <template #select></template>
+    <div class="w-200px flex flex-items-center">
+      <RightCircleOutlined class="w-30px" />
+      <div class="flex-grow-1">
+        网络断开
+        {{ warns.length }}
+      </div>
+    </div>
+  </CostumeHeader>
+  <Timeline>
+    <TimelineItem v-for="(item, i) in warns" :key="`svvhccdw-${i}`">
+      {{ item.label }}
+    </TimelineItem>
+  </Timeline>
+</template>
+<script lang="ts" setup>
+  import { onMounted, ref } from 'vue';
+  // import { list as cfgList } from '@/views/vent/deviceManager/configurationTable/configuration.api';
+  // import { list } from '@/views/vent/deviceManager/deviceTable/device.api';
+  import CostumeHeader from './CostumeHeader.vue';
+  import { RightCircleOutlined } from '@ant-design/icons-vue';
+  // import MiniBoard from './MiniBoard.vue';
+  import { Timeline, TimelineItem } from 'ant-design-vue';
+  // import mapComponent from './components/3Dmap/index.vue';
+
+  // 设备类别,是个枚举 TODO: 将手动换为自动获取类别
+  // const devicekind = 'fanlocal';
+
+  // const configs = ref<{ prop: string; label: string }[]>([]);
+  // function fetchConfig() {
+  //   cfgList({
+  //     deviceType: 'devicekind',
+  //   }).then(({ records }) => {
+  //     const moduleData = JSON.parse(records[0]?.moduleData);
+  //     configs.value = Object.keys(moduleData).map((k) => {
+  //       return {
+  //         prop: k,
+  //         label: moduleData[k],
+  //       };
+  //     });
+  //   });
+  // }
+
+  const warns = ref([
+    {
+      label: 'test',
+      count: 0,
+    },
+  ]);
+  // 获取全部局扇的数据,并以选项格式返回给 Header 消费
+  // function fetchOptions() {
+  //   return list({
+  //     devicekind,
+  //   }).then(({ records }) => {
+  //     devices.value = records;
+  //     selectDeviceByID(records[0]?.id);
+  //     return records.map((e) => {
+  //       return {
+  //         label: e.strinstallpos,
+  //         key: e.id,
+  //       };
+  //     });
+  //   });
+  // }
+
+  onMounted(() => {
+    // fetchConfig();
+  });
+</script>
+<style scoped></style>

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

@@ -0,0 +1,132 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <div class="mini-board" :class="`mini-board_${type}`">
+    <template v-if="layout === 'val-top'">
+      <slot name="value">
+        <div class="mini-board__value" :class="`mini-board__value_${type}`">
+          {{ value }}
+        </div>
+      </slot>
+      <slot name="label">
+        <div class="mini-board__label" :class="`mini-board__label_${type}`">
+          {{ label }}
+        </div>
+      </slot>
+    </template>
+    <template v-if="layout === 'label-top'">
+      <slot name="label">
+        <div class="mini-board__label" :class="`mini-board__label_${type}`">
+          {{ label }}
+        </div>
+      </slot>
+      <slot name="value">
+        <div class="mini-board__value" :class="`mini-board__value_${type}`">
+          {{ value }}
+        </div>
+      </slot>
+    </template>
+  </div>
+</template>
+<script lang="ts" setup>
+  withDefaults(
+    defineProps<{
+      label: string;
+      value?: string;
+      // 告示牌布局,类型为:'val-top' | 'label-top'
+      layout: string;
+      // 告示牌类型,类型为:'A' | 'B' | 'C' | 'D'
+      type?: string;
+    }>(),
+    {
+      value: '/',
+      type: 'A',
+      layout: 'val-top',
+    }
+  );
+
+  defineEmits(['click']);
+</script>
+<style lang="less" scoped>
+  @import '@/design/vent/color.less';
+
+  .mini-board {
+    height: 50px;
+    line-height: 25px;
+    width: 130px;
+    padding: 0 5px 0 5px;
+    // box-sizing: border-box;
+    text-align: center;
+    background-size: 100% 100%;
+    position: relative;
+  }
+
+  .mini-board_A {
+    width: 120px;
+    height: 60px;
+    background-image: url('@/assets/images/company/area3.png');
+    background-size: 100% 100%;
+  }
+  .mini-board_B {
+    width: 131px;
+    height: 64px;
+    background-image: url('@/assets/images/vent/value-bg.png');
+    background-size: 100% auto;
+    background-position: center bottom;
+    background-repeat: no-repeat;
+  }
+  .mini-board_C {
+    width: 121px;
+    height: 69px;
+    background-image: url('@/assets/images/vent/vent-param-bg.png');
+  }
+  .mini-board_D {
+    width: 105px;
+    height: 58px;
+    background-image: url('@/assets/images/vent/home/mini-board-1.png');
+    background-position: center bottom;
+    background-repeat: no-repeat;
+  }
+
+  .mini-board__value_A {
+    color: @vent-gas-primary-text;
+    font-size: 20px;
+    font-weight: bold;
+    height: 30px;
+    line-height: 30px;
+  }
+  // .mini-board__label_A {
+  // }
+
+  .mini-board__value_B {
+    font-size: 20px;
+    font-weight: bold;
+    height: 40px;
+    line-height: 40px;
+  }
+  .mini-board__label_B {
+    line-height: 20px;
+    height: 20px;
+  }
+
+  .mini-board__value_C {
+    color: @vent-gas-primary-text;
+    height: 40px;
+    line-height: 40px;
+    font-size: 20px;
+    font-weight: bold;
+  }
+  // .mini-board__label_C {
+  // }
+
+  .mini-board__value_D {
+    color: @vent-gas-primary-text;
+    font-size: 20px;
+    font-weight: bold;
+    height: 40px;
+    line-height: 40px;
+  }
+  .mini-board__label_D {
+    line-height: 20px;
+    height: 20px;
+  }
+</style>

+ 3 - 2
src/views/vent/home/configurable/components/SubVentilate.vue

@@ -7,8 +7,8 @@
       </div>
     </div>
   </CostumeHeader>
-  <div>
-    <div v-for="item in configs" :key="item.prop"> {{ item.label }}{{ selectedDevice[item.prop] }} </div>
+  <div class="flex justify-around mt-10px">
+    <MiniBoard v-for="item in configs" :key="item.prop" :label="item.label" :value="selectedDevice[item.prop]" type="A" />
   </div>
 </template>
 <script lang="ts" setup>
@@ -17,6 +17,7 @@
   import { list } from '@/views/vent/deviceManager/deviceTable/device.api';
   import CostumeHeader from './CostumeHeader.vue';
   import { RightCircleOutlined } from '@ant-design/icons-vue';
+  import MiniBoard from './MiniBoard.vue';
   // import mapComponent from './components/3Dmap/index.vue';
 
   // 设备类别,是个枚举 TODO: 将手动换为自动获取类别

+ 69 - 0
src/views/vent/home/configurable/components/Ventilate.vue

@@ -0,0 +1,69 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <CostumeHeader :api="fetchOptions" @change="selectDeviceByID">
+    <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="item in configs" :key="item.prop" :label="item.label" :value="selectedDevice[item.prop]" type="C" />
+  </div>
+</template>
+<script lang="ts" setup>
+  import { onMounted, ref } from 'vue';
+  import { list as cfgList } from '@/views/vent/deviceManager/configurationTable/configuration.api';
+  import { list } from '@/views/vent/deviceManager/deviceTable/device.api';
+  import CostumeHeader from './CostumeHeader.vue';
+  import { RightCircleOutlined } from '@ant-design/icons-vue';
+  import MiniBoard from './MiniBoard.vue';
+  // import mapComponent from './components/3Dmap/index.vue';
+
+  // 设备类别,是个枚举 TODO: 将手动换为自动获取类别
+  const devicekind = 'fanlocal';
+
+  const configs = ref<{ prop: string; label: string }[]>([]);
+  function fetchConfig() {
+    cfgList({
+      deviceType: 'devicekind',
+    }).then(({ records }) => {
+      const moduleData = JSON.parse(records[0]?.moduleData);
+      configs.value = Object.keys(moduleData).map((k) => {
+        return {
+          prop: k,
+          label: moduleData[k],
+        };
+      });
+    });
+  }
+
+  const devices = ref<any[]>([]);
+  const selectedDevice = ref<any>({});
+  function selectDeviceByID(id: string) {
+    selectedDevice.value = devices.value.find((e) => {
+      return e.id === id;
+    });
+  }
+  // 获取全部局扇的数据,并以选项格式返回给 Header 消费
+  function fetchOptions() {
+    return list({
+      devicekind,
+    }).then(({ records }) => {
+      devices.value = records;
+      selectDeviceByID(records[0]?.id);
+      return records.map((e) => {
+        return {
+          label: e.strinstallpos,
+          key: e.id,
+        };
+      });
+    });
+  }
+
+  onMounted(() => {
+    fetchConfig();
+  });
+</script>
+<style scoped></style>

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

@@ -0,0 +1,69 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <CostumeHeader :api="fetchOptions" @change="selectDeviceByID">
+    <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="item in configs" :key="item.prop" :label="item.label" :value="selectedDevice[item.prop]" layout="label-top" type="D" />
+  </div>
+</template>
+<script lang="ts" setup>
+  import { onMounted, ref } from 'vue';
+  import { list as cfgList } from '@/views/vent/deviceManager/configurationTable/configuration.api';
+  import { list } from '@/views/vent/deviceManager/deviceTable/device.api';
+  import CostumeHeader from './CostumeHeader.vue';
+  import { RightCircleOutlined } from '@ant-design/icons-vue';
+  import MiniBoard from './MiniBoard.vue';
+  // import mapComponent from './components/3Dmap/index.vue';
+
+  // 设备类别,是个枚举 TODO: 将手动换为自动获取类别
+  const devicekind = 'fanlocal';
+
+  const configs = ref<{ prop: string; label: string }[]>([]);
+  function fetchConfig() {
+    cfgList({
+      deviceType: 'devicekind',
+    }).then(({ records }) => {
+      const moduleData = JSON.parse(records[0]?.moduleData);
+      configs.value = Object.keys(moduleData).map((k) => {
+        return {
+          prop: k,
+          label: moduleData[k],
+        };
+      });
+    });
+  }
+
+  const devices = ref<any[]>([]);
+  const selectedDevice = ref<any>({});
+  function selectDeviceByID(id: string) {
+    selectedDevice.value = devices.value.find((e) => {
+      return e.id === id;
+    });
+  }
+  // 获取全部局扇的数据,并以选项格式返回给 Header 消费
+  function fetchOptions() {
+    return list({
+      devicekind,
+    }).then(({ records }) => {
+      devices.value = records;
+      selectDeviceByID(records[0]?.id);
+      return records.map((e) => {
+        return {
+          label: e.strinstallpos,
+          key: e.id,
+        };
+      });
+    });
+  }
+
+  onMounted(() => {
+    fetchConfig();
+  });
+</script>
+<style scoped></style>

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

@@ -0,0 +1,69 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <CostumeHeader :api="fetchOptions" @change="selectDeviceByID">
+    <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="item in configs" :key="item.prop" :label="item.label" :value="selectedDevice[item.prop]" />
+  </div> -->
+</template>
+<script lang="ts" setup>
+  import { onMounted, ref } from 'vue';
+  import { list as cfgList } from '@/views/vent/deviceManager/configurationTable/configuration.api';
+  import { list } from '@/views/vent/deviceManager/deviceTable/device.api';
+  import CostumeHeader from './CostumeHeader.vue';
+  import { RightCircleOutlined } from '@ant-design/icons-vue';
+  // import MiniBoard from './MiniBoard.vue';
+  // import mapComponent from './components/3Dmap/index.vue';
+
+  // 设备类别,是个枚举 TODO: 将手动换为自动获取类别
+  const devicekind = 'fanlocal';
+
+  const configs = ref<{ prop: string; label: string }[]>([]);
+  function fetchConfig() {
+    cfgList({
+      deviceType: 'devicekind',
+    }).then(({ records }) => {
+      const moduleData = JSON.parse(records[0]?.moduleData);
+      configs.value = Object.keys(moduleData).map((k) => {
+        return {
+          prop: k,
+          label: moduleData[k],
+        };
+      });
+    });
+  }
+
+  const devices = ref<any[]>([]);
+  const selectedDevice = ref<any>({});
+  function selectDeviceByID(id: string) {
+    selectedDevice.value = devices.value.find((e) => {
+      return e.id === id;
+    });
+  }
+  // 获取全部局扇的数据,并以选项格式返回给 Header 消费
+  function fetchOptions() {
+    return list({
+      devicekind,
+    }).then(({ records }) => {
+      devices.value = records;
+      selectDeviceByID(records[0]?.id);
+      return records.map((e) => {
+        return {
+          label: e.strinstallpos,
+          key: e.id,
+        };
+      });
+    });
+  }
+
+  onMounted(() => {
+    fetchConfig();
+  });
+</script>
+<style scoped></style>

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

@@ -0,0 +1,84 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <CostumeHeader :api="fetchOptions" @change="selectDeviceByID">
+    <div class="w-200px flex flex-items-center">
+      <RightCircleOutlined class="w-30px" />
+      <div class="flex-grow-1">
+        {{ selectedDevice.strinstallpos }}
+      </div>
+    </div>
+  </CostumeHeader>
+  <LineMulti
+    :prop-type-arr="
+      new Map([
+        ['valueA', '值A'],
+        ['valueB', '值B'],
+      ])
+    "
+    x-axis-prop-type="x"
+    :chart-data="[
+      { valueA: 1, valueB: 1, x: 2 },
+      { valueA: 1, valueB: 1, x: 4 },
+    ]"
+    height="170px"
+  />
+  <div class="flex justify-around mt-10px">
+    <MiniBoard v-for="item in configs" :key="item.prop" :label="item.label" :value="selectedDevice[item.prop]" layout="label-top" type="B" />
+  </div>
+</template>
+<script lang="ts" setup>
+  import { onMounted, ref } from 'vue';
+  import { list as cfgList } from '@/views/vent/deviceManager/configurationTable/configuration.api';
+  import { list } from '@/views/vent/deviceManager/deviceTable/device.api';
+  import CostumeHeader from './CostumeHeader.vue';
+  import { RightCircleOutlined } from '@ant-design/icons-vue';
+  import MiniBoard from './MiniBoard.vue';
+  import LineMulti from '/@/components/chart/LineMulti.vue';
+  // import mapComponent from './components/3Dmap/index.vue';
+
+  // 设备类别,是个枚举 TODO: 将手动换为自动获取类别
+  const devicekind = 'fanlocal';
+
+  const configs = ref<{ prop: string; label: string }[]>([]);
+  function fetchConfig() {
+    cfgList({
+      deviceType: 'devicekind',
+    }).then(({ records }) => {
+      const moduleData = JSON.parse(records[0]?.moduleData);
+      configs.value = Object.keys(moduleData).map((k) => {
+        return {
+          prop: k,
+          label: moduleData[k],
+        };
+      });
+    });
+  }
+
+  const devices = ref<any[]>([]);
+  const selectedDevice = ref<any>({});
+  function selectDeviceByID(id: string) {
+    selectedDevice.value = devices.value.find((e) => {
+      return e.id === id;
+    });
+  }
+  // 获取全部局扇的数据,并以选项格式返回给 Header 消费
+  function fetchOptions() {
+    return list({
+      devicekind,
+    }).then(({ records }) => {
+      devices.value = records;
+      selectDeviceByID(records[0]?.id);
+      return records.map((e) => {
+        return {
+          label: e.strinstallpos,
+          key: e.id,
+        };
+      });
+    });
+  }
+
+  onMounted(() => {
+    fetchConfig();
+  });
+</script>
+<style scoped></style>

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

@@ -46,7 +46,7 @@
     .module-content__title__expand {
       width: 100%;
       height: var(--bg-height);
-      background: url('../../../../../assets/images/home-container/configurable/model_left_title_bg_expand.png') no-repeat;
+      background: url('@/assets/images/home-container/configurable/model_left_title_bg_expand.png') no-repeat;
       background-size: 100% 100%;
       position: relative;
       text-align: right;
@@ -56,7 +56,7 @@
     .module-content__title {
       width: 50%;
       height: var(--bg-height);
-      background: url('../../../../../assets/images/home-container/configurable/model_left_title_bg.png') no-repeat;
+      background: url('@/assets/images/home-container/configurable/model_left_title_bg.png') no-repeat;
       background-size: 100% 100%;
       position: relative;
       text-align: right;
@@ -67,7 +67,7 @@
     .action-btn {
       width: 18px;
       height: 18px;
-      background: url('../../../../../assets/images/home-container/configurable/expand.svg') no-repeat center;
+      background: url('@/assets/images/home-container/configurable/expand.svg') no-repeat center;
       position: absolute;
       right: 0;
       top: 0;
@@ -79,7 +79,7 @@
     .module-slot {
       height: calc(100% - 33px);
       width: 100%;
-      background-color: #259ccf60;
+      background-color: #259ccf22;
     }
   }
 

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

@@ -13,12 +13,24 @@
     <ModuleLeft class="module-left top-70px" title="局部通风机监测">
       <SubVentilate />
     </ModuleLeft>
-    <ModuleLeft class="module-left top-410px" title="主通风机监测"> 主通风机监测 </ModuleLeft>
-    <ModuleLeft class="module-left top-750px" title="通风设施远程控制"> 通风设施远程控制 </ModuleLeft>
-    <ModuleBottom class="module-bottom left-460px" title="矿井风量实时监测"> 矿井风量实时监测 </ModuleBottom>
-    <ModuleRight class="module-right top-70px" title="通风系统监测与分析"> 通风系统监测与分析 </ModuleRight>
-    <ModuleRight class="module-right top-410px" title="采煤工作面智能管控"> 采煤工作面智能管控 </ModuleRight>
-    <ModuleRight class="module-right top-750px" title="设备告警"> 设备告警 </ModuleRight>
+    <ModuleLeft class="module-left top-410px" title="主通风机监测">
+      <Ventilate />
+    </ModuleLeft>
+    <ModuleLeft class="module-left top-750px" title="通风设施远程控制">
+      <VentilateControl />
+    </ModuleLeft>
+    <ModuleBottom class="module-bottom left-460px" title="矿井风量实时监测">
+      <AirVolumeMonitor />
+    </ModuleBottom>
+    <ModuleRight class="module-right top-70px" title="通风系统监测与分析">
+      <VentilateAnalysis />
+    </ModuleRight>
+    <ModuleRight class="module-right top-410px" title="采煤工作面智能管控">
+      <WorkSurface />
+    </ModuleRight>
+    <ModuleRight class="module-right top-750px" title="设备告警">
+      <DeviceWarning />
+    </ModuleRight>
   </div>
 </template>
 <script lang="ts" setup>
@@ -27,7 +39,13 @@
   import ModuleRight from './components/moduleRight.vue';
   import ModuleBottom from './components/moduleBottom.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 mapComponent from './components/3Dmap/index.vue';
 
   const mainTitle = ref('智能通风管控系统');