Browse Source

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

lxh 1 year ago
parent
commit
8963b3bf99

+ 6 - 0
src/assets/images/home-container/configurable/expand.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="18.031" height="18.03" viewBox="0 0 18.031 18.03">
+  <g id="组_14725" data-name="组 14725" transform="translate(8.818 21.23) rotate(-135)">
+    <path id="路径_45560" data-name="路径 45560" d="M8.5,8.5,17,0,8.5,1.4,0,0Z" transform="translate(0 4.531)" fill="#3df6ff"/>
+    <path id="路径_45561" data-name="路径 45561" d="M3.971,5.745,7.943,0,3.971,1.781,0,0Z" transform="translate(4.526 0)" fill="#3df6ff"/>
+  </g>
+</svg>

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


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


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


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


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


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


+ 51 - 0
src/views/vent/deviceManager/showninfoTable/device.api.ts

@@ -0,0 +1,51 @@
+import { defHttp } from '/@/utils/http/axios';
+import { Modal } from 'ant-design-vue';
+
+enum Api {
+  list = '/safety/configurationData/getConfigurationDataList',
+  save = '/safety/configurationData/addConfigurationData',
+  edit = '/safety/configurationData/updateConfigurationData',
+  deleteById = '/safety/configurationData/deleteConfigurationData',
+}
+
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) => defHttp.get({ url: Api.list, params });
+
+/**
+ * 删除配置项
+ */
+export const deleteById = (params, handleSuccess) => {
+  return defHttp.get({ url: Api.deleteById, params }, { joinParamsToUrl: true }).then(() => {
+    handleSuccess();
+  });
+};
+
+/**
+ * 批量删除配置项
+ * @param params
+ */
+export const batchDeleteById = (params, handleSuccess) => {
+  Modal.confirm({
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.get({ url: Api.deleteById, data: params }, { joinParamsToUrl: true }).then(() => {
+        handleSuccess();
+      });
+    },
+  });
+};
+
+/**
+ * 保存或者更新用户
+ * @param params
+ */
+export const saveOrUpdate = (params, isUpdate) => {
+  const url = isUpdate ? Api.edit : Api.save;
+  return isUpdate ? defHttp.post({ url: url, params }) : defHttp.post({ url: url, params });
+};

+ 85 - 0
src/views/vent/deviceManager/showninfoTable/device.data.ts

@@ -0,0 +1,85 @@
+import { BasicColumn } from '/@/components/Table';
+import { FormSchema } from '/@/components/Table';
+
+export const columns: BasicColumn[] = [
+  {
+    title: '所属模块',
+    dataIndex: 'pageType',
+  },
+  {
+    title: '设备类型',
+    dataIndex: 'deviceType',
+  },
+  {
+    title: '所展示点位及名称',
+    dataIndex: 'modelData',
+    format: (ctx: string) => {
+      const json = JSON.parse(ctx);
+      return Object.keys(json)
+        .map((k) => {
+          return `点位:${k};名称:${json[k]}`;
+        })
+        .join('\n');
+    },
+  },
+];
+
+export const searchFormSchema: FormSchema[] = [
+  {
+    label: '设备类型',
+    field: 'devicetype',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'devicekind',
+      placeholder: '请选择设备类型',
+    },
+    colProps: { span: 6 },
+  },
+  {
+    label: '页面类型',
+    field: 'pagetype',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'configurable_homepage',
+      placeholder: '请选择页面类型',
+    },
+    colProps: { span: 6 },
+  },
+];
+
+export const formSchema: FormSchema[] = [
+  {
+    label: '',
+    field: 'id',
+    component: 'Input',
+    show: false,
+  },
+  {
+    label: '设备类型',
+    field: 'devicetype',
+    component: 'JDictSelectTag',
+    required: true,
+    componentProps: {
+      dictCode: 'devicekind',
+      placeholder: '请选择设备类型',
+    },
+  },
+  {
+    label: '页面类型',
+    field: 'pagetype',
+    component: 'JDictSelectTag',
+    required: true,
+    componentProps: {
+      dictCode: 'configurable_homepage',
+      placeholder: '请选择页面类型',
+    },
+  },
+  {
+    label: '所展示点位及名称',
+    field: 'moduleData',
+    component: 'JAddInput',
+    componentProps: {
+      min: 0,
+    },
+  },
+];

+ 29 - 0
src/views/vent/deviceManager/showninfoTable/index.vue

@@ -0,0 +1,29 @@
+<template>
+  <div class="device-manager-box">
+    <NormalTable
+      :columns="columns"
+      :searchFormSchema="searchFormSchema"
+      :formSchema="formSchema"
+      :list="list"
+      :deleteById="deleteById"
+      :saveOrUpdate="saveOrUpdate"
+      designScope="device-tabel"
+      title="设备列表"
+      :showTab="true"
+      :deviceType="deviceType"
+    />
+  </div>
+</template>
+
+<script lang="ts" name="system-user" setup>
+  //ts语法
+  import { ref } from 'vue';
+  import NormalTable from '../comment/NormalTable.vue';
+  import { list, deleteById, saveOrUpdate } from './device.api';
+
+  import { searchFormSchema, columns, formSchema } from './device.data';
+
+  const deviceType = ref('');
+</script>
+
+<style scoped></style>

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

