<script lang="ts" setup name="Layout"> import hotkeys from 'hotkeys-js' import NewHeader from './components/Header/index.vue' import MainSidebar from './components/MainSidebar/index.vue' import SubSidebar from './components/SubSidebar/index.vue' import Topbar from './components/Topbar/index.vue' import Search from './components/Search/index.vue' import AppSetting from './components/AppSetting/index.vue' import HotkeysIntro from './components/HotkeysIntro/index.vue' import useSettingsStore from '@/store/modules/settings' import useKeepAliveStore from '@/store/modules/keepAlive' import useMenuStore from '@/store/modules/menu' import {dataRecord, softwareStop} from "@/api/home/robot/robot"; import {ElMessage} from "element-plus"; import {getRobotList} from "@/api/home/robot/robot"; import {ref} from "vue"; import robotImg from '@/assets/images//机器人.png' import singalImg from '@/assets/images/robot/信号.png' import singalFullImg from '@/assets/images/robot/信号满.png' import alarmImg from '@/assets/images/robot/告警.png' import noAlarmImg from '@/assets/images/robot/没告警.png' import powerImg from '@/assets/images/robot/power.png' import useWebsocketStore from "@/store/modules/websocket"; import dayjs from "dayjs"; const routeInfo = useRoute() const settingsStore = useSettingsStore() const keepAliveStore = useKeepAliveStore() const menuStore = useMenuStore() const robotList = ref<any[]>([]) // 机器人 const robotIndex = ref<number>(0) const width = ref<any>('16px') const img1 = ref<any>('') const img2 = ref<any>('') const isStop = ref(false) function changeRobot(num: number) { robotIndex.value += num settingsStore.setRobot(robotList.value[robotIndex.value]) // socket重连 websocket.destroyWebSocket() websocket.initWebSocket() // 更新机器人急停信息 getRobotList({}).then((response) => { isStop.value = response.data.filter((item: { id: any }) => item.id === settingsStore.robot.id)[0].statusInfo.soft === 1 ? true : false }) } function getRobot() { getRobotList({}).then((response) => { robotList.value = response.data if(response.data.length !== 0) { if(localStorage.getItem('robot_id') === null) { settingsStore.setRobot(response.data[0]) } else if(!settingsStore.robot.hasOwnProperty('id')) { settingsStore.setRobot(response.data.filter((item: any) => item.id === localStorage.getItem('robot_id'))[0]) } if(settingsStore.robot.hasOwnProperty('id')) { response.data.forEach((item: any, index: number) => { if(item.id === settingsStore.robot.id) { robotIndex.value = index changeRobot(0) } }) } else { robotIndex.value = 0 changeRobot(0) } } }) } function stop() { softwareStop({ control: 1, robotId: settingsStore.robot.id, }).then((response) => { if (response.code === 200) { // 更新机器人信息 setTimeout(() => { getRobotList({}).then((response) => { isStop.value = response.data.filter((item: { id: any }) => item.id === settingsStore.robot.id)[0].statusInfo.soft === 1 ? true : false }) }, 2000) // if(response.data === 1) { // ElMessage.success('急停成功') // } else if(response.data === 0) { // ElMessage.error('急停失败') // } } }) } function run() { softwareStop({ control: 0, robotId: settingsStore.robot.id, }).then((response) => { if (response.code === 200) { // 更新机器人信息 setTimeout(() => { getRobotList({}).then((response) => { isStop.value = response.data.filter((item: { id: any }) => item.id === settingsStore.robot.id)[0].statusInfo.soft === 1 ? true : false }) }, 2000) // if(response.data === 1) { // ElMessage.success('启动成功') // } else if(response.data === 0) { // ElMessage.error('启动失败') // } } }) } watch(() => settingsStore.menu.subMenuCollapse, (val) => { if (settingsStore.mode === 'mobile') { if (!val) { document.body.classList.add('hidden') } else { document.body.classList.remove('hidden') } } }) watch(() => routeInfo.path, () => { if (settingsStore.mode === 'mobile') { settingsStore.$patch((state) => { state.menu.subMenuCollapse = true }) } }) const websocket = useWebsocketStore() onMounted(() => { getRobot() img1.value = singalFullImg img2.value = noAlarmImg hotkeys('f5', (e) => { if (settingsStore.toolbar.enablePageReload) { e.preventDefault() useMainPage().reload() } }) hotkeys('alt+`', (e) => { if (settingsStore.menu.enableHotkeys) { e.preventDefault() useMenu().switchTo(menuStore.actived + 1 < menuStore.allMenus.length ? menuStore.actived + 1 : 0) } }) }) onUnmounted(() => { hotkeys.unbind('f5') hotkeys.unbind('alt+`') websocket.destroyWebSocket() }) const router = useRouter() function clickAlarm() { img2.value = noAlarmImg router.push({ name: 'Alarm', }) } const unwatch = watch(websocket, (newVal) => { if (newVal.robotData && Object.keys(newVal.robotData).length >= 1 ) { newVal.robotData.connStatus === 1 ? img1.value = singalFullImg: img1.value = singalImg width.value = (Number(newVal.robotData.electricityQuantity) / 100 * 16) + 'px' } else if (newVal.alarmData && Object.keys(newVal.alarmData).length >= 1 ) { img2.value = alarmImg } }) onBeforeUnmount(() => { unwatch() }) </script> <template> <div class="layout"> <div id="app-main"> <new-header /> <div class="wrapper"> <div v-if="settingsStore.menu.menuMode !== 'top'" class="sidebar-container" :class="{ show: settingsStore.mode === 'mobile' && !settingsStore.menu.subMenuCollapse }"> <main-sidebar /> <sub-sidebar /> </div> <div v-if="settingsStore.menu.menuMode !== 'top'" class="sidebar-mask" :class="{ show: settingsStore.mode === 'mobile' && !settingsStore.menu.subMenuCollapse }" @click="settingsStore.toggleSidebarCollapse()" /> <div class="main-container" :style="{ 'padding-bottom': $route.meta.paddingBottom }"> <topbar v-if="!(settingsStore.menu.menuMode === 'head' && !settingsStore.menu.enableSubMenuCollapseButton && !settingsStore.breadcrumb.enable)" /> <div class="main"> <router-view v-slot="{ Component, route }"> <transition name="main" mode appear> <keep-alive :include="keepAliveStore.list"> <component :is="Component" :key="route.fullPath" /> </keep-alive> </transition> </router-view> </div> <!-- <copyright />--> </div> </div> <el-backtop :right="20" :bottom="20" title="回到顶部" /> <!-- 左侧红色按钮--> <div v-show="!settingsStore.subMenuCollapseLastStatus && !isStop" class="stop" @click="stop"/> <div v-show="!settingsStore.subMenuCollapseLastStatus && isStop" class="run" @click="run"/> <!-- 选择机器人--> <div class="select-robot"> <el-avatar shape="square" size="medium" :src="robotImg" style="background: #00000000"></el-avatar> <div style="margin-top: -6px;margin-left: -12px">{{settingsStore.robot?.robotName}}</div> <el-icon v-if="robotIndex>0" style="position: absolute;top: 10px;left: 60px;cursor: pointer" @click="changeRobot(-1)"> <svg-icon name="icon-up" /> </el-icon> <el-icon v-if="robotIndex<robotList.length-1" style="position: absolute;top: 30px;left: 60px;cursor: pointer" @click="changeRobot(1)"> <svg-icon name="icon-down" /> </el-icon> </div> <div class="current"> <el-image shape="square" size="small" :src="img1" style="width: 24px;height: 20px;margin-top: 4px"></el-image> <el-avatar shape="square" size="small" :src="img2" style="background: #00000000;margin: 0 15px;cursor: pointer" @click="clickAlarm()"></el-avatar> <el-image shape="square" size="small" :src="powerImg" style="width: 22px;height: 14px;margin-top: 5px;transform:rotateY(180deg);"></el-image> <div class="power" :style="{width}"/> </div> <copyright v-show="!settingsStore.subMenuCollapseLastStatus" class="copy"/> </div> <search /> <app-setting /> <hotkeys-intro /> </div> </template> <style lang="scss" scoped> .power { position: absolute; top: 7px; right: 101px; cursor: pointer; background-color: #1af72b; z-index: 99999999; height: 10px; border-radius: 1px; } [data-mode="mobile"] { .sidebar-container { transform: translateX(calc((var(--g-main-sidebar-width) + var(--g-sub-sidebar-width)) * -1)); &.show { transform: translateX(0); } } .main-container { margin-left: 0 !important; } &[data-menu-mode="single"] { .sidebar-container { transform: translateX(calc(var(--g-sub-sidebar-width) * -1)); &.show { transform: translateX(0); } } } } .layout { height: 100%; } #app-main { width: 100%; height: 100%; margin: 0 auto; transition: all 0.2s; } .current { position: absolute; top: 18px; right: 130px; width: 200px; height: 40px; z-index: 9999999; color: white; font-weight: bolder; font-size: 14px; display: flex; } .select-robot { position: absolute; top: 5px; left: 340px; width: 200px; height: 40px; z-index: 9999999; color: white; font-weight: bolder; font-size: 14px; } .stop { position: absolute; bottom: 35px; left: 42px; width: 96px; height: 96px; z-index: 111111111; background: url("@/assets/images/robot/急停.png") no-repeat right center; &:hover { background: url("@/assets/images/robot/急停按下.png") no-repeat right center; } } .run { position: absolute; bottom: 35px; left: 42px; width: 96px; height: 96px; z-index: 111111111; background: url("@/assets/images/robot/启动.png") no-repeat right center; &:hover { background: url("@/assets/images/robot/启动按下.png") no-repeat right center; } } .copy { position: absolute; bottom: 10px; left: 0px; z-index: 99999999999; } .wrapper { position: relative; width: 100%; height: 100%; box-shadow: -1px 0 0 0 var(--g-box-shadow-color); transition: padding-top 0.3s; .sidebar-container { position: fixed; z-index: 1010; top: 0; bottom: 0; display: flex; transition: transform 0.3s, top 0.3s; width: calc(var(--g-main-sidebar-actual-width) + var(--g-sub-sidebar-actual-width)); } .sidebar-mask { position: fixed; z-index: 1000; top: 0; left: 0; width: 100%; height: 100%; background-color: rgb(0 0 0 / 50%); backdrop-filter: blur(2px); transition: all 0.2s; transform: translateZ(0); opacity: 0; visibility: hidden; &.show { opacity: 1; visibility: visible; } } .main-sidebar-container:not(.main-sidebar-leave-active) + .sub-sidebar-container { left: var(--g-main-sidebar-width); } .main-container { display: flex; flex-direction: column; min-height: 100%; margin-left: calc(var(--g-main-sidebar-actual-width) + var(--g-sub-sidebar-actual-width)); background-color: var(--g-main-bg); transition: margin-left 0.3s, background-color 0.3s; .topbar-container { top: 0; z-index: 998; } .main { height: 100%; flex: auto; position: relative; // overflow: hidden; transition: 0.3s; } .topbar-container + .main { margin: var(--g-topbar-height) 0 0; } } } header:not(.header-leave-active) + .wrapper { padding-top: var(--g-header-height); .sidebar-container { top: var(--g-header-height); :deep(.sidebar-logo) { display: none; } :deep(.el-menu) { padding-top: 0; } } .main-container { .topbar-container { top: var(--g-header-height); :deep(.tools) { display: none; } } } } // 主内容区动画 .main-enter-active { transition: 0.2s; } .main-leave-active { transition: 0.15s; } .main-enter-from { opacity: 0; margin-left: -20px; } .main-leave-to { opacity: 0; margin-left: 20px; } </style>