Quellcode durchsuchen

feat(views): 环境监控区域编辑器支持与 iframe 进行通信

wangcong vor 2 Monaten
Ursprung
Commit
f24f0ef8b6

+ 6 - 0
src/types/index.ts

@@ -44,6 +44,12 @@ export interface IconObject {
   color?: string;
 }
 
+export interface IframeMsg {
+  msgType: string;
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  [key: string]: any;
+}
+
 export type FormRules<T> = {
   [K in keyof T]?: Rule[];
 } & {

+ 19 - 0
src/utils/env-area.ts

@@ -0,0 +1,19 @@
+/**
+ * 环境监控模块与其区域 Iframe 内嵌网页通信的消息前缀
+ */
+export const envAreaMsgPrefix = 'hvac-env-monitor';
+
+/**
+ * 环境监控模块与其区域 Iframe 内嵌网页通信的消息类型
+ */
+export const enum EnvAreaMsgType {
+  EditLoaded = 'edit-loaded',
+  EditArea = 'edit-area',
+  EditOutdoorTempHumidity = 'edit-outdoor-temp-humidity',
+  SubmitEditArea = 'submit-edit-area',
+  CancelEditArea = 'cancel-edit-area',
+}
+
+export const getEnvAreaMsgType = (type: EnvAreaMsgType) => {
+  return envAreaMsgPrefix + '-' + type;
+};

+ 58 - 1
src/views/env-monitor/AreaEditor.vue

@@ -1,7 +1,64 @@
 <script setup lang="ts">
+import { onMounted, onUnmounted, useTemplateRef, watch } from 'vue';
+
 import { useViewVisible } from '@/hooks/view-visible';
+import { EnvAreaMsgType, getEnvAreaMsgType } from '@/utils/env-area';
+
+import type { IframeMsg, RegionsPointsItem } from '@/types';
+
+interface Props {
+  areaData?: RegionsPointsItem;
+}
+
+const props = defineProps<Props>();
+
+const emit = defineEmits<{
+  openOutdoorDrawer: [];
+}>();
 
 const { visible, showView, hideView } = useViewVisible();
+const iframeRef = useTemplateRef('editorIframe');
+let isIframeLoaded = false;
+
+onMounted(() => {
+  window.addEventListener('message', handleIframeMsg);
+});
+
+onUnmounted(() => {
+  window.removeEventListener('message', handleIframeMsg);
+});
+
+watch(visible, () => {
+  if (visible.value && isIframeLoaded) {
+    sendAreaData();
+  }
+});
+
+const handleIframeMsg = (e: MessageEvent<IframeMsg>) => {
+  const { msgType } = e.data;
+
+  if (msgType === getEnvAreaMsgType(EnvAreaMsgType.EditLoaded)) {
+    isIframeLoaded = true;
+    sendAreaData();
+  } else if (msgType === getEnvAreaMsgType(EnvAreaMsgType.EditOutdoorTempHumidity)) {
+    emit('openOutdoorDrawer');
+  } else if (msgType === getEnvAreaMsgType(EnvAreaMsgType.SubmitEditArea)) {
+    console.log('submit');
+  } else if (msgType === getEnvAreaMsgType(EnvAreaMsgType.CancelEditArea)) {
+    hideView();
+  }
+};
+
+const sendAreaData = () => {
+  if (props.areaData) {
+    const msg: IframeMsg = {
+      msgType: getEnvAreaMsgType(EnvAreaMsgType.EditArea),
+      ...JSON.parse(JSON.stringify(props.areaData)),
+    };
+
+    iframeRef.value?.contentWindow?.postMessage(msg, '*');
+  }
+};
 
 defineExpose({
   showView,
@@ -19,7 +76,7 @@ defineExpose({
     :mask-closable="false"
     :footer="null"
   >
-    <iframe src="http://localhost:88/env-area"></iframe>
+    <iframe ref="editorIframe" src="http://localhost:88/env-area"></iframe>
   </AModal>
 </template>
 

+ 10 - 3
src/views/env-monitor/EnvMonitor.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { onMounted, ref, useTemplateRef, watch } from 'vue';
+import { computed, onMounted, ref, useTemplateRef, watch } from 'vue';
 import { message } from 'ant-design-vue';
 
 import ButtonTabs from '@/components/ButtonTabs.vue';
@@ -27,6 +27,7 @@ import { HumitureType } from '@/constants';
 
 import envMonitorBgc from '@/assets/img/env-monitor-bgc.png';
 
+import AreaEditor from './AreaEditor.vue';
 import EnvMonitorList from './EnvMonitorList.vue';
 import HumitureCurve from './HumitureCurve.vue';
 
@@ -542,6 +543,11 @@ onMounted(() => {
   getDeviceGroup();
   timeList.value = generateTimeArray();
 });
+
+const areaEditorRef = useTemplateRef('areaEditor');
+const currentAreaData = computed(() => {
+  return monitoringList.value.find((item) => item.id === selectId.value);
+});
 </script>
 
 <template>
@@ -617,13 +623,13 @@ onMounted(() => {
           </AFlex>
           <div v-show="regionList.length" class="canvas-div">
             <AFlex justify="space-between" class="canvas-div-top">
-              <AButton class="icon-button" @click="addOutdoorDrawer">
+              <AButton class="icon-button">
                 <SvgIcon name="outdoor" />
                 22.9℃|60.6%
               </AButton>
               <AFlex>
                 <AFlex justify="center" align="center" class="button-icon">
-                  <SvgIcon name="edit-o" />
+                  <SvgIcon name="edit-o" @click="areaEditorRef?.showView" />
                 </AFlex>
                 <div @click="copyRegion">
                   <AFlex justify="center" align="center" class="button-icon">
@@ -989,6 +995,7 @@ onMounted(() => {
         <AButton type="primary">{{ $t('common.confirm') }}</AButton>
       </AFlex>
     </AModal>
+    <AreaEditor ref="areaEditor" :area-data="currentAreaData" @open-outdoor-drawer="addOutdoorDrawer" />
   </div>
 </template>