فهرست منبع

公司端预警通知更新

lxh 1 ماه پیش
والد
کامیت
0c8db4ba0a

+ 306 - 0
src/layouts/default/header/components/VoiceBroadcastGsd.vue

@@ -0,0 +1,306 @@
+<template>
+    <div>
+        <div class="btn" @click="showWarningBroad">
+            <a-badge :dot="isWarningDot" style="display: flex; flex-direction: row">
+                <BellOutlined style="font-size: 22px; color: #fff; margin-right: 10px" />
+                <WarningOutlined style="font-size: 22px; color: #fff" />
+            </a-badge>
+        </div>
+        <div v-if="isShowWarningBroad" class="broadcast" ref="VoiceBroadcastRef" id="VoiceBroadcast">
+            <div class="title">
+                <div class="message-title">预警通知</div>
+                <div class="badge-box">
+                    <ClearOutlined style="font-size: 20px; color: #fff" @click="clearInfo" />
+                    <!-- <SoundOutlined :class="{ 'no-play': !isBroad }" style="font-size: 20px; color: #fff" @click="handleBroad" /> -->
+                </div>
+            </div>
+            <div class="broadcast-context">
+                <div class="context-tab">
+                    <div class="context-tab-item" :class="{ 'context-tab-item-active': activeKey == 0 }"> 全部</div>
+                    <!-- <div class="context-tab-item" :class="{ 'context-tab-item-active': activeKey == 1 }"
+                        > 未解决</div>
+                    <div class="context-tab-item" :class="{ 'context-tab-item-active': activeKey == 2 }"
+                        > 已解决</div> -->
+                </div>
+                <div class="context-box">
+                    <div v-if="(broadcastList && broadcastList.length == 0) || !broadcastList" class="no-context">暂无内容
+                    </div>
+                    <div class="context-detail" v-else v-for="(item, index) in broadcastList" :key="index"
+                        :style="{ color: item['isok'] == 0 ? '#f73210' : '#eee', fontWeight: item['isok'] == 0 ? '600' : '500' }">
+                        <div>{{ item['label'] }}</div>
+                        <!-- <div>{{ item['createTime'] }}</div>
+                        <div>{{ item['devicename'] }}</div>
+                        <div>{{ item['wardescrip'] || item['nwartype_dictText'] }}</div>
+                        <div>{{ item['isok'] ? '已解决' : '未解决' }}</div> -->
+                    </div>
+                </div>
+                <div v-if="broadcastList" class="more" @click="toMore">更多>></div>
+                <!-- <div v-if="broadcastList.length > 0" class="more" @click.self="test()">测试>></div> -->
+            </div>
+        </div>
+    </div>
+</template>
+<script lang="ts">
+import { Tooltip, Badge } from 'ant-design-vue';
+import { SoundOutlined, ClearOutlined, BellOutlined, WarningOutlined } from '@ant-design/icons-vue';
+import Icon from '/@/components/Icon';
+import { defineComponent, ref, unref, onMounted, nextTick, computed } from 'vue';
+import { defHttp } from '/@/utils/http/axios';
+import { useRouter } from 'vue-router';
+import { connectWebSocket, onWebSocket } from '/@/hooks/web/useWebSocket';
+import { getToken } from '/@/utils/auth';
+import { useUserStore } from '/@/store/modules/user';
+import { useGlobSetting } from '/@/hooks/setting';
+
+import { useDrag } from '@/hooks/event/useDrag';
+export default defineComponent({
+    name: 'VoiceBroadcast',
+    components: { Icon, Tooltip, Badge, SoundOutlined, ClearOutlined, BellOutlined, WarningOutlined },
+
+    setup() {
+        let websocketMsg = ref<any[]>([])
+        const userStore = useUserStore();
+        const glob = useGlobSetting();
+        const router = useRouter();
+        const activeKey = ref(0);
+        const isShowWarningBroad = ref(false);
+        const isWarningDot = ref(false);
+        let broadcastList = computed(() => {
+            return localStorage.getItem('messageArr');
+        })
+
+        //点击切换预警信息弹窗显示
+        function showWarningBroad() {
+            isShowWarningBroad.value = !isShowWarningBroad.value;
+            if (isShowWarningBroad.value) {
+                nextTick(() => {
+                    const dom = document.getElementById('VoiceBroadcast');
+                    if (dom) useDrag(dom);
+                });
+            }
+        }
+
+        async function clearInfo() {
+            localStorage.removeItem('messageArr');
+        }
+
+        //点击跳转预警历史详情
+        async function toMore() {
+            await router.push({ path: '/monitorChannel/device-monitor/warningHistory/company/home' });
+            showWarningBroad();
+        }
+
+        // 初始化 WebSocket
+        function initWebSocket() {
+            let token = getToken();
+            //将登录token生成一个短的标识
+            // let wsClientId = md5(token);
+            // let userId = unref(userStore.getUserInfo).id + '_' + wsClientId;
+            let userId = unref(userStore.getUserInfo).id + '?token=' + token;
+            // WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https
+            let url = glob.wsUrl?.replace('https://', 'wss://').replace('http://', 'ws://') + '/websocket/' + userId;
+            connectWebSocket(url);
+            onWebSocket(onWebSocketMessage);
+        }
+
+        async function onWebSocketMessage(data) {
+            debugger;
+            console.log('WebSocket 监测消息--------------》', data);
+            if (data.topic === 'warn' || data.cmd === 'user') {
+                const messageText = data['warndata'];
+                if (websocketMsg.value.length <= 20) {
+                    websocketMsg.value.push({ label: messageText })
+                    localStorage.setItem('messageArr', websocketMsg.value as any);
+                } else {
+                    websocketMsg.value.push({ label: messageText })
+                    websocketMsg.value.splice(0, 1)
+                    localStorage.setItem('messageArr', websocketMsg.value as any);
+                }
+                //   const messageText = '这是一个测试';
+                if (!isShowWarningBroad.value) {
+                    isWarningDot.value = true;
+                } else {
+                    isWarningDot.value = false;
+                }
+            }
+        }
+        onMounted(() => {
+            nextTick(async () => {
+                initWebSocket();
+            });
+            // window.speechSynthesis.onvoiceschanged = () => {
+            //     console.log('语音列表已更新');
+            // };
+        });
+
+        return {
+            showWarningBroad,
+            isShowWarningBroad,
+            activeKey,
+            broadcastList,
+            toMore,
+            clearInfo,
+            isWarningDot,
+        };
+    },
+});
+</script>
+<style lang="less" scoped>
+.btn {
+    line-height: 30px;
+    margin-right: 20px;
+    cursor: pointer;
+    display: flex;
+}
+
+.no-play {
+    position: relative;
+
+    &::after {
+        position: absolute;
+        width: 70%;
+        height: 100%;
+        content: '';
+        left: 15%;
+        top: 0;
+        background: linear-gradient(to bottom left,
+                transparent 0%,
+                transparent calc(50% - 1px),
+                #ffffff 50%,
+                transparent calc(50% + 1px),
+                transparent 100%);
+    }
+}
+
+.broadcast {
+    width: 500px;
+    height: 350px;
+    border-radius: 4px;
+    position: fixed;
+    top: 50px;
+    right: 20px;
+    background-color: rgb(255, 255, 255);
+    background: url('../../../../assets/images/warn-dialog-bg.png') no-repeat center;
+    background-size: 100% 100%;
+    z-index: 9999999;
+    color: #fff;
+
+    .title {
+        height: 32px;
+        padding: 0 20px;
+
+        :deep(.ant-badge:not(.ant-badge-status)) {
+            margin-right: 40px !important;
+        }
+
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        margin-bottom: 5px;
+
+        .message-title {
+            font-size: 18px;
+            padding-top: 10px;
+        }
+
+        .badge-box {
+            display: flex;
+            align-items: center;
+            padding-top: 10px;
+
+            .badge-title {
+                display: inline-block;
+                width: 62px;
+                line-height: 32px;
+                background-color: #2174f0;
+                border-radius: 26px;
+                text-align: center;
+                color: #fff;
+                padding-bottom: 2px;
+            }
+        }
+    }
+
+    .broadcast-context {
+        .context-tab {
+            display: flex;
+            padding: 20px;
+
+            .context-tab-item {
+                line-height: 24px;
+                background-color: #6b6b6b;
+                border-radius: 24px;
+                text-align: center;
+                padding: 0 10px;
+                color: #fff;
+                margin: 5px;
+                cursor: pointer;
+                font-size: 14px;
+            }
+
+            .context-tab-item-active {
+                background-color: #2174f0;
+            }
+        }
+
+        .context-box {
+            flex: 1;
+            padding: 0 10px;
+            height: 200px;
+            overflow-y: auto;
+
+            .no-context {
+                display: flex;
+                justify-content: center;
+                padding-top: 30px;
+                font-size: 16px;
+            }
+
+            .context-detail {
+                width: 100%;
+                display: flex;
+                justify-content: space-between;
+                line-height: 24px;
+                padding: 0px 16px;
+
+                // div {
+                //     display: flex;
+                //     justify-content: flex-start;
+
+                //     &:nth-child(1) {
+                //         width: 44%;
+                //     }
+
+                //     &:nth-child(2) {
+                //         width: 40%;
+                //     }
+
+                //     &:nth-child(3) {
+                //         width: 25%;
+                //     }
+
+                //     &:nth-child(4) {
+                //         width: 15%;
+                //     }
+                // }
+            }
+        }
+
+        .more {
+            position: absolute;
+            left: 24px;
+            bottom: 10px;
+            cursor: pointer;
+
+            &:hover {
+                color: #2174f0;
+            }
+        }
+    }
+}
+
+:deep(.zxm-badge-count) {
+    width: 8px;
+    height: 8px;
+}
+</style>

