瀏覽代碼

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

hongrunxia 8 月之前
父節點
當前提交
7ba64a102c

+ 5 - 2
src/hooks/vent/useAutoLogin.ts

@@ -33,7 +33,10 @@ export function useAutoLogin() {
     return false;
   }
 
-  /** 用在路由守卫里,执行自动登录的逻辑,如果存在符合自动登录标准的query则执行自动登录,返回是否自动登录 */
+  /** 用在路由守卫里,执行自动登录的逻辑,如果存在符合自动登录标准的query则执行自动登录,返回是否自动登录
+   *
+   * 该方法需要修改query
+   * */
   async function doAutoLogin(route: RouteLocationNormalized): Promise<void> {
     if (!validateRoute(route)) return;
 
@@ -52,7 +55,7 @@ export function useAutoLogin() {
         goHome: false,
       });
       delete route.query[AUTO_LOGIN_URL_QUERY.key];
-      delete route.query['username'];
+      delete route.query['realname'];
       delete route.query['workNo'];
       return;
     } catch (e) {

+ 1 - 1
src/router/guard/permissionGuard.ts

@@ -65,7 +65,7 @@ export function createPermissionGuard(router: Router) {
     if (validateRoute(to)) {
       await doAutoLogin(to);
       // 自动登录后会动态添加路由,此处应当重定向到fullPath,否则会加载404页面内容
-      return next({ path: to.fullPath, replace: true });
+      return next({ path: to.fullPath, replace: true, query: to.query });
     }
 
     const token = userStore.getToken;

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

@@ -49,9 +49,9 @@ export interface ModuleData {
     link: string;
   };
   /** 模块的布局,使用规定的枚举组合为一个数组,代表着从上到下所应展示的元素 */
-  layout: ('board' | 'list' | 'chart')[];
+  layout: ('board' | 'list' | 'chart' | 'table' | 'blast_delta')[];
   /** 展示牌元素 */
-  board?: {
+  board: {
     /** 展示牌说明内容 */
     label: string;
     /** 展示牌预设的背景类型 */
@@ -62,15 +62,15 @@ export interface ModuleData {
     prop: string;
   }[];
   /** 列表元素 */
-  list?: {
+  list: {
     color: string;
     /** 列表项说明内容 */
     label: string;
     formatter?: string;
     prop: string;
   }[];
-  /** 图表元素 */
-  chart?: {
+  /** 图表元素,仅第一个配置项将生效 */
+  chart: {
     /** 图表通用类型,一个类型对应一种图表预设 */
     type: 'pie' | 'bar' | 'line';
     /** 读取数据时的基础路径,例如如果图表依赖一个数组,那么该项应设置能读取到该数组的路径。例如:readData.history */
@@ -80,18 +80,24 @@ export interface ModuleData {
     /** 排序规则,desc降序,asc升序 */
     order?: 'desc' | 'asc';
     /** 图表x轴配置(若有),例如:{ prop: 'strInstallPos' } */
-    xAxis?: {
+    xAxis: {
       formatter?: string;
       prop: string;
     }[];
     /** 图表y轴配置(若有),例如:['风量', '风速'] */
-    yAxis?: {
+    yAxis: {
       label: string;
       align: 'left' | 'right';
     }[];
     /** 图表各系列配置,一个系列应对应一个数据维度,例如:[{ label: '风量', prop: 'f1Val' }] */
     series: { label: string; prop: string }[];
   }[];
+  /** 表格元素,仅第一个配置项将生效 */
+  table: {
+    columns: { label: string; prop: string }[];
+    /** 读取数据时的基础路径,例如如果表格依赖一个数组,那么该项应设置能读取到该数组的路径。例如:readData.history */
+    readFrom: string;
+  }[];
 }
 export interface ShowStyle {
   /** 模块的宽高 */

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

@@ -1,3 +1,4 @@
+<!-- eslint-disable vue/multi-word-component-names -->
 <template>
   <!-- Header部分 -->
   <div v-if="headerConfig.show" class="w-100% flex content__header">
@@ -34,8 +35,9 @@
       </div>
     </template>
   </div>
-  <!-- 主内容部分 -->
+  <!-- 主内容部分 -->
   <div class="content">
+    <!-- 背景 -->
     <img v-if="background.show && background.type === 'image'" class="content__background" :src="background.link" />
     <video
       v-if="background.show && background.type === 'video'"
@@ -49,20 +51,25 @@
       Not Supportted Link Or Browser
     </video>
     <template v-for="val in layout" :key="val">
+      <!-- 告示板部分 -->
       <div v-if="val === 'board'" class="flex flex-justify-around pt-10px pb-10px">
         <MiniBoard v-for="item in boardConfig" :key="item.prop" :type="item.type" :label="item.label" :layout="item.layout" :value="item.value" />
       </div>
-      <template v-if="val === 'chart'"></template>
-      <div v-if="val === 'list'" class="timeline">
-        <div v-for="item in listConfig" :key="item.prop" class="flex items-center timeline-item">
-          <div class="timeline-item__icon" :class="`timeline-item__icon_${item.color}`"></div><div class="timeline-item__dot"></div>
-          <div class="timeline-item__label">{{ item.label }}</div>
-          <div :class="`timeline-item__value_${item.color}`">
-            {{ item.value }}
-          </div>
-        </div>
-        <div class="timeline-component"></div>
-      </div>
+      <!-- 图表部分,这部分通常需要填充,有告示板、Header等内容需要填充父级 -->
+      <template v-if="val === 'chart'">
+        <CustomChart :chart-config="chartConfig" :chart-data="chartData" style="flex-grow: 1" />
+      </template>
+      <!-- 时间线列表部分,这部分通常是占一整个模块的 -->
+      <template v-if="val === 'list'">
+        <TimelineList :list-config="listConfig" />
+      </template>
+      <!-- 表格部分,这部分通常是占一整个模块的 -->
+      <template v-if="val === 'table'">
+        <CommonTable :columns="tableConfig.columns" :data="tableData" class="mt-10px mb-10px" />
+      </template>
+      <template v-if="val === 'blast_delta'">
+        <BlastDelta class="mt-10px mb-10px" />
+      </template>
     </template>
   </div>
 </template>
@@ -73,7 +80,12 @@
   import { MenuItem, Menu, Dropdown } from 'ant-design-vue';
   import { SwapOutlined, CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons-vue';
   import MiniBoard from './miniBoard.vue';
+  import TimelineList from './timelineList.vue';
   import { getFormattedText } from '../../../deviceManager/configurationTable/adapters';
+  import CustomChart from './customChart.vue';
+  import { get } from 'lodash-es';
+  import CommonTable from '../../billboard/components/CommonTable.vue';
+  import BlastDelta from '../../../monitorManager/deviceMonitor/components/device/modal/blastDelta.vue';
 
   const props = defineProps<{
     deviceType: Config['deviceType'];
@@ -81,7 +93,7 @@
     showStyle: Config['showStyle'];
   }>();
 
-  const { header: headerConfig, background, board, layout, list } = props.moduleData;
+  const { header: headerConfig, background, board, layout, list, chart, table } = props.moduleData;
 
   // 额外的 header 相关的变量
   const headerVisible = ref(false);
@@ -111,6 +123,29 @@
     });
   });
 
+  const chartConfig = computed(() => {
+    return chart[0];
+  });
+  const chartData = computed(() => {
+    const data = selectedDevice.value;
+    return get(data, chart[0]?.readFrom, []);
+  });
+
+  const tableConfig = computed(() => {
+    return {
+      columns: (table[0]?.columns || []).map((e) => {
+        return {
+          name: e.label,
+          prop: e.prop,
+        };
+      }),
+    };
+  });
+  const tableData = computed(() => {
+    const data = selectedDevice.value;
+    return get(data, table[0]?.readFrom, []);
+  });
+
   const { selectedDeviceID, selectedDevice, selectedDeviceSlot, selectedDeviceLabel, options, fetchDevices } = useInitDevices(
     props.deviceType,
     headerConfig
@@ -145,6 +180,8 @@
     height: calc(100% - 30px);
     position: relative;
     z-index: -2;
+    display: flex;
+    flex-direction: column;
   }
   .content__background {
     width: 100%;
@@ -168,83 +205,4 @@
   ::v-deep .zxm-select-selection-placeholder {
     color: #fff !important;
   }
-
-  /* Timeline 相关的样式 */
-
-  .timeline-item {
-    height: 20%;
-  }
-  .timeline-item__icon_red {
-    background-image: url('@/assets/images/home-container/configurable/warn_icon_5.png');
-  }
-  .timeline-item__icon_orange {
-    background-image: url('@/assets/images/home-container/configurable/warn_icon_4.png');
-  }
-  .timeline-item__icon_yellow {
-    background-image: url('@/assets/images/home-container/configurable/warn_icon_3.png');
-  }
-  .timeline-item__icon_green {
-    background-image: url('@/assets/images/home-container/configurable/warn_icon_2.png');
-  }
-  .timeline-item__icon_blue {
-    background-image: url('@/assets/images/home-container/configurable/warn_icon_1.png');
-  }
-  .timeline-item__icon {
-    width: 33px;
-    height: 35px;
-    margin-left: 50px;
-    background-repeat: no-repeat;
-    background-position: center center;
-  }
-  .timeline-item__dot {
-    width: 10px;
-    height: 10px;
-    margin-left: 70px;
-    background-color: @vent-gas-primary-bg;
-    border-radius: 5px;
-    position: relative;
-  }
-  .timeline-item__dot::before {
-    content: '';
-    position: absolute;
-    top: -3px;
-    left: -3px;
-    width: 16px;
-    height: 16px;
-    border-radius: 8px;
-    border: 1px solid @vent-gas-tab-border;
-  }
-  .timeline-item__label {
-    width: 100px;
-    margin-left: 70px;
-  }
-  .timeline-item__value_red {
-    color: red;
-  }
-  .timeline-item__value_orange {
-    color: orange;
-  }
-  .timeline-item__value_yellow {
-    color: yellow;
-  }
-  .timeline-item__value_green {
-    color: yellowgreen;
-  }
-  .timeline-item__value_blue {
-    color: lightblue;
-  }
-
-  .timeline {
-    height: 220px;
-    padding: 5px;
-    position: relative;
-  }
-  .timeline-component {
-    position: absolute;
-    width: 2px;
-    height: 180px;
-    top: 20px;
-    left: 162px;
-    background-image: @vent-configurable-home-timeline;
-  }
 </style>

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

@@ -0,0 +1,221 @@
+<template>
+  <div ref="chartRef" :style="{ height, width }"></div>
+</template>
+<script lang="ts" setup>
+  import { ref, Ref, watch } from 'vue';
+  import { useECharts } from '/@/hooks/web/useECharts';
+  import { get } from 'lodash-es';
+  import { Config } from '/@/views/vent/deviceManager/configurationTable/types';
+  import { EChartsOption, graphic } from 'echarts';
+  import { getFormattedText } from '../../../deviceManager/configurationTable/adapters';
+
+  const props = withDefaults(
+    defineProps<{
+      chartData: Record<string, any> | Record<string, any>[];
+      chartConfig: Config['moduleData']['chart']['0'];
+      height: string;
+      width: string;
+    }>(),
+    {
+      chartData: () => [],
+      height: '100%',
+      width: '100%',
+    }
+  );
+
+  const chartRef = ref<HTMLDivElement | null>(null);
+  const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
+
+  // 核心方法,生成适用与 echart 的选项
+  const genChartOption = () => {
+    // 依据每一个图表配置生成图表选项
+    const { yAxis = [], xAxis = [], order, type, sortBy, series } = props.chartConfig;
+    const isArray = Array.isArray(props.chartData);
+
+    // 饼状图通常依赖单个对象的不同字段绘制
+    if (type === 'pie' && !isArray) {
+      return {
+        legend: { show: false },
+        color: ['#d9a1ff', '#00d1ff', '#82fe78'],
+        series: [
+          {
+            type: 'pie',
+            radius: ['50%', '75%'],
+            center: ['50%', '55%'],
+            data: series.map((serie) => {
+              return {
+                name: serie.label,
+                value: get(props.chartData, serie.prop, 0),
+                labelLine: { show: false },
+                label: { show: false },
+                itemStyle: {
+                  shadowBlur: 20,
+                  shadowColor: '#259bcf',
+                },
+              };
+            }),
+          },
+        ],
+      };
+    }
+    if (!isArray) return {};
+
+    let sorttedData = [...(props.chartData as any[])];
+
+    // 如果这个配置指明了需要排序则执行排序
+    if (sortBy && order) {
+      sorttedData.sort((pre, cur) => {
+        if (order === 'asc') {
+          return get(pre, sortBy, 0) - get(cur, sortBy, 0);
+        } else {
+          return get(cur, sortBy, 0) - get(pre, sortBy, 0);
+        }
+      });
+    }
+
+    // 柱状图则要求使用数组形式的数据作依赖
+    if (type === 'bar') {
+      return {
+        grid: {
+          top: 50,
+          height: 150,
+        },
+        textStyle: {
+          color: '#fff',
+        },
+        legend: { show: false },
+        xAxis: xAxis.map((e) => {
+          return {
+            type: 'category',
+            data: sorttedData.map((d) => {
+              return getFormattedText(d, e.prop, e.formatter);
+            }),
+          };
+        }),
+        yAxis: yAxis.map((e) => {
+          return {
+            name: e.label,
+            position: e.align,
+            splitLine: {
+              lineStyle: {
+                color: '#ffffff',
+                opacity: 0.3,
+              },
+            },
+          };
+        }),
+        series: series.reduce((curr: EChartsOption[], serie, index) => {
+          const colors = ['#66ffff', '#ffff66'];
+          // 系列选项,如果指定了x轴配置则以x轴配置优先
+          const data = sorttedData.map((d) => {
+            return {
+              name: serie.label,
+              value: get(d, serie.prop, 0),
+            };
+          });
+          curr.push({
+            name: 'pictorial element',
+            type: 'pictorialBar',
+            symbol: 'circle',
+            symbolPosition: 'end',
+            symbolSize: [16, 16],
+            symbolOffset: [0, -8],
+            yAxisIndex: index,
+            itemStyle: {
+              color: colors[index % colors.length],
+            },
+            data,
+          });
+          curr.push({
+            name: 'reference bar',
+            type: 'bar',
+            silent: true,
+            yAxisIndex: index,
+            itemStyle: {
+              color: new graphic.LinearGradient(0, 0, 0, 1, [
+                { offset: 0, color: colors[index % colors.length] },
+                { offset: 0.2, color: colors[index % colors.length] },
+                { offset: 1, color: `${colors[index % colors.length]}22` },
+              ]),
+            },
+            tooltip: { show: false },
+            barWidth: 8,
+            data,
+          });
+
+          return curr;
+        }, []),
+      };
+    }
+    // 折线图和上面的柱状图类似
+    if (type === 'line') {
+      return {
+        legend: {
+          top: 10,
+          right: 10,
+          textStyle: {
+            color: '#fff',
+          },
+        },
+        // backgroundColor: '#081f33',
+        textStyle: {
+          color: '#fff',
+        },
+        grid: {
+          left: 80,
+          top: 50,
+          right: 80,
+          bottom: 50,
+        },
+        xAxis: xAxis.map((e) => {
+          return {
+            type: 'category',
+            data: sorttedData.map((d) => {
+              return getFormattedText(d, e.prop, e.formatter);
+            }),
+          };
+        }),
+        yAxis: yAxis.map((e) => {
+          return {
+            name: e.label,
+            position: e.align,
+            splitLine: {
+              lineStyle: {
+                color: '#fff',
+                opacity: 0.3,
+              },
+            },
+          };
+        }),
+        series: series.map((serie) => {
+          const data = sorttedData.map((d) => {
+            return {
+              name: serie.label,
+              value: get(d, serie.prop, 0),
+            };
+          });
+
+          return {
+            type: 'line',
+            data,
+          };
+        }),
+      };
+
+      return {};
+    }
+  };
+
+  watch(
+    () => props.chartData,
+    () => {
+      initCharts();
+    }
+  );
+
+  function initCharts() {
+    const o = genChartOption();
+    console.log('debug', o);
+    setOptions(o as EChartsOption, false);
+  }
+</script>

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

@@ -32,6 +32,7 @@
     --bg-height: 33px;
     color: #fff;
     box-sizing: border-box;
+    position: absolute;
 
     .module-content {
       width: 100%;

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

@@ -32,6 +32,7 @@
     --bg-height: 33px;
     color: #fff;
     box-sizing: border-box;
+    position: absolute;
 
     .module-content {
       width: 100%;

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

@@ -32,6 +32,7 @@
     --bg-height: 33px;
     color: #fff;
     box-sizing: border-box;
+    position: absolute;
 
     .module-content {
       width: 100%;

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

@@ -35,7 +35,7 @@
     if (position.includes('right:0')) {
       return ModuleRight;
     }
-    if (position.includes('bottom:0')) {
+    if (position.includes('top:640px;left:460px')) {
       return ModuleBottom;
     }
     return ModuleLeft; //

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

@@ -28,7 +28,7 @@
 
   // 根据配置里的定位判断应该使用哪个module组件
   function getModuleComponent(position) {
-    if (position.includes('bottom:0')) {
+    if (position.includes('top:640px;left:460px')) {
       return ModuleBottom;
     }
     return ModuleLeft;

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


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

@@ -32,6 +32,7 @@
     --bg-height: 33px;
     color: #fff;
     box-sizing: border-box;
+    position: absolute;
 
     .module-content {
       width: 100%;
@@ -73,10 +74,10 @@
 
     .module-slot {
       height: calc(100% - 33px);
-      width: calc(100% - 40px);
+      width: calc(100% - 15px);
       backdrop-filter: blur(5px);
       background-color: #6ad6ff1c;
-      margin-left: 20px;
+      margin-left: 5px;
     }
   }
 

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

@@ -32,6 +32,7 @@
     --bg-height: 33px;
     color: #fff;
     box-sizing: border-box;
+    position: absolute;
 
     .module-content {
       width: 100%;

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

@@ -0,0 +1,111 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <div class="timeline">
+    <div v-for="item in listConfig" :key="item.prop" class="flex items-center timeline-item">
+      <div class="timeline-item__icon" :class="`timeline-item__icon_${item.color}`"></div><div class="timeline-item__dot"></div>
+      <div class="timeline-item__label">{{ item.label }}</div>
+      <div :class="`timeline-item__value_${item.color}`">
+        {{ item.value }}
+      </div>
+    </div>
+    <div class="timeline-component"></div>
+  </div>
+</template>
+<script lang="ts" setup>
+  withDefaults(
+    defineProps<{
+      listConfig: {
+        value: string;
+        color: string;
+        label: string;
+        prop: string;
+      }[];
+    }>(),
+    {
+      listConfig: () => [],
+    }
+  );
+
+  //   defineEmits(['click']);
+</script>
+<style lang="less" scoped>
+  @import '@/design/vent/color.less';
+  /* Timeline 相关的样式 */
+
+  .timeline-item {
+    height: 20%;
+  }
+  .timeline-item__icon_red {
+    background-image: url('@/assets/images/home-container/configurable/warn_icon_5.png');
+  }
+  .timeline-item__icon_orange {
+    background-image: url('@/assets/images/home-container/configurable/warn_icon_4.png');
+  }
+  .timeline-item__icon_yellow {
+    background-image: url('@/assets/images/home-container/configurable/warn_icon_3.png');
+  }
+  .timeline-item__icon_green {
+    background-image: url('@/assets/images/home-container/configurable/warn_icon_2.png');
+  }
+  .timeline-item__icon_blue {
+    background-image: url('@/assets/images/home-container/configurable/warn_icon_1.png');
+  }
+  .timeline-item__icon {
+    width: 33px;
+    height: 35px;
+    margin-left: 50px;
+    background-repeat: no-repeat;
+    background-position: center center;
+  }
+  .timeline-item__dot {
+    width: 10px;
+    height: 10px;
+    margin-left: 70px;
+    background-color: @vent-gas-primary-bg;
+    border-radius: 5px;
+    position: relative;
+  }
+  .timeline-item__dot::before {
+    content: '';
+    position: absolute;
+    top: -3px;
+    left: -3px;
+    width: 16px;
+    height: 16px;
+    border-radius: 8px;
+    border: 1px solid @vent-gas-tab-border;
+  }
+  .timeline-item__label {
+    width: 100px;
+    margin-left: 70px;
+  }
+  .timeline-item__value_red {
+    color: red;
+  }
+  .timeline-item__value_orange {
+    color: orange;
+  }
+  .timeline-item__value_yellow {
+    color: yellow;
+  }
+  .timeline-item__value_green {
+    color: yellowgreen;
+  }
+  .timeline-item__value_blue {
+    color: lightblue;
+  }
+
+  .timeline {
+    height: 220px;
+    padding: 5px;
+    position: relative;
+  }
+  .timeline-component {
+    position: absolute;
+    width: 2px;
+    height: 180px;
+    top: 20px;
+    left: 162px;
+    background-image: @vent-configurable-home-timeline;
+  }
+</style>

+ 207 - 74
src/views/vent/home/configurable/index.vue

@@ -22,16 +22,16 @@
     <VentilateAnalysis />
     <WorkSurface />
     <DeviceWarning /> -->
-    <div v-if="isOriginal">
+    <template v-if="isOriginal">
       <ModuleOriginal v-for="cfg in configs" :key="cfg.deviceType" :show-style="cfg.showStyle" :module-name="cfg.moduleName" :visible="visible">
         <Content v-bind="cfg" />
       </ModuleOriginal>
-    </div>
-    <div v-else>
+    </template>
+    <template v-else>
       <ModuleEnhanced v-for="cfg in configs" :key="cfg.deviceType" :show-style="cfg.showStyle" :module-name="cfg.moduleName" :visible="visible">
         <Content v-bind="cfg" />
       </ModuleEnhanced>
-    </div>
+    </template>
   </div>
 </template>
 <script lang="ts" setup>
@@ -44,7 +44,7 @@
   // 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 MonitorCenter from './components/monitorCenter.vue';
   // import { useInitConfigs } from './hooks/useInit';
   import { Config } from '../../deviceManager/configurationTable/types';
   import ModuleEnhanced from './components/moduleEnhanced.vue';
@@ -67,11 +67,9 @@
           showSelector: true,
           showSlot: true,
           selector: {
-            icon: 'SwapOutlined',
             prop: 'strinstallpos',
           },
           slot: {
-            icon: 'SwapOutlined',
             prop: 'strinstallpos',
           },
         },
@@ -80,7 +78,7 @@
           type: 'video',
           link: '/src/assets/vedio/fanLocal.mp4',
         },
-        layout: ['board', 'chart'],
+        layout: ['board'],
         board: [
           {
             label: '风速1',
@@ -90,36 +88,72 @@
           },
           {
             label: '风速2',
-            type: 'D',
+            type: 'B',
             layout: 'label-top',
             prop: 'readData.windSpeed2',
           },
         ],
+        list: [],
+        chart: [],
+        table: [],
+      },
+      showStyle: {
+        size: 'width:450px;height:280px;',
+        version: 'enhanced',
+        position: 'top:60px;left:0;',
+      },
+    },
+    {
+      deviceType: 'sys_majorpath',
+      moduleName: '测试折线图',
+      pageType: '',
+      moduleData: {
+        header: {
+          show: true,
+          showSelector: true,
+          showSlot: true,
+          selector: {
+            prop: 'strinstallpos',
+          },
+          slot: {
+            prop: 'strinstallpos',
+          },
+        },
+        background: {
+          show: false,
+          type: 'video',
+          link: '',
+        },
+        layout: ['chart'],
+        board: [],
+        list: [],
         chart: [
           {
             type: 'line',
-            readFrom: 'readData.history',
-            xAxis: [{ prop: 'strinstallpos' }],
+            readFrom: 'majorpath.paths',
+            xAxis: [{ prop: 'name' }],
             yAxis: [
-              { label: '风量', align: 'left' },
-              { label: '风速', align: 'right' },
+              { label: 'Drag', align: 'left' },
+              { label: 'M3', align: 'right' },
             ],
             series: [
-              { label: '风量', prop: 'f1Val' },
-              { label: '风速', prop: 'f2Val' },
+              { label: 'Drag', prop: 'drag' },
+              { label: 'M3', prop: 'm3' },
+              // { label: '回2', prop: 'hui2' },
             ],
           },
         ],
+        table: [],
       },
       showStyle: {
         size: 'width:450px;height:280px;',
         version: 'enhanced',
-        position: 'top:60px;left:0;',
+        position: 'top:350px;left:0;',
       },
     },
     {
-      deviceType: 'fanlocal',
-      moduleName: '测试局扇',
+      deviceType: 'warn',
+      moduleName: '测试报警',
       pageType: '',
       moduleData: {
         header: {
@@ -127,12 +161,11 @@
           showSelector: false,
           showSlot: true,
           selector: {
-            icon: 'SwapOutlined',
             prop: 'strinstallpos',
           },
           slot: {
-            icon: 'SwapOutlined',
-            prop: 'strinstallpos',
+            prop: 'netstatus.val',
+            formatter: '网络异常:${} 台',
           },
         },
         background: {
@@ -140,58 +173,106 @@
           type: 'video',
           link: '',
         },
-        layout: ['board', 'chart'],
-        board: [
+        layout: ['list'],
+        board: [],
+        chart: [],
+        table: [],
+        list: [
           {
-            label: '风量',
-            type: 'A',
-            layout: 'val-top',
-            prop: 'f1Val',
+            label: '正常',
+            prop: 'blue.val',
+            color: 'blue',
           },
           {
-            label: '风速',
-            type: 'A',
-            layout: 'val-top',
-            prop: 'f2Val',
+            label: '告警',
+            prop: 'orange.val',
+            color: 'orange',
+          },
+          {
+            label: '报警',
+            prop: 'yellow.val',
+            color: 'yellow',
+          },
+          {
+            label: '危险',
+            prop: 'red.val',
+            color: 'red',
+          },
+          {
+            label: '错误',
+            prop: 'alarm.val',
+            color: 'green',
           },
         ],
+      },
+      showStyle: {
+        size: 'width:450px;height:280px;',
+        version: 'enhanced',
+        position: 'top:640px;left:0;',
+      },
+    },
+    {
+      deviceType: 'midinfo',
+      moduleName: '测试中间模块',
+      pageType: '',
+      moduleData: {
+        header: {
+          show: false,
+          showSelector: false,
+          showSlot: false,
+          selector: {
+            icon: 'SwapOutlined',
+            prop: 'strinstallpos',
+          },
+          slot: {
+            icon: 'SwapOutlined',
+            prop: 'strinstallpos',
+          },
+        },
+        background: {
+          show: false,
+          type: 'video',
+          link: '',
+        },
+        layout: ['chart'],
+        board: [],
+        list: [],
+        table: [],
         chart: [
           {
-            type: 'line',
-            readFrom: 'readData.history',
-            xAxis: [{ prop: 'strinstallpos' }],
+            type: 'bar',
+            readFrom: 'sysdata.history',
+            xAxis: [{ prop: 'time' }],
             yAxis: [
-              { label: '风量', align: 'left' },
-              { label: '风速', align: 'right' },
+              { label: '回1', align: 'left' },
+              // { label: '回2', align: 'right' },
             ],
             series: [
-              { label: '风量', prop: 'f1Val' },
-              { label: '风速', prop: 'f2Val' },
+              { label: '回1', prop: 'hui1' },
+              // { label: '回2', prop: 'hui2' },
             ],
           },
         ],
       },
       showStyle: {
-        size: 'width:450px;height:280px;',
+        size: 'width:1000px;height:280px;',
         version: 'enhanced',
-        position: 'top:350px;left:0;',
+        position: 'top:640px;left:460px;',
       },
     },
     {
-      deviceType: 'fanlocal',
-      moduleName: '测试局扇',
+      deviceType: 'sys_wind',
+      moduleName: '测试测风装置',
       pageType: '',
       moduleData: {
         header: {
-          show: true,
+          show: false,
           showSelector: true,
           showSlot: false,
           selector: {
-            icon: 'SwapOutlined',
             prop: 'strinstallpos',
           },
           slot: {
-            icon: 'SwapOutlined',
             prop: 'strinstallpos',
           },
         },
@@ -200,31 +281,36 @@
           type: 'video',
           link: '',
         },
-        layout: ['list'],
-        list: [
+        layout: ['blast_delta'],
+        board: [
           {
             label: '风量',
+            type: 'C',
+            layout: 'val-top',
             prop: 'f1Val',
-            color: 'blue',
           },
           {
             label: '风速',
+            type: 'C',
+            layout: 'val-top',
             prop: 'f2Val',
-            color: 'green',
           },
         ],
+        list: [],
+        table: [],
         chart: [
           {
-            type: 'line',
-            readFrom: 'readData.history',
-            xAxis: [{ prop: 'strinstallpos' }],
+            type: 'pie',
+            readFrom: 'readData',
+            xAxis: [{ prop: 'stationname' }],
             yAxis: [
-              { label: '风量', align: 'left' },
-              { label: '风速', align: 'right' },
+              { label: '风量1', align: 'left' },
+              // { label: '回2', align: 'right' },
             ],
             series: [
-              { label: '风量', prop: 'f1Val' },
-              { label: '风速', prop: 'f2Val' },
+              { label: '风量1', prop: 'va' },
+              { label: '风量2', prop: 'va2' },
+              // { label: '回2', prop: 'hui2' },
             ],
           },
         ],
@@ -232,7 +318,54 @@
       showStyle: {
         size: 'width:450px;height:280px;',
         version: 'enhanced',
-        position: 'top:640px;left:0;',
+        position: 'top:60px;right:0;',
+      },
+    },
+    {
+      deviceType: 'sys_majorpath',
+      moduleName: '测试关键路线',
+      pageType: '',
+      moduleData: {
+        header: {
+          show: false,
+          showSelector: true,
+          showSlot: true,
+          selector: {
+            prop: 'devicePos',
+          },
+          slot: {
+            prop: 'devicePos',
+          },
+        },
+        background: {
+          show: false,
+          type: 'video',
+          link: '',
+        },
+        layout: ['table'],
+        board: [],
+        list: [],
+        table: [
+          {
+            readFrom: 'history',
+            columns: [
+              {
+                prop: 'A',
+                label: 'A列',
+              },
+              {
+                prop: 'B',
+                label: 'B列',
+              },
+            ],
+          },
+        ],
+        chart: [],
+      },
+      showStyle: {
+        size: 'width:450px;height:570px;',
+        version: 'enhanced',
+        position: 'top:350px;right:0;',
       },
     },
   ]);
@@ -273,23 +406,23 @@
       }
     }
 
-    .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-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);