@@ -0,0 +1,75 @@
+<template>
+  <div class="w-100% flex costume-header__header">
+    <!-- 选择下拉框,自动填充剩余空间 -->
+    <Select
+      v-model:value="value"
+      class="flex-grow-1 costume-header__header_left"
+      :bordered="false"
+      :options="options"
+      placeholder="请选择"
+      @change="$emit('change', $event)"
+    />
+    <slot class="costume-header__header_right"></slot>
+  </div>
+</template>
+<script lang="ts" setup>
+  import { onMounted, ref } from 'vue';
+  import { Select } from 'ant-design-vue';
+  const props = withDefaults(
+    defineProps<{
+      api: Promise<Record<string, unknown>[]>;
+      labelKey?: string;
+      valueKey?: string;
+    }>(),
+    {
+      labelKey: 'label',
+      valueKey: 'value',
+    }
+  );
+  defineEmits(['change']);
+
+  const value = ref();
+  const options = ref([]);
+
+  onMounted(() => {
+    props.api().then((opts) => {
+      options.value = opts.map((o) => {
+        return {
+          label: o[props.labelKey],
+          value: o[props.valueKey],
+        };
+      });
+      value.value = options.value[0]?.value;
+    });
+  });
+</script>
+<style scoped>
+  .costume-header__header {
+    background-image: linear-gradient(90deg, #3df6ff44, transparent 20%, transparent 80%, #3df6ff44);
+  }
+  .costume-header__header_left {
+    border-left: 3px solid;
+    border-right: 3px solid;
+    border-image-source: linear-gradient(to top, #185f7188, #3df6ff, #185f7188);
+    border-image-slice: 1;
+  }
+  .costume-header__header_right {
+    border-right: 3px solid;
+    border-image-source: linear-gradient(to top, #185f7188, #3df6ff, #185f7188);
+    border-image-slice: 1;
+  }
+
+  ::v-deep .zxm-select:not(.zxm-select-customize-input) .zxm-select-selector {
+    /* background-color: transparent; */
+    color: #fff;
+  }
+  ::v-deep .zxm-select-arrow {
+    color: #fff;
+  }
+  ::v-deep .zxm-select-selection-item {
+    color: #fff !important;
+  }
+  ::v-deep .zxm-select-selection-placeholder {
+    color: #fff !important;
+  }
+</style>

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


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

@@ -0,0 +1,20 @@
+<template>
+  <CostumeHeader :api="fetchOptions"> 123 </CostumeHeader>
+</template>
+<script lang="ts" setup>
+  import { computed, ref } from 'vue';
+  import CostumeHeader from './CostumeHeader.vue';
+  // import mapComponent from './components/3Dmap/index.vue';
+
+  const searchValue = ref();
+  const lineTypeList = ref([
+    {
+      label: '你好',
+      value: 1,
+    },
+  ]);
+  function fetchOptions() {
+    return Promise.resolve([]);
+  }
+</script>
+<style scoped></style>

+ 96 - 0
src/views/vent/home/configurable/components/moduleBottom.vue

@@ -0,0 +1,96 @@
+<template>
+  <div class="module-bottom">
+    <!-- 正常展示模块时 -->
+    <div class="module-content">
+      <div class="module-content__title__expand">
+        <span class="action-btn" :class="{ 'show-btn': !moduleShown }" @click="toggleModuleShown"></span>
+        {{ title }}
+      </div>
+      <Transition>
+        <div v-if="moduleShown" class="module-slot">
+          <slot></slot>
+        </div>
+      </Transition>
+    </div>
+    <!-- 隐藏模块时 -->
+    <!-- <div v-else class="w-100%">
+      <div class="module-content__title__expand">
+        <span class="action-btn" @click="showModel"></span>
+        {{ title }}
+      </div>
+    </div> -->
+  </div>
+</template>
+<script lang="ts" setup>
+  import { ref } from 'vue';
+
+  defineProps<{ title: string }>();
+  const moduleShown = ref(true);
+
+  function toggleModuleShown() {
+    moduleShown.value = !moduleShown.value;
+  }
+</script>
+<style lang="less" scoped>
+  .module-bottom {
+    --bg-height: 33px;
+    color: #fff;
+    box-sizing: border-box;
+
+    .module-content {
+      width: 100%;
+      height: 100%;
+    }
+
+    .module-content__title__expand {
+      width: 100%;
+      height: var(--bg-height);
+      background: url('../../../../../assets/images/home-container/configurable/model_bottom_title_bg_expand.png') no-repeat;
+      background-size: 100% 100%;
+      position: relative;
+      text-align: left;
+      padding: 4px 0 0 5%;
+    }
+
+    // .module-content__title {
+    //   width: 50%;
+    //   height: var(--bg-height);
+    //   background: url('../../../../../assets/images/home-container/configurable/model_bottom_title_bg.png') no-repeat;
+    //   background-size: 100% 100%;
+    //   position: relative;
+    //   text-align: left;
+    //   padding-left: 5%;
+    // }
+
+    // 固定在父容器右上角的按钮图标
+    .action-btn {
+      width: 18px;
+      height: 18px;
+      background: url('../../../../../assets/images/home-container/configurable/expand.svg') no-repeat center;
+      position: absolute;
+      left: 0;
+      top: 0;
+    }
+    .show-btn {
+      transform: rotate(-90deg);
+    }
+
+    .module-slot {
+      height: calc(100% - 33px);
+      width: 100%;
+      background-color: #259ccf60;
+    }
+  }
+
+  // Transition动画相关
+  .v-enter-active,
+  .v-leave-active {
+    transition: all 0.3s ease;
+  }
+
+  .v-enter-from,
+  .v-leave-to {
+    opacity: 0;
+    transform: translateY(-33px);
+  }
+</style>

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

@@ -0,0 +1,99 @@
+<template>
+  <Transition class="module-left">
+    <!-- 正常展示模块时 -->
+    <div v-if="moduleShown" class="module-content">
+      <div class="module-content__title__expand">
+        <span class="action-btn close-btn" @click="closeModel"></span>
+        {{ title }}
+      </div>
+      <div class="module-slot">
+        <slot></slot>
+      </div>
+    </div>
+    <!-- 隐藏模块时 -->
+    <div v-else class="w-100%">
+      <div class="module-content__title">
+        <span class="action-btn show-btn" @click="showModel"></span>
+        {{ title }}
+      </div>
+    </div>
+  </Transition>
+</template>
+<script lang="ts" setup>
+  import { ref } from 'vue';
+
+  defineProps<{ title: string }>();
+  const moduleShown = ref(true);
+
+  function closeModel() {
+    moduleShown.value = false;
+  }
+  function showModel() {
+    moduleShown.value = true;
+  }
+</script>
+<style lang="less" scoped>
+  .module-left {
+    --bg-height: 33px;
+    color: #fff;
+    box-sizing: border-box;
+
+    .module-content {
+      width: 100%;
+      height: 100%;
+    }
+
+    .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-size: 100% 100%;
+      position: relative;
+      text-align: right;
+      padding: 4px 10% 0 0;
+    }
+
+    .module-content__title {
+      width: 50%;
+      height: var(--bg-height);
+      background: url('../../../../../assets/images/home-container/configurable/model_left_title_bg.png') no-repeat;
+      background-size: 100% 100%;
+      position: relative;
+      text-align: right;
+      padding: 4px 10% 0 0;
+    }
+
+    // 固定在父容器右上角的按钮图标
+    .action-btn {
+      width: 18px;
+      height: 18px;
+      background: url('../../../../../assets/images/home-container/configurable/expand.svg') no-repeat center;
+      position: absolute;
+      right: 0;
+      top: 0;
+    }
+    .close-btn {
+      transform: rotate(-90deg);
+    }
+
+    .module-slot {
+      height: calc(100% - 33px);
+      width: 100%;
+      background-color: #259ccf60;
+    }
+  }
+
+  // Transition动画相关
+  .v-enter-active,
+  .v-leave-active {
+    transition: all 0.3s ease;
+  }
+
+  .v-enter-from,
+  .v-leave-to {
+    // opacity: 1;
+    transform: translateX(-100%);
+    // transform: scaleY(0);
+    // transform-origin: center top;
+  }
+</style>

+ 100 - 0
src/views/vent/home/configurable/components/moduleRight.vue

@@ -0,0 +1,100 @@
+<template>
+  <Transition class="module-right">
+    <!-- 正常展示模块时 -->
+    <div v-if="moduleShown" class="module-content">
+      <div class="module-content__title__expand">
+        <span class="action-btn close-btn" @click="closeModel"></span>
+        {{ title }}
+      </div>
+      <div class="module-slot">
+        <slot></slot>
+      </div>
+    </div>
+    <!-- 隐藏模块时 -->
+    <div v-else class="w-100%">
+      <div class="module-content__title">
+        <span class="action-btn show-btn" @click="showModel"></span>
+        {{ title }}
+      </div>
+    </div>
+  </Transition>
+</template>
+<script lang="ts" setup>
+  import { ref } from 'vue';
+
+  defineProps<{ title: string }>();
+  const moduleShown = ref(true);
+
+  function closeModel() {
+    moduleShown.value = false;
+  }
+  function showModel() {
+    moduleShown.value = true;
+  }
+</script>
+<style lang="less" scoped>
+  .module-right {
+    --bg-height: 33px;
+    color: #fff;
+    box-sizing: border-box;
+
+    .module-content {
+      width: 100%;
+      height: 100%;
+    }
+
+    .module-content__title__expand {
+      width: 100%;
+      height: var(--bg-height);
+      background: url('../../../../../assets/images/home-container/configurable/model_right_title_bg_expand.png') no-repeat;
+      background-size: 100% 100%;
+      position: relative;
+      text-align: left;
+      padding: 4px 0 0 10%;
+    }
+
+    .module-content__title {
+      width: 50%;
+      height: var(--bg-height);
+      background: url('../../../../../assets/images/home-container/configurable/model_right_title_bg.png') no-repeat;
+      background-size: 100% 100%;
+      position: relative;
+      text-align: left;
+      margin-left: 50%;
+      padding: 4px 0 0 10%;
+    }
+
+    // 固定在父容器右上角的按钮图标
+    .action-btn {
+      width: 18px;
+      height: 18px;
+      background: url('../../../../../assets/images/home-container/configurable/expand.svg') no-repeat center;
+      position: absolute;
+      left: 0;
+      top: 0;
+    }
+    .show-btn {
+      transform: rotate(-90deg);
+    }
+
+    .module-slot {
+      height: calc(100% - 33px);
+      width: 100%;
+      background-color: #259ccf60;
+    }
+  }
+
+  // Transition动画相关
+  .v-enter-active,
+  .v-leave-active {
+    transition: all 0.3s ease;
+  }
+
+  .v-enter-from,
+  .v-leave-to {
+    // opacity: 1;
+    transform: translateX(100%);
+    // transform: scaleY(0);
+    // transform-origin: center top;
+  }
+</style>

+ 13 - 0
src/views/vent/home/configurable/configurable.api.ts

@@ -0,0 +1,13 @@
+import { defHttp } from '/@/utils/http/axios';
+
+enum Api {
+  list = '/ventanaly-device/safety/ventanalyDevice/homedata2',
+}
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) => defHttp.post({ url: Api.list, params });
+
+
+

+ 156 - 0
src/views/vent/home/configurable/configurable.data.ts

@@ -0,0 +1,156 @@
+import dayjs from 'dayjs';
+import { cloneDeep } from 'lodash-es';
+
+export const airVolumeMonitorKey = [
+  {
+    code: 'name',
+    value: '矿井名称',
+  },
+  {
+    code: 'jin',
+    value: '总进风量',
+  },
+  {
+    code: 'hui',
+    value: '总回风量',
+  },
+  {
+    code: 'xufeng',
+    value: '总需风量',
+  },
+];
+export const airVolumeMonitor = [
+  {
+    name: 'XXX',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: 'XXX',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: 'XXX',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: 'XXX',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: 'XXX',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: 'XXX',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: 'XXX',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: 'XXX',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: 'XXX',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: 'XXX',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: 'XXX',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+];
+
+let latestData = [];
+let latestTime = 0;
+export function getDate(workData) {
+  // debugger;
+  const workTypeList = cloneDeep(workData);
+  workData = latestData;
+  const getTime = (val) => {
+    const fiveSecondsAgo = dayjs().subtract(val, 'second');
+    // 获取时分秒
+    const hours = fiveSecondsAgo.hour();
+    const minutes = fiveSecondsAgo.minute();
+    const seconds = fiveSecondsAgo.second();
+    return `${hours}:${minutes}:${seconds}`;
+  };
+  if (latestData.length == 0) {
+    for (let j = 0; j < workTypeList.length; j++) {
+      const itemData = {
+        jin: '0',
+        hui: '0',
+        history: [],
+        deviceName: workTypeList[j]['deviceName'],
+        deviceID: workTypeList[j]['deviceID'],
+        deviceType: 'sys_surface_caimei',
+      };
+      itemData['jin'] = (1042 + (Math.random() * 2 - 1 * 50)).toFixed(2);
+      itemData['hui'] = (1082 + (Math.random() * 2 - 1 * 50)).toFixed(2);
+
+      // 第一次模拟
+      for (let i = 0; i < 5; i++) {
+        const item = {
+          jin: (1042 + (Math.random() * 2 - 1 * 50)).toFixed(2),
+          hui: (1082 + (Math.random() * 2 - 1 * 50)).toFixed(2),
+          time: getTime((i + 1) * 5),
+          deviceName: workTypeList[j]['deviceName'],
+          deviceID: workTypeList[j]['deviceID'],
+          deviceType: 'sys_surface_caimei',
+        };
+        itemData['history'].unshift(item);
+      }
+      workData.push(itemData);
+    }
+    latestTime = new Date().getTime();
+  } else {
+    if (new Date().getTime() - latestTime >= 5000) {
+      for (let j = 0; j < workTypeList.length; j++) {
+        const now = dayjs(latestTime + 5000);
+        // 获取时分秒
+        const hours = now.hour() > 9 ? now.hour() : `0${now.hour()}`;
+        const minutes = now.minute() > 9 ? now.minute() : `0${now.minute()}`;
+        const seconds = now.second() > 9 ? now.second() : `0${now.second()}`;
+        workData[j]['history'].shift();
+        workData[j]['jin'] = (1042 + (Math.random() * 2 - 1 * 50)).toFixed(2);
+        workData[j]['hui'] = (1082 + (Math.random() * 2 - 1 * 50)).toFixed(2);
+        workData[j]['history'].push({
+          jin: (1042 + (Math.random() * 2 - 1 * 50)).toFixed(2),
+          hui: (1082 + (Math.random() * 2 - 1 * 50)).toFixed(2),
+          time: `${hours}:${minutes}:${seconds}`,
+        });
+      }
+      latestTime = new Date().getTime();
+    }
+  }
+  latestData = workData;
+
+  return workData;
+}

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

@@ -0,0 +1,550 @@
+<template>
+  <div v-if="pageType == 'home'" style="position: relative; width: 100%; height: 100%">
+    <div class="home-container">
+      <div class="header">
+        <div class="head-time">
+          <span>{{ nowTimeYear }}</span>
+          <span>{{ nowTimeWeek }}</span>
+          <span>{{ nowTime }}</span>
+        </div>
+        <div class="main-title">{{ title }}</div>
+      </div>
+      <div class="home-contents">
+        <div class="left-content">
+          <!-- 主通风机 -->
+          <div class="monitor-box">
+            <mainMonitor :maindata="mainList" @goDetail="goDetail" />
+          </div>
+          <!-- 局部通风机 -->
+          <div class="monitor-box monitor-box1">
+            <fanMonitor @goDetail="goDetail" :fandata="fanLocalList" />
+          </div>
+          <!-- 通风设备远程控制 -->
+          <div class="monitor-box">
+            <windDevice :devicedata="deviceData" @goDetail="goDetail" />
+          </div>
+        </div>
+        <div class="center-content">
+          <!-- 三维模型 -->
+          <div class="three-box">
+            <div class="three-nav">
+              <template v-for="(item, index) in navList" :key="index">
+                <div class="nav-item" v-if="(item.valList && item.valList.length > 0) || item.val">
+                  <div class="item-label">{{ item.name }}</div>
+                  <div class="item-value">
+                    <div v-if="item.isShow" class="bg-box" v-for="(ite, ind) in item.valList" :key="ind">
+                      <div class="box-line"></div>
+                      <div class="value-text">{{ ite.val }}</div>
+                    </div>
+                    <div v-else class="value-text1">{{ item.val }}</div>
+                  </div>
+                </div>
+              </template>
+            </div>
+            <div class="three-modal" id="modalBox" style="position: relative">
+              <div class="btn-icon" @click="goModalDetail"></div>
+              <VentModal ref="centerModalRef" style="width: calc(100% - 30px); height: calc(100% - 30px); position: absolute" />
+            </div>
+          </div>
+          <!-- 风量监测 -->
+          <div class="wind-box">
+            <windMonitor :flList="flList" @goDetail="goDetail" />
+          </div>
+        </div>
+        <div class="right-content">
+          <!-- 关键通风路线 -->
+          <div class="monitor-box">
+            <windLine :lineList="lineList" @goDetail="goDetail" />
+          </div>
+          <!-- 工作面智能管控 -->
+          <div class="monitor-box monitor-box1">
+            <workMonitor :workList="workList" @goDetail="goDetail" />
+          </div>
+          <!-- 设备预警 -->
+          <div class="monitor-box">
+            <deviceWarn :warnData="warnData" @goDetail="goDetail" />
+          </div>
+        </div>
+      </div>
+    </div>
+    <!-- <DeviceMonitor :pageType="pageType" @goHome="goHome" /> -->
+  </div>
+  <VentModal v-if="pageType == 'model3D'" ref="fullModalRef" style="width: calc(100% - 30px); height: calc(100% - 30px); position: absolute" />
+</template>
+<script lang="ts" setup>
+  import { reactive, onMounted, ref, nextTick, computed, unref, inject, onBeforeUnmount, onUnmounted } from 'vue';
+  import fanMonitor from './components/fan-monitor.vue';
+  import mainMonitor from './components/main-monitor.vue';
+  import windDevice from './components/wind-device.vue';
+  import windMonitor from './components/wind-monitor.vue';
+  import windLine from './components/wind-line.vue';
+  import workMonitor from './components/work-monitor.vue';
+  import deviceWarn from './components/device-warn.vue';
+  import { useGlobSetting } from '/@/hooks/setting';
+  import { list } from './clique.api';
+  import DeviceMonitor from '../../monitorManager/deviceMonitor/index.vue';
+  import { useRouter } from 'vue-router';
+  import { router } from '/@/router';
+  // import { Modal } from 'ant-design-vue';
+  // import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
+  import dayjs from 'dayjs';
+  import { getActions } from '/@/qiankun/state';
+  import { unmountMicroApps, mountMicroApp } from '/@/qiankun';
+
+  import { getDate } from './clique.data';
+  import VentModal from '/@/components/vent/micro/ventModal.vue';
+  const { currentRoute } = useRouter();
+  const { title, logoUrl } = useGlobSetting();
+  const actions = getActions();
+  let timer: NodeJS.Timeout | null = null;
+  let fanLocalList = reactive<any[]>([]); //局部风机数据
+  let mainList = ref<any[]>([]); //主通风机数据
+  let centerList = reactive<any[]>([]); //中间区域数据
+  let flList = ref<any[]>([]); //风量监测数据
+  let lineList = ref<any>([]); //关键路线数据
+  let workList = ref<any>([]); //工作面数据
+  let warnData = ref<any>([]); //预警数据
+  let deviceData = ref<any>({}); //设备监测数据
+  let navList = reactive([
+    { name: '总风量(m³/min)', isShow: true, valList: [] },
+    { name: '需风量(m³/min)', isShow: true, valList: [] },
+    // { name: '有效风量(m³/min)', isShow: true, valList: [] },
+    { name: '等积孔(m²)', isShow: true, valList: [] },
+    { name: '外部漏风率', isShow: false, val: 0 },
+    { name: '有效风量率', isShow: false, val: '0%' },
+  ]);
+  let nowTimeYear = ref('');
+  let nowTimeWeek = ref('');
+  let nowTime = ref('');
+
+  const centerModalRef = ref();
+  const fullModalRef = ref();
+
+  const globSetting = useGlobSetting();
+  const pageType = ref('');
+  let router = useRouter();
+
+  function goDetail(deviceType) {
+    //lxh
+    // pageType.value = deviceType;
+    if (deviceType == 'fanMain') {
+      router.push('/monitorChannel/monitor-fanmain');
+    } else if (deviceType == 'fanLocal') {
+      router.push('/monitorChannel/monitor-fanlocal');
+    } else if (deviceType == 'windrect') {
+      router.push('/monitorChannel/monitor-windrect');
+    } else if (deviceType == 'warning') {
+      router.push('/monitorChannel/monitor-alarm-home');
+    }
+  }
+  function goHome() {
+    pageType.value = 'home';
+  }
+
+  function getList() {
+    list({}).then((res) => {
+      console.log(res, 'res-----------');
+      fanLocalList.length = 0;
+      fanLocalList.push(res.fanlocal);
+      mainList.value = res.fanmain;
+      centerList = res.midinfo[0].sysdata;
+      // 窝兔沟模拟风量
+      // centerList = {
+      //   zongfengliang: "8010", // 总风量
+      //   xufengliang: '7232', // 有效风量
+      //   zonghuifeng: '8188' // 总会风
+      // }
+      navList[0].valList =
+        centerList && centerList.zongfengliang
+          ? centerList.zongfengliang.split('').map((el) => {
+              return { val: el };
+            })
+          : [];
+      navList[1].valList =
+        centerList && centerList.xufengliang
+          ? centerList.xufengliang
+              .toString()
+              .split('')
+              .map((el) => {
+                return { val: el };
+              })
+          : [];
+      navList[2].valList =
+        centerList && centerList.dengjikong
+          ? (Number(centerList.dengjikong) > 10 ? centerList.dengjikong.toFixed(2) : `0${centerList.dengjikong.toFixed(2)}`)
+              .toString()
+              .split('')
+              .map((el) => {
+                return { val: el };
+              })
+          : [];
+      if (centerList && centerList.zongfengliang && centerList.zongjinfeng) {
+        // 外部漏风率  (zongfengliang-zongjinfeng)/zongfengliang
+        navList[3].val =
+          (((parseFloat(centerList.zongfengliang) - parseFloat(centerList.zongjinfeng)) / parseFloat(centerList.zongfengliang)) * 100).toFixed(2) +
+          '%';
+        // navList[4].val = ((centerList.xufengliang / parseFloat(centerList.zongfengliang)) * 100).toFixed(2) + '%';
+      } else {
+        navList[3].val = '0%';
+      }
+
+      if (res.midinfo[0] && res.midinfo[0].sysinfo) {
+        navList[4].val = (res.midinfo[0].sysinfo.useM3Perent ? res.midinfo[0].sysinfo.useM3Perent : '0') + '%';
+      }
+
+      flList.value = res.windrect || res.sys_wind;
+
+      if (res.sys_majorpath.length != 0) {
+        lineList.value = res.sys_majorpath;
+      } else {
+        let paramArr: any = [];
+        paramArr.push({
+          deviceName: '关键路线1',
+          deviceType: 'sys_majorpath',
+          deviceID: Math.random() * 100,
+          majorpath: {
+            drag_1: 380,
+            drag_2: 167,
+            drag_3: 333,
+            drag_total: Math.abs(
+              Number(
+                res.fanmain && res.fanmain[0]
+                  ? res.fanmain[0].readData.Fan1FanPre ||
+                      res.fanmain[0].readData.Fan2FanPre ||
+                      res.fanmain[0].readData.DataPa ||
+                      680 + (Math.random() * 2 - 1 * 5)
+                  : 680 + (Math.random() * 2 - 1 * 5)
+              )
+            ),
+            m3_total: Number(
+              res.fanmain && res.fanmain[0]
+                ? res.fanmain[0].readData.Fan1m3 ||
+                    res.fanmain[0].readData.Fan2m3 ||
+                    res.fanmain[0].readData.m3 ||
+                    8138 + (Math.random() * 2 - 1 * 20)
+                : 8138 + (Math.random() * 2 - 1 * 20)
+            ),
+          },
+        });
+        lineList.value = paramArr;
+      }
+
+      if (res.sys_surface_caimei.length != 0) {
+        workList.value = res.sys_surface_caimei;
+      } else {
+        let paramArr: any = [];
+        paramArr.push({
+          deviceName: '工作面',
+          deviceType: 'sys_surface_caimei',
+          deviceID: '11111',
+          history: [],
+          jin: 100,
+          hui: 200,
+          xufengliang: 300,
+        });
+        workList.value = getDate(paramArr);
+      }
+      warnData.value = res.warn || [];
+      deviceData.value = res.device || {};
+    });
+  }
+
+  //获取当前时间年月日时分秒
+  function getNowTime() {
+    setInterval(() => {
+      nowTimeYear.value = dayjs().format('YYYY/MM/DD');
+      let week = dayjs(new Date().getTime()).day();
+      switch (week) {
+        case 0:
+          nowTimeWeek.value = '星期日';
+          break;
+        case 1:
+          nowTimeWeek.value = '星期一';
+          break;
+        case 2:
+          nowTimeWeek.value = '星期二';
+          break;
+        case 3:
+          nowTimeWeek.value = '星期三';
+          break;
+        case 4:
+          nowTimeWeek.value = '星期四';
+          break;
+        case 5:
+          nowTimeWeek.value = '星期五';
+          break;
+        case 6:
+          nowTimeWeek.value = '星期六';
+          break;
+      }
+      let date = new Date();
+      let hours = date.getHours();
+      let minutes = date.getMinutes();
+      let seconds = date.getSeconds();
+      if (minutes >= 0 && minutes <= 9) {
+        minutes = `0${minutes}`;
+      }
+      if (seconds >= 0 && seconds <= 9) {
+        seconds = `0${seconds}`;
+      }
+      nowTime.value = `${hours}:${minutes}:${seconds}`;
+    }, 1000);
+  }
+
+  function goModalDetail() {
+    router.push('/micro-vent-3dModal/modelchannel/model3D/home?deviceType=model3D');
+    // history.pushState({}, '', '/micro-vent-3dModal/modelchannel/model3D/home?deviceType=model3D');
+    // location.reload()
+  }
+
+  onMounted(() => {
+    const currentRouteObj = unref(currentRoute);
+    if (currentRouteObj && currentRouteObj['query'] && currentRouteObj['query']['deviceType']) {
+      pageType.value = 'model3D';
+    } else {
+      pageType.value = 'home';
+    }
+    getNowTime();
+    getList();
+    timer = Number(
+      setInterval(() => {
+        getList();
+      }, 10000)
+    );
+  });
+  onBeforeUnmount(() => {
+    clearInterval(timer);
+    timer = null;
+  });
+  onUnmounted(() => {
+    pageType.value = '';
+  });
+</script>
+
+<style lang="less" scoped>
+  @font-face {
+    font-family: 'douyuFont';
+    src: url('../../../../assets/font/douyuFont.otf');
+  }
+
+  @font-face {
+    font-family: 'yjsz';
+    src: url('../../../../assets/font/yjsz.TTF');
+  }
+
+  .home-container {
+    width: 100%;
+    height: 100%;
+    position: relative;
+
+    .header {
+      width: 100%;
+      height: 76px;
+      position: relative;
+      background: url('../../../../assets//images//home-container/header-nav.png') no-repeat;
+
+      .head-time {
+        position: absolute;
+        top: 14px;
+        left: 15px;
+        color: #b5c9e9;
+        font-size: 14px;
+
+        span {
+          margin-right: 20px;
+          letter-spacing: 2px;
+        }
+      }
+
+      .main-title {
+        position: absolute;
+        left: 50%;
+        top: 50%;
+        transform: translate(-50%, -50%);
+        color: #fff;
+        font-size: 24px;
+        font-family: 'douyuFont';
+      }
+    }
+
+    .home-contents {
+      display: flex;
+      justify-content: space-between;
+      height: calc(100% - 76px);
+      padding: 10px;
+      box-sizing: border-box;
+
+      .left-content {
+        display: flex;
+        flex-direction: column;
+        flex: 1;
+        justify-content: space-between;
+        height: 100%;
+
+        .monitor-box {
+          display: flex;
+          flex: 1;
+          width: 100%;
+          background: url('../../../../assets/images/home-container/dialog.png') no-repeat;
+          background-size: 100% 100%;
+        }
+
+        .monitor-box1 {
+          margin: 10px 0px;
+        }
+      }
+
+      .center-content {
+        display: flex;
+        flex-direction: column;
+        justify-content: space-between;
+        flex: 2;
+        height: 100%;
+        margin: 0px 10px;
+
+        .three-box {
+          position: relative;
+          display: flex;
+          background-color: #fff;
+          flex: 2;
+          width: 100%;
+          margin-bottom: 15px;
+          background: url('../../../../assets/images/home-container/three-dialog.png') no-repeat;
+          background-size: 100% 100%;
+
+          .three-nav {
+            position: absolute;
+            z-index: 9999;
+            left: 50%;
+            top: 38px;
+            transform: translate(-50%, 0);
+            width: 812px;
+            height: 89px;
+            padding: 0px 20px;
+            box-sizing: border-box;
+            display: flex;
+            justify-content: space-around;
+            align-items: center;
+            background: url('../../../../assets/images/home-container/three-nav.png') no-repeat;
+
+            .nav-item {
+              display: flex;
+              flex: 1;
+              flex-direction: column;
+              justify-content: space-around;
+              align-items: center;
+              height: 80%;
+
+              .item-label {
+                color: #98f5ff;
+              }
+
+              .item-value {
+                position: relative;
+                width: 125px;
+                height: 37px;
+                padding: 0px 5px;
+                box-sizing: border-box;
+                display: flex;
+                justify-content: space-between;
+                align-items: center;
+                background: url('../../../../assets/images/home-container/item-value.png') no-repeat;
+
+                .bg-box {
+                  position: relative;
+                  width: 20px;
+                  height: 26px;
+                  border-bottom: 2px solid #063493;
+                  background: linear-gradient(to right, rgba(1, 194, 249), rgba(0, 125, 252));
+
+                  .box-line {
+                    position: absolute;
+                    left: 0;
+                    top: 50%;
+                    transform: translate(0, -50%);
+                    height: 1px;
+                    width: 100%;
+                    background-color: rgba(6, 52, 147, 0.6);
+                  }
+
+                  .value-text {
+                    position: absolute;
+                    left: 50%;
+                    top: 50%;
+                    transform: translate(-50%, -50%);
+                    color: #fff;
+                    font-size: 22px;
+                    font-family: 'yjsz';
+                    font-weight: 500;
+                  }
+                }
+
+                .value-text1 {
+                  width: 100%;
+                  text-align: center;
+                  color: #fff;
+                  font-size: 22px;
+                  font-family: 'yjsz';
+                  font-weight: 500;
+                }
+              }
+            }
+          }
+
+          .three-modal {
+            width: 100%;
+            height: 100%;
+            padding: 20px 17px 20px 15px;
+            box-sizing: border-box;
+            position: relative;
+
+            .btn-icon {
+              width: 40px;
+              height: 40px;
+              background: url('/@/assets/images/vent/home/tosmall.png') no-repeat center;
+              background-size: 100% 100%;
+              position: absolute;
+              z-index: 99999;
+              bottom: 30px;
+              right: 30px;
+            }
+          }
+        }
+
+        .wind-box {
+          display: flex;
+          flex: 1;
+          width: 100%;
+          background: url('../../../../assets/images/home-container/dialog1.png') no-repeat;
+          background-size: 100% 100%;
+        }
+      }
+
+      .right-content {
+        display: flex;
+        flex-direction: column;
+        justify-content: space-between;
+        flex: 1;
+        height: 100%;
+
+        .monitor-box {
+          display: flex;
+          flex: 1;
+          width: 100%;
+          background: url('../../../../assets/images/home-container/dialog.png') no-repeat;
+          background-size: 100% 100%;
+        }
+
+        .monitor-box1 {
+          margin: 10px 0px;
+        }
+      }
+    }
+  }
+
+  // #__qiankun_microapp_wrapper_for_micro_vent_3_d_modal__{
+  //   width: 100% !important;
+  //   height: 100% !important;
+  // }
+</style>
+./configurable.api

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

@@ -0,0 +1,92 @@
+<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> <span class="color-#fff">全矿井通风检测</span> </template>
+    </a-dropdown>
+    <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>
+  </div>
+</template>
+<script lang="ts" setup>
+  import { computed, ref } from 'vue';
+  import ModuleLeft from './components/moduleLeft.vue';
+  import ModuleRight from './components/moduleRight.vue';
+  import ModuleBottom from './components/moduleBottom.vue';
+  import SubVentilate from './components/SubVentilate.vue';
+  import { CaretDownOutlined } from '@ant-design/icons-vue';
+  // import mapComponent from './components/3Dmap/index.vue';
+
+  const mainTitle = ref('智能通风管控系统');
+</script>
+<style lang="less" scoped>
+  @font-face {
+    font-family: 'douyuFont';
+    src: url('../../../../assets/font/douyuFont.otf');
+  }
+
+  .company-home {
+    width: 100%;
+    height: 100%;
+    color: #fff;
+    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: 320px;
+      left: 0;
+    }
+    .module-right {
+      position: absolute;
+      width: 450px;
+      height: 320px;
+      right: 0;
+    }
+    .module-bottom {
+      position: absolute;
+      width: 1000px;
+      height: 320px;
+      bottom: 10px;
+    }
+    .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>