+ 256 - 253
src/layouts/default/header/index.vue

@@ -1,28 +1,23 @@
 <template>
-  <Header
-    v-if="
-      ((!getShowFullHeader && !currentRoute.path.endsWith('home')) || currentRoute.path.startsWith('/micro-vent-3dModal/modelchannel/')) &&
-      !noHeadeLink.includes(currentRoute.path) &&
-      currentRoute.path !== homePath
-    "
-    :class="[
+  <Header v-if="
+    ((!getShowFullHeader && !currentRoute.path.endsWith('home')) || currentRoute.path.startsWith('/micro-vent-3dModal/modelchannel/')) &&
+    !noHeadeLink.includes(currentRoute.path) &&
+    currentRoute.path !== homePath
+  " :class="[
       ...getHeaderClass,
       {
         'vent-header': currentRoute.path.startsWith('/monitorChannel/monitor-'),
         'normal-header': !currentRoute.path.startsWith('/monitorChannel/monitor-'),
         'no-header': currentRoute.path.endsWith('home'),
       },
-    ]"
-    style="z-index: 1"
-  >
+    ]" style="z-index: 1">
     <!-- left start -->
     <div :class="`${prefixCls}-left`">
       <!-- logo -->
       <!-- <AppLogo v-if="getShowHeaderLogo || getIsMobile" :class="`${prefixCls}-logo`" :theme="getHeaderTheme" :style="getLogoWidth" /> -->
       <AppLogo :class="`${prefixCls}-logo`" :theme="getHeaderTheme" :style="getLogoWidth" />
-      <div v-if="!currentRoute.path.startsWith('/monitorChannel/monitor-')" style="margin-top: 5px; color: #aaa; margin-left: 10px; font-weight: 600"
-        >/{{ currentRoute.meta.title }}</div
-      >
+      <div v-if="!currentRoute.path.startsWith('/monitorChannel/monitor-')"
+        style="margin-top: 5px; color: #aaa; margin-left: 10px; font-weight: 600">/{{ currentRoute.meta.title }}</div>
       <!-- <LayoutTrigger
         v-if="(getShowContent && getShowHeaderTrigger && !getSplit && !getIsMixSidebar) || getIsMobile"
         :theme="getHeaderTheme"
@@ -58,266 +53,274 @@
     <div class="right-position">
       <!-- 公司端不显示语音播报功能 -->
       <VoiceBroadcast v-if="sysOrgCode != 'sdmtjtgsd'" />
+      <VoiceBroadcastGsd v-if="sysOrgCode == 'sdmtjtgsd'" />
       <UserDropDown v-if="showUserDropdown" :theme="getHeaderTheme" />
       <LoginSelect ref="loginSelectRef" @success="loginSelectOk" />
     </div>
   </div>
 </template>
 <script lang="ts">
-  import { defineComponent, unref, computed, ref, onMounted, toRaw } from 'vue';
-  import { useGlobSetting } from '/@/hooks/setting';
-  import { propTypes } from '/@/utils/propTypes';
-
-  import { Layout } from 'ant-design-vue';
-  import { AppLogo } from '/@/components/Application';
-  import LayoutMenu from '../menu/index.vue';
-  import LayoutTrigger from '../trigger/index.vue';
-
-  import { AppSearch } from '/@/components/Application';
-
-  import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
-  import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
-  import { useRootSetting } from '/@/hooks/setting/useRootSetting';
-
-  import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
-  import { SettingButtonPositionEnum } from '/@/enums/appEnum';
-  import { AppLocalePicker } from '/@/components/Application';
-
-  import { UserDropDown, LayoutBreadcrumb, FullScreen, Notify, ErrorAction, LockScreen } from './components';
-  import { useAppInject } from '/@/hooks/web/useAppInject';
-  import { useDesign } from '/@/hooks/web/useDesign';
-
-  import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
-  import { useLocale } from '/@/locales/useLocale';
-
-  import VoiceBroadcast from './components/VoiceBroadcast.vue';
-
-  import LoginSelect from '/@/views/sys/login/LoginSelect.vue';
-  import { useUserStore } from '/@/store/modules/user';
-  import { useRouter } from 'vue-router';
-
-  import { noHeadeLink } from '../layout.data';
-
-  export default defineComponent({
-    name: 'LayoutHeader',
-    components: {
-      Header: Layout.Header,
-      AppLogo,
-      LayoutTrigger,
-      LayoutBreadcrumb,
-      LayoutMenu,
-      UserDropDown,
-      AppLocalePicker,
-      FullScreen,
-      Notify,
-      AppSearch,
-      ErrorAction,
-      LockScreen,
-      LoginSelect,
-      VoiceBroadcast,
-      SettingDrawer: createAsyncComponent(() => import('/@/layouts/default/setting/index.vue'), {
-        loading: true,
-      }),
-    },
-    props: {
-      fixed: propTypes.bool,
-    },
-    setup(props) {
-      const { prefixCls } = useDesign('layout-header');
-      const userStore = useUserStore();
-      const { currentRoute } = useRouter();
-      console.log(currentRoute);
-
-      const { getShowTopMenu, getShowHeaderTrigger, getSplit, getIsMixMode, getMenuWidth, getIsMixSidebar } = useMenuSetting();
-      const { getUseErrorHandle, getShowSettingButton, getSettingButtonPosition } = useRootSetting();
-      const { title, sysOrgCode, homePath } = useGlobSetting();
-      const {
-        getHeaderTheme,
-        getShowFullScreen,
-        getShowNotice,
-        getShowContent,
-        getShowBread,
-        getShowHeaderLogo,
-        getShowHeader,
-        getShowSearch,
-        getUseLockPage,
-        getShowBreadTitle,
-        getShowFullHeaderRef,
-      } = useHeaderSetting();
-
-      const { getShowLocalePicker } = useLocale();
-
-      const { getIsMobile } = useAppInject();
-
-      const getHeaderClass = computed(() => {
-        const theme = unref(getHeaderTheme);
-        return [
-          prefixCls,
-          {
-            [`${prefixCls}--fixed`]: props.fixed,
-            [`${prefixCls}--mobile`]: unref(getIsMobile),
-            [`${prefixCls}--${theme}`]: theme,
-          },
-        ];
-      });
-
-      const getShowFullHeader = computed(() => {
-        const route = unref(currentRoute);
-        return getShowFullHeaderRef && route.path.startsWith('/micro-');
-      });
-
-      const getShowSetting = computed(() => {
-        if (!unref(getShowSettingButton)) {
-          return false;
-        }
-        const settingButtonPosition = unref(getSettingButtonPosition);
-
-        if (settingButtonPosition === SettingButtonPositionEnum.AUTO) {
-          return unref(getShowHeader);
-        }
-        return settingButtonPosition === SettingButtonPositionEnum.HEADER;
-      });
-
-      const getLogoWidth = computed(() => {
-        if (!unref(getIsMixMode) || unref(getIsMobile)) {
-          return {};
-        }
-        const width = unref(getMenuWidth) < 180 ? 180 : unref(getMenuWidth);
-        return { width: `${width}px` };
-      });
-
-      const getSplitType = computed(() => {
-        return unref(getSplit) ? MenuSplitTyeEnum.TOP : MenuSplitTyeEnum.NONE;
-      });
-
-      const getMenuMode = computed(() => {
-        return unref(getSplit) ? MenuModeEnum.HORIZONTAL : null;
-      });
-
-      // /**
-      //  * 首页多租户部门弹窗逻辑
-      //  */
-      const loginSelectRef = ref();
-
-      function showLoginSelect() {
-        //update-begin---author:liusq  Date:20220101  for:判断登录进来是否需要弹窗选择租户----
-        //判断是否是登陆进来
-        const loginInfo = toRaw(userStore.getLoginInfo) || {};
-        if (!!loginInfo.isLogin) {
-          loginSelectRef.value.show(loginInfo);
-        }
-        //update-end---author:liusq  Date:20220101  for:判断登录进来是否需要弹窗选择租户----
+import { defineComponent, unref, computed, ref, onMounted, toRaw } from 'vue';
+import { useGlobSetting } from '/@/hooks/setting';
+import { propTypes } from '/@/utils/propTypes';
+
+import { Layout } from 'ant-design-vue';
+import { AppLogo } from '/@/components/Application';
+import LayoutMenu from '../menu/index.vue';
+import LayoutTrigger from '../trigger/index.vue';
+
+import { AppSearch } from '/@/components/Application';
+
+import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
+import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
+import { useRootSetting } from '/@/hooks/setting/useRootSetting';
+
+import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
+import { SettingButtonPositionEnum } from '/@/enums/appEnum';
+import { AppLocalePicker } from '/@/components/Application';
+
+import { UserDropDown, LayoutBreadcrumb, FullScreen, Notify, ErrorAction, LockScreen } from './components';
+import { useAppInject } from '/@/hooks/web/useAppInject';
+import { useDesign } from '/@/hooks/web/useDesign';
+
+import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+import { useLocale } from '/@/locales/useLocale';
+
+import VoiceBroadcast from './components/VoiceBroadcast.vue';
+import VoiceBroadcastGsd from './components/VoiceBroadcastGsd.vue';
+
+import LoginSelect from '/@/views/sys/login/LoginSelect.vue';
+import { useUserStore } from '/@/store/modules/user';
+import { useRouter } from 'vue-router';
+
+import { noHeadeLink } from '../layout.data';
+
+export default defineComponent({
+  name: 'LayoutHeader',
+  components: {
+    Header: Layout.Header,
+    AppLogo,
+    LayoutTrigger,
+    LayoutBreadcrumb,
+    LayoutMenu,
+    UserDropDown,
+    AppLocalePicker,
+    FullScreen,
+    Notify,
+    AppSearch,
+    ErrorAction,
+    LockScreen,
+    LoginSelect,
+    VoiceBroadcast,
+    VoiceBroadcastGsd,
+    SettingDrawer: createAsyncComponent(() => import('/@/layouts/default/setting/index.vue'), {
+      loading: true,
+    }),
+  },
+  props: {
+    fixed: propTypes.bool,
+  },
+  setup(props) {
+    const { prefixCls } = useDesign('layout-header');
+    const userStore = useUserStore();
+    const { currentRoute } = useRouter();
+    console.log(currentRoute);
+
+    const { getShowTopMenu, getShowHeaderTrigger, getSplit, getIsMixMode, getMenuWidth, getIsMixSidebar } = useMenuSetting();
+    const { getUseErrorHandle, getShowSettingButton, getSettingButtonPosition } = useRootSetting();
+    const { title, sysOrgCode, homePath } = useGlobSetting();
+    const {
+      getHeaderTheme,
+      getShowFullScreen,
+      getShowNotice,
+      getShowContent,
+      getShowBread,
+      getShowHeaderLogo,
+      getShowHeader,
+      getShowSearch,
+      getUseLockPage,
+      getShowBreadTitle,
+      getShowFullHeaderRef,
+    } = useHeaderSetting();
+
+    const { getShowLocalePicker } = useLocale();
+
+    const { getIsMobile } = useAppInject();
+
+    const getHeaderClass = computed(() => {
+      const theme = unref(getHeaderTheme);
+      return [
+        prefixCls,
+        {
+          [`${prefixCls}--fixed`]: props.fixed,
+          [`${prefixCls}--mobile`]: unref(getIsMobile),
+          [`${prefixCls}--${theme}`]: theme,
+        },
+      ];
+    });
+
+    const getShowFullHeader = computed(() => {
+      const route = unref(currentRoute);
+      return getShowFullHeaderRef && route.path.startsWith('/micro-');
+    });
+
+    const getShowSetting = computed(() => {
+      if (!unref(getShowSettingButton)) {
+        return false;
       }
+      const settingButtonPosition = unref(getSettingButtonPosition);
 
-      function loginSelectOk() {
-        console.log('成功。。。。。');
+      if (settingButtonPosition === SettingButtonPositionEnum.AUTO) {
+        return unref(getShowHeader);
       }
+      return settingButtonPosition === SettingButtonPositionEnum.HEADER;
+    });
 
-      // 用户下拉框应该在以下情况中隐藏:
-      // 1. 本页面是由其他页面的 iframe 嵌入的页面
-      const showUserDropdown = computed(() => {
-        return window.self === window.top;
-      });
+    const getLogoWidth = computed(() => {
+      if (!unref(getIsMixMode) || unref(getIsMobile)) {
+        return {};
+      }
+      const width = unref(getMenuWidth) < 180 ? 180 : unref(getMenuWidth);
+      return { width: `${width}px` };
+    });
+
+    const getSplitType = computed(() => {
+      return unref(getSplit) ? MenuSplitTyeEnum.TOP : MenuSplitTyeEnum.NONE;
+    });
+
+    const getMenuMode = computed(() => {
+      return unref(getSplit) ? MenuModeEnum.HORIZONTAL : null;
+    });
+
+    // /**
+    //  * 首页多租户部门弹窗逻辑
+    //  */
+    const loginSelectRef = ref();
+
+    function showLoginSelect() {
+      //update-begin---author:liusq  Date:20220101  for:判断登录进来是否需要弹窗选择租户----
+      //判断是否是登陆进来
+      const loginInfo = toRaw(userStore.getLoginInfo) || {};
+      if (!!loginInfo.isLogin) {
+        loginSelectRef.value.show(loginInfo);
+      }
+      //update-end---author:liusq  Date:20220101  for:判断登录进来是否需要弹窗选择租户----
+    }
 
-      onMounted(() => {
-        showLoginSelect();
-      });
+    function loginSelectOk() {
+      console.log('成功。。。。。');
+    }
 
-      return {
-        prefixCls,
-        getHeaderClass,
-        getShowHeaderLogo,
-        getHeaderTheme,
-        getShowHeaderTrigger,
-        getIsMobile,
-        getShowBreadTitle,
-        getShowBread,
-        getShowContent,
-        getSplitType,
-        getSplit,
-        getMenuMode,
-        getShowTopMenu,
-        getShowLocalePicker,
-        getShowFullScreen,
-        getShowNotice,
-        getUseErrorHandle,
-        getLogoWidth,
-        getIsMixSidebar,
-        getShowSettingButton,
-        getShowSetting,
-        getShowSearch,
-        getUseLockPage,
-        loginSelectOk,
-        loginSelectRef,
-        currentRoute,
-        title,
-        getShowFullHeader,
-        noHeadeLink,
-        showUserDropdown,
-        sysOrgCode,
-        homePath,
-      };
-    },
-  });
+    // 用户下拉框应该在以下情况中隐藏:
+    // 1. 本页面是由其他页面的 iframe 嵌入的页面
+    const showUserDropdown = computed(() => {
+      return window.self === window.top;
+    });
+
+    onMounted(() => {
+      showLoginSelect();
+    });
+
+    return {
+      prefixCls,
+      getHeaderClass,
+      getShowHeaderLogo,
+      getHeaderTheme,
+      getShowHeaderTrigger,
+      getIsMobile,
+      getShowBreadTitle,
+      getShowBread,
+      getShowContent,
+      getSplitType,
+      getSplit,
+      getMenuMode,
+      getShowTopMenu,
+      getShowLocalePicker,
+      getShowFullScreen,
+      getShowNotice,
+      getUseErrorHandle,
+      getLogoWidth,
+      getIsMixSidebar,
+      getShowSettingButton,
+      getShowSetting,
+      getShowSearch,
+      getUseLockPage,
+      loginSelectOk,
+      loginSelectRef,
+      currentRoute,
+      title,
+      getShowFullHeader,
+      noHeadeLink,
+      showUserDropdown,
+      sysOrgCode,
+      homePath,
+    };
+  },
+});
 </script>
 <style lang="less">
-  @import './index.less';
-  //update-begin---author:scott ---date:2022-09-30  for:默认隐藏顶部菜单面包屑-----------
-  //顶部欢迎语展示样式
-  @prefix-cls: ~'@{namespace}-layout-header';
-
-  .@{prefix-cls} {
-    display: flex;
-    padding: 0 8px;
-    // align-items: center;
+@import './index.less';
+//update-begin---author:scott ---date:2022-09-30  for:默认隐藏顶部菜单面包屑-----------
+//顶部欢迎语展示样式
+@prefix-cls: ~'@{namespace}-layout-header';
+
+.@{prefix-cls} {
+  display: flex;
+  padding: 0 8px;
+  // align-items: center;
+
+  .headerIntroductionClass {
+    margin-right: 4px;
+    margin-bottom: 2px;
+    border-bottom: 0px;
+    border-left: 0px;
+  }
 
+  &--light {
     .headerIntroductionClass {
-      margin-right: 4px;
-      margin-bottom: 2px;
-      border-bottom: 0px;
-      border-left: 0px;
+      color: @breadcrumb-item-normal-color;
     }
+  }
 
-    &--light {
-      .headerIntroductionClass {
-        color: @breadcrumb-item-normal-color;
-      }
+  &--dark {
+    .headerIntroductionClass {
+      color: rgba(255, 255, 255, 0.6);
     }
 
-    &--dark {
-      .headerIntroductionClass {
-        color: rgba(255, 255, 255, 0.6);
-      }
-      .anticon {
-        color: rgba(255, 255, 255, 0.8);
-      }
+    .anticon {
+      color: rgba(255, 255, 255, 0.8);
     }
-    //update-end---author:scott ---date::2022-09-30  for:默认隐藏顶部菜单面包屑--------------
-  }
-  // background: linear-gradient(#003f77, #0a134c);
-  //   // background: linear-gradient(#02050c 0%, #03114c 100%);
-  //   // border: none;
-  //   border-bottom: 1px solid #81aabf01;
-  //   padding-bottom: 2px;
-  //   box-shadow: 0 0 20px #44caff55 inset;
-  .normal-header {
-    height: 52px !important;
-    line-height: 52px !important;
-    background: var(--vent-header-bg-color) !important;
-    // background: linear-gradient(#005177,#0a344c) !important;
-    border-bottom: 1px solid #81aabf01 !important;
-    padding-bottom: 2px !important;
-    box-shadow: 0 0 20px #44caff55 inset !important;
-    padding: 0 8px !important;
-  }
-  .no-header {
-    height: 0px !important;
-    display: none !important;
-  }
-  .header-nav-title {
-    background-image: linear-gradient(#ffffff 50%, #60f4ff);
-    -webkit-background-clip: text;
-    color: transparent;
-    font-weight: 600;
   }
+
+  //update-end---author:scott ---date::2022-09-30  for:默认隐藏顶部菜单面包屑--------------
+}
+
+// background: linear-gradient(#003f77, #0a134c);
+//   // background: linear-gradient(#02050c 0%, #03114c 100%);
+//   // border: none;
+//   border-bottom: 1px solid #81aabf01;
+//   padding-bottom: 2px;
+//   box-shadow: 0 0 20px #44caff55 inset;
+.normal-header {
+  height: 52px !important;
+  line-height: 52px !important;
+  background: var(--vent-header-bg-color) !important;
+  // background: linear-gradient(#005177,#0a344c) !important;
+  border-bottom: 1px solid #81aabf01 !important;
+  padding-bottom: 2px !important;
+  box-shadow: 0 0 20px #44caff55 inset !important;
+  padding: 0 8px !important;
+}
+
+.no-header {
+  height: 0px !important;
+  display: none !important;
+}
+
+.header-nav-title {
+  background-image: linear-gradient(#ffffff 50%, #60f4ff);
+  -webkit-background-clip: text;
+  color: transparent;
+  font-weight: 600;
+}
 </style>

+ 0 - 137
src/views/vent/monitorManager/gasPumpMonitor/components/ceshi.json

@@ -1,137 +0,0 @@
-{
-    "success": true,
-    "message": "",
-    "code": 200,
-    "result": {
-        "cmd": "monitordata",
-        "msgTxt": [
-            {
-                "datalist": [
-                    {
-                        "msgType": null,
-                        "deviceID": "1775327220752187394",
-                        "strname": "31煤地下瓦斯泵站",
-                        "strinstallpos": "31煤地下瓦斯泵站",
-                        "fsectarea": "null",
-                        "stationname": "31煤瓦斯泵站",
-                        "stationtype": "redis",
-                        "deviceType": "pump_under_31",
-                        "typeName": "31煤地下瓦斯泵站",
-                        "netStatus": 1,
-                        "warnFlag": 0,
-                        "warnLevel": 0,
-                        "warnLevel_str": "正常",
-                        "warnTime": null,
-                        "readTime": "2024-04-03 09:00:43",
-                        "warnDes": "",
-                        "frontGateOpenCtrl": null,
-                        "rearGateOpenCtrl": null,
-                        "readData": {
-                            "SubmarinePump1_MOT4_Ia": "0",
-                            "SubmarinePump2_MOT2_Ia": "0",
-                            "CentrifugalPump1_GVL1_OpenDegree": "100.0",
-                            "sign": "0",
-                            "T102_HighVoltSwitch_Current": "0",
-                            "CentrifugalPump1_MOT1_AvgVoltage": "618.0",
-                            "SubmarinePump2_MOT2_Uab": "1121",
-                            "CentrifugalPump2_FlowSensor2_InputFlux": "0.05",
-                            "CentrifugalPump2_MOT_FrontAxleTemp": "14.84",
-                            "T102_HighVoltSwitch_CBStatus": "1",
-                            "PressureSensor2_Pressure": "-10.38",
-                            "CentrifugalPump2_PU_CtrlMode": "0",
-                            "CentrifugalPump2_VFD_Status": "0",
-                            "CentrifugalPump1_PU_StateWord": "12",
-                            "CentrifugalPump1_PU_CtrlMode": "0",
-                            "CentrifugalPump1_FlowSensor2_InputFlux": "2.53",
-                            "CentrifugalPump2_PU_Temp": "15.0",
-                            "CentrifugalPump2_LiquidLevelSensor3_Level": "344.0",
-                            "SubmarinePump2_MOT3_Uab": "1121",
-                            "CentrifugalPump1_LiquidLevelSensor1_Level": "369.0",
-                            "SubmarinePump1_MOT1_Ia": "3",
-                            "T101_LowVoltSwitch_CBStatus": "1",
-                            "SubmarinePump1_MOT3_Ia": "0",
-                            "CentrifugalPump2_GVL1_OpenDegree": "0.0",
-                            "CentrifugalPump2_VFD_CtrlMode": "0",
-                            "SubmarinePump1_MOT4_Uab": "1140",
-                            "CentrifugalPump1_VFD_CtrlMode": "1.0",
-                            "CentrifugalPump2_FlowSensor1_InputFlux": "0.05",
-                            "CtrlMode": "0.0",
-                            "SubmarinePump2_MOT4_Uab": "1121",
-                            "CentrifugalPump1_VFD_Current": "156.0",
-                            "VFD_GasConcentration1": "0.64",
-                            "VFD_GasConcentration2": "0.08",
-                            "SubmarinePump1_MOT3_Uab": "1140",
-                            "CentrifugalPump1_LiquidLevelSensor2_Level": "344.0",
-                            "CentrifugalPump2_GVL2_OpenDegree": "0.0",
-                            "CentrifugalPump2_VFD_Frequency": "0.0",
-                            "CentrifugalPump1_FlowSensor1_InputFlux": "2.53",
-                            "SubmarinePump2_PU1_Status1": "0",
-                            "CentrifugalPump2_VFD_Current": "0.0",
-                            "CentrifugalPump2_LiquidLevelSensor2_Level": "353.0",
-                            "SubmarinePump1_PU1_Status1": "1",
-                            "SubmarinePump1_MOT2_Ia": "0",
-                            "SubmarinePump1_MOT1_Uab": "1140",
-                            "CentrifugalPump1_FlowSensor3_InputFlux": "0.0",
-                            "CentrifugalPump2_LiquidLevelSensor1_Level": "346.0",
-                            "CentrifugalPump1_GVL3_Status": "0.0",
-                            "CentrifugalPump2_GVL3_Status": "0.0",
-                            "CentrifugalPump1_GVL4_Status": "0.0",
-                            "CentrifugalPump2_GVL4_Status": "0.0",
-                            "PressureSensor1_Pressure": "-10.0",
-                            "CentrifugalPump1_LiquidLevelSensor3_Level": "413.0",
-                            "CentrifugalPump2_VFD_DCBusVoltage": "1177.0",
-                            "CentrifugalPump1_VFD_Frequency": "27.0",
-                            "CentrifugalPump1_GVL2_OpenDegree": "100.0",
-                            "GVL_OpenDegree": "60.0",
-                            "CentrifugalPump1_PU_Temp": "26.77",
-                            "SubmarinePump1_MOT2_Uab": "1140",
-                            "TrackRobot_PipeCO": "0.0",
-                            "CentrifugalPump2_PU_StateWord": "116",
-                            "CentrifugalPump2_MOT1_AvgVoltage": "0.0",
-                            "CentrifugalPump1_VFD_DCBusVoltage": "1133.0",
-                            "SubmarinePump2_MOT3_Ia": "0",
-                            "CentrifugalPump2_GEA_Temp": "15.0",
-                            "CentrifugalPump1_GEA_Temp": "35.17",
-                            "T102_HighVoltSwitch_SysVoltage": "10487",
-                            "T101_LowVoltSwitch_SysVoltage": "1232",
-                            "SubmarinePump2_MOT1_Ia": "0",
-                            "T102_LowVoltSwitch_SysVoltage": "1218",
-                            "CentrifugalPump1_VFD_Status": "1",
-                            "SubmarinePump2_PU2_Status1": "0",
-                            "T102_LowVoltSwitch_Current": "0",
-                            "CentrifugalPump1_MOT_FrontAxleTemp": "33.25",
-                            "T101_HighVoltSwitch_Current": "8",
-                            "VFD_CavityTemp": "18.0",
-                            "CentrifugalPump2_FlowSensor3_InputFlux": "0.05",
-                            "T101_LowVoltSwitch_Current": "70",
-                            "SubmarinePump1_PU2_Status1": "0",
-                            "FlowSensor_InputFlux": "237.94",
-                            "SubmarinePump2_MOT4_Ia": "0",
-                            "SubmarinePump2_MOT1_Uab": "1121",
-                            "isRun": "-2",
-                            "T101_HighVoltSwitch_CBStatus": "1",
-                            "T102_LowVoltSwitch_CBStatus": "1",
-                            "T101_HighVoltSwitch_SysVoltage": "10646"
-                        },
-                        "readDataDes": null,
-                        "summaryHour": [],
-                        "summaryDay": [],
-                        "history": [],
-                        "dayhistory": [],
-                        "totalInfo": null,
-                        "sign": null,
-                        "cameras": [],
-                        "links": [],
-                        "other1": null,
-                        "other2": null,
-                        "other3": null,
-                        "remarkInfo": null,
-                        "linkInfo": null
-                    }
-                ],
-                "type": "pump_under_31"
-            }
-        ]
-    },
-    "timestamp": 1712106043720
-}

+ 637 - 0
src/views/vent/monitorManager/gasPumpMonitor/components/gasPumpHomeCopy.vue

@@ -0,0 +1,637 @@
+<template>
+  <div class="monitor-container">
+    <div id="FlowSensor" class="FlowSensor-box" style="position: absolute; display: none">
+      <!-- <div class="elementContent" v-if="selectData['deviceType'].startsWith('pump_under') || selectData['deviceType'] == 'pump_n12m2pq'">
+        <fourBorderBg>
+          <template v-for="(item, index) in modelMonitor" :key="index">
+            <div class="gas-monitor-row">
+              <div class="title">{{ item.title }}</div>
+              <div class="value">{{ selectData[item.code] ? selectData[item.code] : '-' }}</div>
+            </div>
+          </template>
+        </fourBorderBg>
+      </div> -->
+    </div>
+    <!-- 布尔台新瓦斯泵模型上的数据 -->
+    <div class="elementContent" style="position: absolute; display: none">
+      <div v-for="(tag, index) in modelMonitorTags" :key="index" :id="tag.domId" class="modal-monitor-box">
+        <div class="title">{{ tag.title }}</div>
+        <div
+          v-if="tag.type == 'sign'"
+          class="signal-round"
+          :class="{ 'signal-round-gry': selectData[tag.code] != 1, 'signal-round-run': selectData[tag.code] == 1 }"
+        ></div>
+        <div v-else class="value">{{ selectData[tag.code] }}</div>
+      </div>
+    </div>
+    <div v-if="selectData['netStatus'] == 0" class="device-state">网络断开</div>
+    <div class="lr left-box">
+      <div class="left-container">
+        <div class="monitor-box">
+          <ventBox1>
+            <template #title>
+              <div>瓦斯泵</div>
+            </template>
+            <template #container>
+              <div v-for="key in 2" :key="key">
+                <div class="parameter-title group-parameter-title">
+                  <SvgIcon class="icon" size="14" name="pulp-title" /><span>{{ key }}#瓦斯泵磁力启动器</span>
+                </div>
+                <div class="input-box">
+                  <div v-for="(item, index) in pumpMonitorData" class="input-item" :key="index">
+                    <div class="title">{{ item.title }}:</div>
+                    <template v-if="item.type !== 'sign' && item.type !== 'warning'">
+                      <div class="value">{{
+                        selectData && selectData[item.code.replace('Starter', `Starter${key + 4}`)]
+                          ? formatNum(selectData[item.code.replace('Starter', `Starter${key + 4}`)], 1)
+                          : '-'
+                      }}</div>
+                    </template>
+                    <template v-else>
+                      <div class="value">
+                        <span
+                          :class="{
+                            'signal-round': true,
+                            'signal-round-run': item.type === 'sign' && selectData[item.code.replace('Starter', `Starter${key + 4}`)] == '1',
+                            'signal-round-gry': selectData[item.code.replace('Starter', `Starter${key + 4}`)] == '0',
+                            'signal-round-warning': item.type === 'warning' && selectData[item.code.replace('Starter', `Starter${key + 4}`)] == '1',
+                          }"
+                        ></span>
+                      </div>
+                    </template>
+                  </div>
+                </div>
+              </div>
+            </template>
+          </ventBox1>
+          <ventBox1 class="vent-margin-t-10">
+            <template #title>
+              <div>注水泵</div>
+            </template>
+            <template #container>
+              <div v-for="key in 2" :key="key">
+                <div class="parameter-title group-parameter-title">
+                  <SvgIcon class="icon" size="14" name="pulp-title" /><span>{{ key }}#注水泵</span>
+                </div>
+                <div class="input-box">
+                  <div v-for="(item, index) in waterPumpData" class="input-item" :key="index">
+                    <div class="title">{{ item.title }}:</div>
+                    <template v-if="item.type !== 'sign'">
+                      <div class="value">{{
+                        selectData && selectData[item.code.replace('WaterfloodPump', `WaterfloodPump${key}`)]
+                          ? formatNum(selectData[item.code.replace('WaterfloodPump', `WaterfloodPump${key}`)], 1)
+                          : '-'
+                      }}</div>
+                    </template>
+                    <template v-else>
+                      <div class="value">
+                        <span
+                          :class="{
+                            'signal-round': true,
+                            'signal-round-run': selectData[item.code.replace('WaterfloodPump', `WaterfloodPump${key}`)],
+                            'signal-round-gry': selectData[item.code.replace('WaterfloodPump', `WaterfloodPump${key}`)] == '0',
+                          }"
+                        ></span>
+                      </div>
+                    </template>
+                  </div>
+                </div>
+              </div>
+            </template>
+          </ventBox1>
+          <ventBox1 class="vent-margin-t-10">
+            <template #title>
+              <div>排水泵</div>
+            </template>
+            <template #container>
+              <div v-for="key in 2" :key="key">
+                <div class="parameter-title group-parameter-title">
+                  <SvgIcon class="icon" size="14" name="pulp-title" /><span>{{ key }}#排水泵</span>
+                </div>
+                <div class="input-box">
+                  <div v-for="(item, index) in dewateringPumpData" class="input-item" :key="index">
+                    <div class="title">{{ item.title }}:</div>
+                    <template v-if="item.type !== 'sign'">
+                      <div class="value">{{
+                        selectData && selectData[item.code.replace('DewateringPump', `DewateringPump${key}`)]
+                          ? formatNum(selectData[item.code.replace('DewateringPump', `DewateringPump${key}`)], 1)
+                          : '-'
+                      }}</div>
+                    </template>
+                    <template v-else>
+                      <div class="value">
+                        <span
+                          :class="{
+                            'signal-round': true,
+                            'signal-round-run': selectData[item.code.replace('DewateringPump', `DewateringPump${key}`)],
+                            'signal-round-gry': selectData[item.code.replace('DewateringPump', `DewateringPump${key}`)] == '0',
+                          }"
+                        ></span>
+                      </div>
+                    </template>
+                  </div>
+                </div>
+              </div>
+            </template>
+          </ventBox1>
+        </div>
+      </div>
+    </div>
+    <div class="lr right-box">
+      <div class="item-box sensor-container">
+        <ventBox1 class="vent-margin-t-10">
+          <template #title>
+            <div>泵站远程集中控制</div>
+          </template>
+          <template #container>
+            <div class="top-btn">
+              <div class="btn-group">
+                <a-button class="btn-item" type="primary" @click="handlerFn('zfw')">总复位</a-button>
+                <a-button class="btn-item" type="default" disabled @click="handlerFn('change')">一键切换</a-button>
+              </div>
+              <div class="btn-group">
+                <a-button style="width: calc(100% - 16px); padding: 0 8px" type="primary" @click="openModal">瓦斯泵控制</a-button>
+              </div>
+              <div>
+                <div class="control-item">
+                  <div class="control-title">控制模式:</div>
+                  <div class="control-container">
+                    <a-radio-group v-model:value="selectData['ykjdqh']">
+                      <a-radio :value="'0'">就地</a-radio>
+                      <a-radio :value="'1'">远程</a-radio>
+                    </a-radio-group>
+                    <div class="btn-box">
+                      <div class="btn btn1" @click="changeCtr(0)">就地</div>
+                      <div class="btn btn1" @click="changeCtr(1)">远程</div>
+                    </div>
+                  </div>
+                </div>
+                <div class="control-item">
+                  <div class="control-title">检修模式:</div>
+                  <div class="control-container">
+                    <a-radio-group v-model:value="selectData['jxmsqh']">
+                      <a-radio :value="'0'">关闭</a-radio>
+                      <a-radio :value="'1'">开启</a-radio>
+                    </a-radio-group>
+                    <div class="btn-box">
+                      <div class="btn btn1" @click="changeMode(0)">关闭</div>
+                      <div class="btn btn1" @click="changeMode(1)">开启</div>
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </template>
+        </ventBox1>
+        <ventBox1 class="vent-margin-t-10">
+          <template #title>
+            <div>泵站监测详情</div>
+          </template>
+          <template #container>
+            <ListItem
+              v-for="(item, index) in modelMonitor"
+              :key="index"
+              class="w-100% mb-5px"
+              :value="selectData[item.code]"
+              :label="item.title"
+              label-width="250px"
+            />
+          </template>
+        </ventBox1>
+      </div>
+      <!-- <div class="item-box" >
+      <LivePlayer id="fm-player1" style="height: 250px;" ref="player1" :videoUrl="flvURL1()" muted live loading controls />
+    </div> -->
+    </div>
+    <div ref="playerRef" class="player-box"></div>
+  </div>
+  <DetailModal @register="register" :device-type="deviceType" :device-id="deviceId" />
+  <PasswordModal
+    :modal-is-show="passwordModalIsShow"
+    modal-title="密码检验"
+    :modal-type="handlerType"
+    @handle-ok="handleOK"
+    @handle-cancel="handleCancel"
+  />
+</template>
+
+<script setup lang="ts">
+  import { ref, onMounted, onUnmounted, reactive, defineProps, watch, inject, nextTick, onBeforeUnmount } from 'vue';
+  import ventBox1 from '/@/components/vent/ventBox1.vue';
+  import { setModelType, playAnimate } from '../gasPump.threejs';
+  import ListItem from '@/views/vent/gas/components/list/listItem.vue';
+  import {
+    stateWarningHeader,
+    valveWarningState,
+    pumpMonitorData,
+    waterPumpData,
+    dewateringPumpData,
+    modelMonitor,
+    getModelMonitorTags,
+    valveCtrlType,
+  } from '../gasPump.data';
+  import { list } from '../gasPump.api';
+  import { SvgIcon } from '/@/components/Icon';
+  import { formatNum } from '/@/utils/ventutil';
+  import DetailModal from './DetailModal.vue';
+  import { useModal } from '/@/components/Modal';
+  import { deviceControlApi } from '/@/api/vent/index';
+  import PasswordModal from '../../comment/components/PasswordModal.vue';
+  import { message } from 'ant-design-vue';
+  import fourBorderBg from '/@/components/vent/fourBorderBg.vue';
+  import { useCamera } from '/@/hooks/system/useCamera';
+
+  const globalConfig = inject('globalConfig');
+
+  const props = defineProps({
+    deviceId: {
+      type: String,
+      require: true,
+    },
+    deviceType: {
+      type: String,
+      require: true,
+    },
+  });
+  const [register, { openModal }] = useModal();
+  const modelMonitorTags = getModelMonitorTags();
+  const loading = ref(false);
+  const tabActiveKey = ref(1);
+  const passwordModalIsShow = ref(false);
+  const handlerType = ref('');
+  const playerRef = ref();
+
+  // 监测数据
+  const selectData = ref({
+    pump1: false,
+    pump2: false,
+    pump3: false,
+    pump4: false,
+    waterPump1: false,
+    waterPump2: false,
+    waterPump3: false,
+    waterPump4: false,
+    inValve1: false,
+    outValve1: false,
+    inValve2: false,
+    outValve2: false,
+    inValve3: false,
+    outValve3: false,
+    inValve4: false,
+    outValve4: false,
+    jxmsqh: '1',
+    ykjdqh: '1',
+    FlowSensor_InputFlux: '-',
+    deviceType: '',
+  });
+
+  const { getCamera, removeCamera } = useCamera();
+
+  // https获取监测数据
+  let timer: null | NodeJS.Timeout = null;
+  function getMonitor(flag?) {
+    if (Object.prototype.toString.call(timer) === '[object Null]') {
+      return new Promise((resolve) => {
+        timer = setTimeout(
+          async () => {
+            if (props.deviceId) {
+              const data = await getDataSource(props.deviceId);
+              selectData.value = data;
+              playAnimate(data);
+              // Object.assign(selectData, data);
+            }
+            if (timer) {
+              timer = null;
+            }
+            resolve(null);
+            await getMonitor();
+            loading.value = false;
+          },
+          flag ? 0 : 1000
+        );
+      });
+    }
+  }
+
+  async function getDataSource(systemID) {
+    const res = await list({ devicetype: props.deviceType, ids: systemID });
+    const result = res.msgTxt[0]['datalist'][0];
+    Object.assign(result, result['readData']);
+    return result;
+  }
+
+  function handler(passWord, paramcode) {
+    let value = '';
+    if (paramcode == 'ykjdqh') {
+      value = selectData.value['ykjdqh'] == '1' ? '2' : '1';
+    }
+    if (paramcode == 'jxmsqh') {
+      value = selectData.value['jxmsqh'] == '1' ? '2' : '1';
+    }
+    const data = {
+      deviceid: selectData.value['deviceID'],
+      devicetype: selectData.value['deviceType'],
+      paramcode: paramcode,
+      password: passWord,
+      value: value,
+    };
+    deviceControlApi(data)
+      .then((res) => {
+        if (globalConfig.History_Type == 'remote') {
+          message.success('指令已下发至生产管控平台成功!');
+        } else {
+          message.success('指令已下发成功!');
+        }
+      })
+      .catch((err) => {
+        message.success('控制异常');
+      });
+  }
+
+  function changeCtr(e) {
+    if (e == 1) {
+      // 就地
+      handlerType.value = 'jxmsqh';
+    } else if (e == 2) {
+      // 远程
+      handlerType.value = 'jxmsqh';
+    }
+    passwordModalIsShow.value = true;
+  }
+
+  function changeMode(e) {
+    if (e == 1) {
+      // 检修开
+      handlerType.value = 'ykjdqh';
+    } else if (e == 2) {
+      // 检修关
+      handlerType.value = 'ykjdqh';
+    }
+    passwordModalIsShow.value = true;
+  }
+
+  function handlerFn(paramcode) {
+    handlerType.value = paramcode;
+    passwordModalIsShow.value = true;
+  }
+
+  function handleOK(passWord, handlerState) {
+    handler(passWord, handlerState);
+    passwordModalIsShow.value = false;
+    handlerType.value = '';
+  }
+
+  function handleCancel() {
+    passwordModalIsShow.value = false;
+    handlerType.value = '';
+  }
+
+  // 喷粉操作
+  function handlerDevice(code, data) {}
+
+  watch(
+    () => props.deviceType,
+    () => {
+      removeCamera();
+      nextTick(async () => {
+        if (props.deviceType == 'pump_over') {
+          setModelType('gasPump');
+        } else if (props.deviceType?.startsWith('pump_under') || props.deviceType == 'pump_n12m2pq') {
+          setModelType('gasPumpUnder');
+        }
+      });
+    }
+  );
+  watch(
+    () => props.deviceId,
+    async (deviceID) => {
+      removeCamera();
+      if (deviceID) await getCamera(deviceID, playerRef.value);
+    }
+  );
+
+  onMounted(async () => {
+    timer = null;
+    await getMonitor(true);
+    // if (selectData && selectData['deviceID']) await getCamera(selectData['deviceID'], playerRef.value);
+  });
+
+  onBeforeUnmount(() => {
+    removeCamera();
+  });
+
+  onUnmounted(() => {
+    removeCamera();
+    if (timer) {
+      clearTimeout(timer);
+      timer = undefined;
+    }
+  });
+</script>
+<style lang="less" scoped>
+  @import '/@/design/theme.less';
+  @import '/@/design/vent/modal.less';
+  @import '../../comment/less/workFace.less';
+  @ventSpace: zxm;
+
+  .elementContent {
+    :deep(.main-container) {
+      display: flex;
+      flex-wrap: wrap;
+      width: 690px;
+      padding: 10px 12px 10px 15px;
+      border: 1px solid #d3e1ff33;
+      background-color: #061c2a55;
+      box-shadow: 0 0 15px #3b567f55;
+      background-color: #38383833;
+      .gas-monitor-row {
+        display: flex;
+        flex-direction: row;
+        flex-wrap: wrap;
+        color: #fff;
+        line-height: 32px;
+        .title {
+          width: 250px;
+          color: #baeaff;
+        }
+        .value {
+          width: 80px;
+          color: #efae05;
+        }
+      }
+    }
+  }
+  .modal-monitor-box {
+    background-color: #000;
+    color: #fff;
+    padding: 0 5px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    .title {
+      margin-right: 5px;
+    }
+    .signal-round {
+      margin-left: 5px;
+    }
+    .value {
+      width: 30px;
+      color: #efae05;
+    }
+  }
+  .device-state {
+    width: 100%;
+    position: absolute;
+    top: 20px;
+    color: #e90000;
+    display: flex;
+    justify-content: center;
+    font-size: 20px;
+  }
+
+  .lr {
+    margin-top: 0 !important;
+  }
+  .left-box {
+    width: 360px !important;
+    direction: rtl;
+    overflow-y: auto;
+    overflow-x: hidden;
+    height: calc(100% - 60px);
+    margin-top: 30px !important;
+
+    .left-container {
+      direction: ltr;
+    }
+  }
+  .right-box {
+    width: 350px !important;
+    overflow-y: auto;
+    overflow-x: hidden;
+    .environment-monitor {
+      .item {
+        flex: 1;
+        margin: 0 5px;
+        .title {
+          color: #7ae5ff;
+          text-align: center;
+          margin-bottom: 2px;
+        }
+        .num {
+          width: 100%;
+          height: 30px;
+          text-align: center;
+          border-top: 2px solid #50c8fc;
+          border-radius: 4px;
+          background-image: linear-gradient(#2e4d5955, #3780b499, #2e465955);
+        }
+      }
+    }
+    .pool-box {
+      width: 327px;
+      height: 65px;
+      padding: 0 5px;
+      background: url('/@/assets/images/vent/pump1.png') no-repeat;
+      background-size: cover;
+      background-origin: content-box;
+      margin-top: 2px;
+      .num {
+        color: aqua;
+      }
+      .center {
+        padding-right: 5px;
+      }
+    }
+  }
+  .player-box {
+    position: absolute;
+    height: 100%;
+    width: 100%;
+    padding: 0 20px 0 20px;
+    z-index: 9999;
+    display: flex;
+    align-items: end;
+    bottom: 80px;
+    :deep(#LivePlayerBox) {
+      display: flex;
+      justify-content: end;
+    }
+  }
+
+  .input-box {
+    width: calc(100%);
+    display: flex;
+    flex-direction: row !important;
+    flex-wrap: wrap !important;
+    .input-item {
+      width: calc(50% - 8px);
+      padding: 0 2px;
+
+      &:nth-child(2n) {
+        margin-left: 4px;
+      }
+    }
+  }
+  .btn-group {
+    display: flex;
+    justify-content: space-around;
+    .btn-item {
+      width: 82px;
+      text-align: center;
+    }
+  }
+  .top-btn {
+    .btn-group {
+      margin-bottom: 8px;
+      .btn-item {
+        width: calc(50% - 16px);
+        margin: 0 4px;
+      }
+    }
+    .control-item {
+      margin-left: 10px;
+      margin-bottom: 8px;
+      display: flex;
+      .control-title {
+        width: 80px;
+        color: var(--vent-font-action-link);
+      }
+      .control-container {
+        display: flex;
+      }
+    }
+  }
+  .btn-box {
+    display: flex;
+    .btn {
+      padding: 0 8px !important;
+      margin: 0 2px;
+    }
+  }
+  .state-header {
+    display: flex;
+    color: var(--vent-font-action-link);
+    .header-item {
+      width: 25%;
+      text-align: center;
+    }
+  }
+  .device-row {
+    display: flex;
+    margin-top: 10px;
+    .state {
+      width: 25%;
+      text-align: center;
+      font-size: 13px;
+    }
+  }
+
+  :deep(.@{ventSpace}-tabs-tabpane-active) {
+    overflow: auto;
+  }
+  :deep(.list-item__background) {
+    background-image: linear-gradient(to right, #39deff15, #3977e500) !important;
+    line-height: 30px !important;
+    height: 30px !important;
+  }
+</style>

+ 2 - 1
src/views/vent/monitorManager/gasPumpMonitor/gasPump.data.ts

@@ -519,7 +519,8 @@ export function getComponent() {
       gasPumpHome = defineAsyncComponent(() => import('./components/gasPumpHomeBD.vue'));
       return gasPumpHome;
     default:
-      gasPumpHome = defineAsyncComponent(() => import('./components/gasPumpHome.vue'));
+      // gasPumpHome = defineAsyncComponent(() => import('./components/gasPumpHome.vue'));
+       gasPumpHome = defineAsyncComponent(() => import('./components/gasPumpHomeCopy.vue'));
       return gasPumpHome;
   }
 }

+ 285 - 0
src/views/vent/monitorManager/gasPumpMonitor/index-copy.vue

@@ -0,0 +1,285 @@
+<template>
+  <div class="bg" style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; overflow: hidden">
+    <a-spin :spinning="loading" />
+    <div id="gasPump3D" v-show="activeKey == 'monitor'" style="width: 100%; height: 100%; position: absolute; overflow: hidden"> </div>
+    <div
+      id="gas3DCSS"
+      v-show="activeKey == 'monitor' && !loading && (currentDeviceType.startsWith('pump_under') || currentDeviceType == 'pump_n12m2pq')"
+      style="width: 100%; height: 100%; top: 0; left: 0; position: absolute; overflow: hidden; pointer-events: none"
+    >
+    </div>
+  </div>
+  <div class="scene-box">
+    <customHeader
+      :fieldNames="{ label: 'strinstallpos', value: 'deviceID', options: 'children' }"
+      :options="options"
+      @change="getSelectRow"
+      :optionValue="optionValue"
+      >瓦斯抽采泵站监测与管控</customHeader
+    >
+    <div class="center-container">
+      <gasPumpHome v-if="activeKey == 'monitor'" :deviceId="optionValue" :device-type="currentDeviceType" />
+      <div v-else class="history-group">
+        <div class="device-button-group" v-if="deviceList.length > 0">
+          <div
+            class="device-button"
+            :class="{ 'device-active': deviceActive == device.deviceType }"
+            v-for="(device, index) in deviceList"
+            :key="index"
+            @click="deviceChange(index)"
+            >{{ device.deviceName }}
+          </div>
+        </div>
+        <gasPumpHistory
+          v-if="activeKey == 'monitor_history'"
+          ref="historyTable"
+          class="vent-margin-t-20"
+          :device-type="currentDeviceType"
+          :device-id="optionValue"
+        />
+        <gasPumpHandleHistoryVue
+          v-if="activeKey == 'handler_history'"
+          ref="alarmHistoryTable"
+          class="vent-margin-t-20"
+          :deviceId="optionValue"
+          :device-type="currentDeviceType"
+        />
+        <gasPumpAlarmHistory
+          v-if="activeKey == 'faultRecord'"
+          ref="handlerHistoryTable"
+          class="vent-margin-t-20"
+          :deviceId="optionValue"
+          :device-type="currentDeviceType"
+        />
+      </div>
+    </div>
+    <BottomMenu @change="changeActive" />
+  </div>
+</template>
+
+<script setup lang="ts">
+  import customHeader from '/@/components/vent/customHeader.vue';
+  import { onBeforeMount, ref, onMounted, onUnmounted, reactive, toRaw } from 'vue';
+  import { list } from './gasPump.api';
+  import BottomMenu from '/@/views/vent/comment/components/bottomMenu.vue';
+  import { getComponent } from './gasPump.data';
+  import gasPumpHistory from './components/gasPumpHistory.vue';
+  import gasPumpHandleHistoryVue from './components/gasPumpHandleHistory.vue';
+  import gasPumpAlarmHistory from './components/gasPumpAlarmHistory.vue';
+  import { mountedThree, destroy, setModelType } from './gasPump.threejs';
+  import { useRouter } from 'vue-router';
+
+  type DeviceType = { deviceType: string; deviceName: string; datalist: any[] };
+  const gasPumpHome = getComponent();
+  const { currentRoute } = useRouter();
+  const activeKey = ref('monitor');
+  const loading = ref(false);
+
+  const historyTable = ref();
+  const alarmHistoryTable = ref();
+  const handlerHistoryTable = ref();
+
+  //关联设备
+  const deviceList = ref<DeviceType[]>([]);
+  const deviceActive = ref('');
+  const deviceType = ref('');
+
+  const options = ref();
+  // 默认初始是第一行
+  const selectRowIndex = ref(0);
+  const dataSource = ref([]);
+
+  const optionValue = ref('');
+  const currentDeviceType = ref('');
+
+  // 监测数据
+  const selectData = reactive({
+    FlowSensor_InputFlux: 0,
+  });
+
+  function changeActive(activeValue) {
+    if (activeKey.value == 'monitor') {
+      if (currentDeviceType.value == 'pump_over') {
+        setModelType('gasPump');
+      } else if (currentDeviceType.value.startsWith('pump_under')) {
+        setModelType('gasPumpUnder');
+      }
+    }
+    activeKey.value = activeValue;
+  }
+
+  function deviceChange(index) {
+    if (deviceList.value.length > 0) {
+      deviceActive.value = deviceType.value = deviceList.value[index].deviceType;
+    }
+  }
+
+  // 查询关联设备列表
+  async function getDeviceList() {
+    const res = await list({ devicetype: 'sys', systemID: optionValue.value });
+    const result = res.msgTxt;
+    const deviceArr = <DeviceType[]>[];
+    result.forEach((item) => {
+      const data = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      });
+      if (item.type != 'sys') {
+        deviceArr.unshift({
+          deviceType: item.type,
+          deviceName: item['typeName'] ? item['typeName'] : item['datalist'][0]['typeName'],
+          datalist: data,
+        });
+      }
+    });
+    deviceList.value = deviceArr;
+    if (deviceArr[0]) deviceActive.value = deviceArr[0].deviceType;
+  }
+
+  async function getSysDataSource() {
+    const res = await list({ devicetype: 'pump', pagetype: 'normal' });
+    dataSource.value = res.msgTxt[0].datalist || [];
+    dataSource.value.forEach((data: any) => {
+      const readData = data.readData;
+      data = Object.assign(data, readData);
+    });
+
+    if (!options.value) {
+      // 初始时选择第一条数据
+      options.value = dataSource.value;
+      if (!optionValue.value) {
+        optionValue.value = dataSource.value[0]['deviceID'];
+        Object.assign(selectData, dataSource.value[0]);
+        getSelectRow(optionValue.value);
+      } else {
+        const currentData = dataSource.value.find((item) => item['deviceID'] === optionValue.value) || {};
+        Object.assign(selectData, currentData);
+      }
+    }
+    const data: any = toRaw(dataSource.value[selectRowIndex.value]); //maxarea
+    return data;
+  }
+
+  // 切换检测数据
+  function getSelectRow(deviceID) {
+    const currentData = dataSource.value.find((item: any) => {
+      return item.deviceID == deviceID;
+    });
+    if (currentData) {
+      optionValue.value = currentData['deviceID'];
+      currentDeviceType.value = currentData['deviceType'];
+      Object.assign(selectData, currentData);
+      if (currentDeviceType.value == 'pump_over') {
+        setModelType('gasPump');
+      } else if (currentDeviceType.value.startsWith('pump_under')) {
+        setModelType('gasPumpUnder');
+      }
+    }
+  }
+
+  onMounted(async () => {
+    if (currentRoute.value && currentRoute.value['query'] && currentRoute.value['query']['id']) optionValue.value = currentRoute.value['query']['id'];
+    mountedThree().then(async () => {
+      await getSysDataSource();
+      await getDeviceList();
+      getSelectRow(optionValue.value);
+    });
+  });
+
+  onUnmounted(() => {
+    destroy();
+  });
+</script>
+<style lang="less" scoped>
+  @import '/@/design/vent/modal.less';
+  @ventSpace: zxm;
+  .scene-box {
+    pointer-events: none;
+    .history-group {
+      padding: 0 20px;
+      .history-container {
+        position: relative;
+        background: #6195af1a;
+        width: calc(100% + 10px);
+        top: 0px;
+        left: -10px;
+        border: 1px solid #00fffd22;
+        padding: 10px 0;
+        box-shadow: 0 0 20px #44b4ff33 inset;
+      }
+    }
+    .device-button-group {
+      // margin: 0 20px;
+      display: flex;
+      pointer-events: auto;
+      position: relative;
+      margin-top: 90px;
+      &::after {
+        position: absolute;
+        content: '';
+        width: calc(100% + 10px);
+        height: 2px;
+        top: 30px;
+        left: -10px;
+        border-bottom: 1px solid #0efcff;
+      }
+      .device-button {
+        padding: 4px 15px;
+        position: relative;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        font-size: 14px;
+
+        color: #fff;
+        cursor: pointer;
+        margin: 0 3px;
+
+        &::before {
+          content: '';
+          position: absolute;
+          top: 0;
+          right: 0;
+          bottom: 0;
+          left: 0;
+          border: 1px solid #6176af;
+          transform: skewX(-38deg);
+          background-color: rgba(0, 77, 103, 85%);
+          z-index: -1;
+        }
+      }
+      .device-active {
+        // color: #0efcff;
+        &::before {
+          border-color: #0efcff;
+          box-shadow: 1px 1px 3px 1px #0efcff inset;
+        }
+      }
+    }
+  }
+  .center-container {
+    width: 100%;
+    height: calc(100% - 100px);
+  }
+
+  :deep(.@{ventSpace}-tabs-tabpane-active) {
+    overflow: auto;
+  }
+
+  .input-box {
+    display: flex;
+    align-items: center;
+    padding-left: 10px;
+
+    .input-title {
+      color: #73e8fe;
+      width: auto;
+    }
+
+    .@{ventSpace}-input-number {
+      border-color: #ffffff88 !important;
+    }
+
+    margin-right: 10px;
+  }
+</style>