| | |
| | | <meta charset="UTF-8"> |
| | | <title>WCS控制中心</title> |
| | | <link rel="stylesheet" href="../../static/css/animate.min.css"> |
| | | <link rel="stylesheet" href="../../static/vue/element/element.css"> |
| | | <link rel="stylesheet" href="../../static/css/watch/console_vue.css"> |
| | | <link rel="stylesheet" href="../../static/vue/element/element.css"> |
| | | <style> |
| | | html, body, #app { |
| | | width: 100%; |
| | |
| | | margin: 0; |
| | | overflow: hidden; |
| | | } |
| | | body { |
| | | background: linear-gradient(180deg, #eef4f8 0%, #e7edf4 100%); |
| | | } |
| | | #app { |
| | | position: relative; |
| | | } |
| | | .monitor-shell { |
| | | position: relative; |
| | | width: 100%; |
| | | height: 100%; |
| | | overflow: hidden; |
| | | } |
| | | .monitor-map { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | .monitor-panel-wrap { |
| | | position: absolute; |
| | | top: 18px; |
| | | left: 18px; |
| | | bottom: 18px; |
| | | z-index: 40; |
| | | pointer-events: none; |
| | | } |
| | | .monitor-panel { |
| | | width: min(max(360px, 30vw), calc(100vw - 92px)); |
| | | max-width: calc(100vw - 92px); |
| | | height: calc(100vh - 36px); |
| | | display: flex; |
| | | flex-direction: column; |
| | | border-radius: 20px; |
| | | border: 1px solid rgba(255, 255, 255, 0.42); |
| | | background: rgba(248, 251, 253, 0.94); |
| | | box-shadow: 0 10px 24px rgba(88, 110, 136, 0.08); |
| | | overflow: hidden; |
| | | pointer-events: auto; |
| | | transform-origin: left center; |
| | | will-change: transform, opacity; |
| | | backface-visibility: hidden; |
| | | contain: layout paint style; |
| | | transition: transform .26s cubic-bezier(0.22, 1, 0.36, 1), opacity .2s ease, box-shadow .2s ease, border-color .2s ease; |
| | | } |
| | | .monitor-panel.is-collapsed { |
| | | opacity: 0; |
| | | transform: translate3d(calc(-100% - 14px), 0, 0); |
| | | border-color: transparent; |
| | | box-shadow: 0 6px 16px rgba(88, 110, 136, 0.02); |
| | | pointer-events: none; |
| | | } |
| | | .monitor-panel-header { |
| | | padding: 14px 16px 10px; |
| | | border-bottom: 1px solid rgba(226, 232, 240, 0.72); |
| | | background: rgba(255, 255, 255, 0.24); |
| | | } |
| | | .monitor-panel-title { |
| | | font-size: 15px; |
| | | font-weight: 600; |
| | | color: #243447; |
| | | line-height: 1.2; |
| | | } |
| | | .monitor-panel-desc { |
| | | margin-top: 4px; |
| | | font-size: 12px; |
| | | color: #6b7b8d; |
| | | } |
| | | .monitor-panel-body { |
| | | flex: 1; |
| | | min-height: 0; |
| | | padding: 12px; |
| | | overflow: hidden; |
| | | } |
| | | .monitor-panel-body { |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | } |
| | | .monitor-card-host { |
| | | flex: 1; |
| | | min-height: 0; |
| | | display: flex; |
| | | align-items: stretch; |
| | | width: 100%; |
| | | } |
| | | .wb-root { |
| | | position: relative; |
| | | flex: 1; |
| | | min-width: 0; |
| | | display: flex; |
| | | flex-direction: column; |
| | | height: 100%; |
| | | gap: 10px; |
| | | color: #395066; |
| | | } |
| | | .wb-main { |
| | | flex: 1; |
| | | min-height: 0; |
| | | display: flex; |
| | | gap: 10px; |
| | | } |
| | | .wb-side { |
| | | flex: 0 0 38%; |
| | | min-width: 220px; |
| | | max-width: 44%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | min-height: 0; |
| | | } |
| | | .wb-side-title { |
| | | font-size: 11px; |
| | | font-weight: 700; |
| | | letter-spacing: 0.06em; |
| | | text-transform: uppercase; |
| | | color: #7d8fa2; |
| | | margin-bottom: 8px; |
| | | } |
| | | .wb-list-card, |
| | | .wb-detail-panel { |
| | | min-height: 0; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | .wb-detail-panel { |
| | | flex: 1 1 62%; |
| | | min-width: 0; |
| | | } |
| | | .wb-tabs { |
| | | display: grid; |
| | | grid-template-columns: repeat(4, 1fr); |
| | | gap: 6px; |
| | | padding: 6px; |
| | | border-radius: 14px; |
| | | background: rgba(242, 246, 250, 0.78); |
| | | border: 1px solid rgba(224, 232, 239, 0.9); |
| | | } |
| | | .wb-tab { |
| | | height: 34px; |
| | | border: none; |
| | | border-radius: 10px; |
| | | background: transparent; |
| | | color: #73869b; |
| | | font-size: 12px; |
| | | font-weight: 600; |
| | | cursor: pointer; |
| | | transition: all .16s ease; |
| | | } |
| | | .wb-tab.is-active { |
| | | background: rgba(255, 255, 255, 0.92); |
| | | color: #24405c; |
| | | box-shadow: 0 8px 16px rgba(148, 163, 184, 0.08); |
| | | } |
| | | .wb-toolbar { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | .wb-toolbar-actions { |
| | | display: flex; |
| | | gap: 8px; |
| | | flex-shrink: 0; |
| | | } |
| | | .wb-input, |
| | | .wb-select { |
| | | width: 100%; |
| | | height: 36px; |
| | | padding: 0 12px; |
| | | border-radius: 10px; |
| | | border: 1px solid rgba(224, 232, 239, 0.96); |
| | | background: rgba(255, 255, 255, 0.76); |
| | | color: #334155; |
| | | box-sizing: border-box; |
| | | outline: none; |
| | | transition: border-color .16s ease, box-shadow .16s ease, background .16s ease; |
| | | } |
| | | .wb-input:focus, |
| | | .wb-select:focus { |
| | | border-color: rgba(128, 168, 208, 0.66); |
| | | box-shadow: 0 0 0 3px rgba(128, 168, 208, 0.1); |
| | | background: rgba(255, 255, 255, 0.92); |
| | | } |
| | | .wb-btn { |
| | | height: 36px; |
| | | padding: 0 14px; |
| | | border: none; |
| | | border-radius: 10px; |
| | | background: #6f95bd; |
| | | color: #fff; |
| | | font-size: 12px; |
| | | font-weight: 600; |
| | | cursor: pointer; |
| | | box-shadow: 0 6px 14px rgba(111, 149, 189, 0.18); |
| | | transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease, background .16s ease; |
| | | } |
| | | .wb-btn:hover { |
| | | transform: translateY(-1px); |
| | | } |
| | | .wb-btn-primary { |
| | | background: linear-gradient(135deg, #5e89b4 0%, #6f95bd 100%); |
| | | box-shadow: 0 10px 20px rgba(111, 149, 189, 0.22); |
| | | } |
| | | .wb-btn.wb-btn-ghost { |
| | | background: rgba(255, 255, 255, 0.76); |
| | | color: #4c6177; |
| | | border: 1px solid rgba(224, 232, 239, 0.96); |
| | | box-shadow: none; |
| | | } |
| | | .wb-btn.wb-btn-soft { |
| | | background: rgba(230, 237, 244, 0.92); |
| | | color: #4c6177; |
| | | border: 1px solid rgba(210, 221, 232, 0.98); |
| | | box-shadow: none; |
| | | } |
| | | .wb-control-card, |
| | | .wb-list-card, |
| | | .wb-detail { |
| | | border-radius: 16px; |
| | | border: 1px solid rgba(224, 232, 239, 0.92); |
| | | background: rgba(255, 255, 255, 0.62); |
| | | box-shadow: 0 8px 18px rgba(148, 163, 184, 0.06); |
| | | } |
| | | .wb-list-card { |
| | | flex: 1; |
| | | padding: 10px 8px 8px; |
| | | } |
| | | .wb-control-card { |
| | | padding: 14px; |
| | | background: linear-gradient(180deg, rgba(255, 255, 255, 0.82) 0%, rgba(246, 250, 253, 0.78) 100%); |
| | | overflow: auto; |
| | | } |
| | | .wb-control-subtitle { |
| | | margin-top: 8px; |
| | | margin-bottom: 10px; |
| | | font-size: 11px; |
| | | line-height: 1.45; |
| | | color: #6f8194; |
| | | } |
| | | .wb-control-target { |
| | | padding: 7px 9px; |
| | | border-radius: 12px; |
| | | background: rgba(234, 241, 247, 0.96); |
| | | border: 1px solid rgba(214, 224, 234, 0.96); |
| | | color: #43607c; |
| | | font-size: 11px; |
| | | font-weight: 700; |
| | | line-height: 1.4; |
| | | } |
| | | .wb-form-grid { |
| | | display: grid; |
| | | grid-template-columns: 1fr; |
| | | gap: 8px; |
| | | } |
| | | .wb-field { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 5px; |
| | | } |
| | | .wb-field-label { |
| | | font-size: 11px; |
| | | font-weight: 700; |
| | | letter-spacing: 0.02em; |
| | | color: #6d8197; |
| | | } |
| | | .wb-action-row { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 8px; |
| | | margin-top: 2px; |
| | | padding-top: 8px; |
| | | border-top: 1px dashed rgba(216, 226, 235, 0.92); |
| | | } |
| | | .wb-section-title { |
| | | font-size: 13px; |
| | | font-weight: 700; |
| | | color: #28425d; |
| | | margin-bottom: 10px; |
| | | } |
| | | .wb-list { |
| | | flex: 1; |
| | | min-height: 0; |
| | | padding: 6px; |
| | | overflow: auto; |
| | | } |
| | | .wb-list-item { |
| | | width: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: flex-start; |
| | | justify-content: flex-start; |
| | | gap: 7px; |
| | | padding: 10px; |
| | | margin-bottom: 8px; |
| | | border: 1px solid transparent; |
| | | border-radius: 12px; |
| | | background: rgba(248, 250, 252, 0.72); |
| | | cursor: pointer; |
| | | text-align: left; |
| | | color: inherit; |
| | | } |
| | | .wb-list-item:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | .wb-list-item.is-active { |
| | | border-color: rgba(135, 166, 198, 0.38); |
| | | background: rgba(236, 243, 249, 0.94); |
| | | } |
| | | .wb-list-main { |
| | | min-width: 0; |
| | | } |
| | | .wb-list-title { |
| | | font-size: 12px; |
| | | font-weight: 700; |
| | | color: #27425c; |
| | | line-height: 1.35; |
| | | } |
| | | .wb-list-meta { |
| | | margin-top: 4px; |
| | | font-size: 11px; |
| | | color: #7b8b9c; |
| | | line-height: 1.4; |
| | | display: -webkit-box; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | overflow: hidden; |
| | | } |
| | | .wb-badge { |
| | | flex-shrink: 0; |
| | | padding: 3px 8px; |
| | | border-radius: 999px; |
| | | font-size: 10px; |
| | | font-weight: 700; |
| | | } |
| | | .wb-badge.is-success { |
| | | background: rgba(82, 177, 126, 0.12); |
| | | color: #2d7650; |
| | | } |
| | | .wb-badge.is-working { |
| | | background: rgba(111, 149, 189, 0.12); |
| | | color: #3f6286; |
| | | } |
| | | .wb-badge.is-warning { |
| | | background: rgba(214, 162, 94, 0.14); |
| | | color: #9b6a24; |
| | | } |
| | | .wb-badge.is-danger { |
| | | background: rgba(207, 126, 120, 0.14); |
| | | color: #a14e4a; |
| | | } |
| | | .wb-badge.is-muted { |
| | | background: rgba(148, 163, 184, 0.14); |
| | | color: #748397; |
| | | } |
| | | .wb-empty { |
| | | padding: 28px 12px; |
| | | text-align: center; |
| | | color: #8b9aad; |
| | | font-size: 12px; |
| | | } |
| | | .wb-detail { |
| | | flex: 1; |
| | | min-height: 0; |
| | | padding: 12px; |
| | | overflow: auto; |
| | | } |
| | | .wb-detail-empty { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | .wb-detail-header { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | justify-content: space-between; |
| | | gap: 10px; |
| | | margin-bottom: 12px; |
| | | } |
| | | .wb-detail-subtitle { |
| | | margin-top: 4px; |
| | | font-size: 12px; |
| | | color: #7c8c9d; |
| | | } |
| | | .wb-detail-actions { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 8px; |
| | | } |
| | | .wb-link { |
| | | padding: 0; |
| | | border: none; |
| | | background: transparent; |
| | | color: #4677a4; |
| | | font-size: 12px; |
| | | cursor: pointer; |
| | | } |
| | | .wb-detail-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); |
| | | gap: 8px; |
| | | } |
| | | .wb-detail-cell { |
| | | padding: 10px 12px; |
| | | border-radius: 12px; |
| | | background: rgba(247, 250, 252, 0.86); |
| | | border: 1px solid rgba(233, 239, 244, 0.96); |
| | | } |
| | | .wb-detail-label { |
| | | font-size: 11px; |
| | | color: #8090a2; |
| | | } |
| | | .wb-detail-value { |
| | | margin-top: 5px; |
| | | font-size: 13px; |
| | | color: #31485f; |
| | | word-break: break-all; |
| | | } |
| | | .wb-notice { |
| | | position: absolute; |
| | | right: 18px; |
| | | bottom: 18px; |
| | | padding: 10px 14px; |
| | | border-radius: 12px; |
| | | font-size: 12px; |
| | | font-weight: 600; |
| | | color: #fff; |
| | | box-shadow: 0 12px 24px rgba(15, 23, 42, 0.12); |
| | | } |
| | | .wb-notice.is-success { |
| | | background: rgba(82, 177, 126, 0.92); |
| | | } |
| | | .wb-notice.is-warning { |
| | | background: rgba(214, 162, 94, 0.92); |
| | | } |
| | | .wb-notice.is-danger { |
| | | background: rgba(207, 126, 120, 0.92); |
| | | } |
| | | .floor-switch-button { |
| | | min-width: 44px; |
| | | height: 30px; |
| | | padding: 0 12px; |
| | | border: 1px solid rgba(185, 197, 210, 0.84); |
| | | border-radius: 999px; |
| | | background: rgba(255, 255, 255, 0.82); |
| | | color: #4b6177; |
| | | font-size: 12px; |
| | | font-weight: 700; |
| | | cursor: pointer; |
| | | } |
| | | .floor-switch-button.is-active { |
| | | border-color: rgba(111, 149, 189, 0.4); |
| | | background: rgba(236, 243, 249, 0.94); |
| | | color: #27425c; |
| | | } |
| | | .monitor-panel-toggle { |
| | | position: absolute; |
| | | left: 0; |
| | | top: 50%; |
| | | margin-left: 0; |
| | | transform: translateY(-50%); |
| | | width: 30px; |
| | | min-height: 108px; |
| | | padding: 10px 4px; |
| | | border: 1px solid rgba(148, 163, 184, 0.22); |
| | | border-left: none; |
| | | border-radius: 0 14px 14px 0; |
| | | background: rgba(255, 255, 255, 0.96); |
| | | color: #3e5974; |
| | | box-shadow: 0 8px 18px rgba(15, 23, 42, 0.08); |
| | | cursor: pointer; |
| | | pointer-events: auto; |
| | | display: inline-flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 10px; |
| | | font-size: 12px; |
| | | line-height: 1; |
| | | white-space: nowrap; |
| | | backface-visibility: hidden; |
| | | transition: left .26s cubic-bezier(0.22, 1, 0.36, 1), transform .26s cubic-bezier(0.22, 1, 0.36, 1), box-shadow .18s ease, background .18s ease; |
| | | } |
| | | .monitor-panel-toggle.is-panel-open { |
| | | left: calc(100% + 10px); |
| | | } |
| | | .monitor-panel-toggle i { |
| | | font-size: 14px; |
| | | } |
| | | .monitor-panel-toggle span { |
| | | writing-mode: vertical-rl; |
| | | text-orientation: mixed; |
| | | letter-spacing: 0.08em; |
| | | user-select: none; |
| | | } |
| | | </style> |
| | | <script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script> |
| | | <script type="text/javascript" src="../../static/layui/layui.js"></script> |
| | | <script type="text/javascript" src="../../static/js/handlebars/handlebars-v4.5.3.js"></script> |
| | | <script type="text/javascript" src="../../static/js/common.js"></script> |
| | | <script type="text/javascript" src="../../static/js/common.js"></script> |
| | | <script type="text/javascript" src="../../static/vue/js/vue.min.js"></script> |
| | | <script type="text/javascript" src="../../static/vue/element/element.js"></script> |
| | | <script src="../../static/js/gsap.min.js"></script> |
| | |
| | | </head> |
| | | <body> |
| | | <div id="app"> |
| | | <div style="display: flex;margin-left: 20px;"> |
| | | <div style="width: 20%;height: 60vh;margin-right: 20px;margin-top: 30px;"> |
| | | <el-tabs type="border-card" v-model="activateCard" @tab-click="handleCardClick"> |
| | | <el-tab-pane label="堆垛机" name="crn"> |
| | | <watch-crn-card ref="watchCrnCard" :param="crnParam"></watch-crn-card> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="双工位堆垛机" name="dualCrn"> |
| | | <watch-dual-crn-card ref="watchDualCrnCard" :param="dualCrnParam"></watch-dual-crn-card> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="输送站" name="devp"> |
| | | <devp-card ref="devpCard" :param="devpParam"></devp-card> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="RGV" name="rgv"> |
| | | <watch-rgv-card ref="watchRgvCard" :param="rgvParam"></watch-rgv-card> |
| | | </el-tab-pane> |
| | | <!-- <el-tab-pane label="地图配置" name="mapSetting"> |
| | | <map-setting-card :param="mapSettingParam"></map-setting-card> |
| | | </el-tab-pane> --> |
| | | </el-tabs> |
| | | </div> |
| | | <div class="monitor-shell" ref="monitorShell"> |
| | | <map-canvas :lev="currentLev" :lev-list="levList" :crn-param="crnParam" :rgv-param="rgvParam" :devp-param="devpParam" :station-task-range="stationTaskRange" :viewport-padding="mapViewportPadding" :hud-padding="mapHudPadding" @switch-lev="switchLev" @crn-click="openCrn" @dual-crn-click="openDualCrn" @station-click="openSite" @rgv-click="openRgv" class="monitor-map"></map-canvas> |
| | | |
| | | <map-canvas :lev="currentLev" :crn-param="crnParam" :rgv-param="rgvParam" :devp-param="devpParam" @crn-click="openCrn" @dual-crn-click="openDualCrn" @station-click="openSite" @rgv-click="openRgv" style="width: 80%; height: 100vh;"></map-canvas> |
| | | |
| | | <div style="position: absolute;top: 15px;left: 50%;display: flex;"> |
| | | <div v-if="levList.length > 1" v-for="(lev,index) in levList" :key="index" style="margin-right: 10px;"> |
| | | <el-button :type="currentLev == lev ? 'primary' : ''" @click="switchLev(lev)" size="mini">{{ lev }}F</el-button> |
| | | <div class="monitor-panel-wrap" ref="monitorPanelWrap"> |
| | | <div class="monitor-panel" ref="monitorPanel" :class="{ 'is-collapsed': panelCollapsed }"> |
| | | <div class="monitor-panel-header"> |
| | | <div class="monitor-panel-title">监控工作台</div> |
| | | <div class="monitor-panel-desc">围绕地图做操作,设备点击后自动切换到对应面板</div> |
| | | </div> |
| | | <div class="monitor-panel-body"> |
| | | <div class="wb-tabs" role="tablist"> |
| | | <button type="button" :class="['wb-tab', { 'is-active': activateCard === 'crn' }]" @click="handleWorkbenchTabChange('crn')">堆垛机</button> |
| | | <button type="button" :class="['wb-tab', { 'is-active': activateCard === 'dualCrn' }]" @click="handleWorkbenchTabChange('dualCrn')">双工位</button> |
| | | <button type="button" :class="['wb-tab', { 'is-active': activateCard === 'devp' }]" @click="handleWorkbenchTabChange('devp')">输送站</button> |
| | | <button type="button" :class="['wb-tab', { 'is-active': activateCard === 'rgv' }]" @click="handleWorkbenchTabChange('rgv')">RGV</button> |
| | | </div> |
| | | <div class="monitor-card-host"> |
| | | <watch-crn-card v-if="activateCard === 'crn'" ref="watchCrnCard" :param="crnParam" :items="crnStateList" :auto-refresh="false"></watch-crn-card> |
| | | <watch-dual-crn-card v-else-if="activateCard === 'dualCrn'" ref="watchDualCrnCard" :param="dualCrnParam" :items="dualCrnStateList" :auto-refresh="false"></watch-dual-crn-card> |
| | | <devp-card v-else-if="activateCard === 'devp'" ref="devpCard" :param="devpParam" :items="stationStateList" :auto-refresh="false"></devp-card> |
| | | <watch-rgv-card v-else ref="watchRgvCard" :param="rgvParam" :items="rgvStateList" :auto-refresh="false"></watch-rgv-card> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <button class="monitor-panel-toggle" :class="{ 'is-panel-open': !panelCollapsed }" ref="monitorToggle" @click="toggleMonitorPanel"> |
| | | <i>{{ panelCollapsed ? '>' : '<' }}</i> |
| | | <span>{{ panelCollapsed ? '展开面板' : '收起面板' }}</span> |
| | | </button> |
| | | </div> |
| | | </div> |
| | | |
| | | </div> |
| | | |
| | | <script src="../../components/MonitorCardKit.js"></script> |
| | | <script src="../../components/WatchCrnCard.js"></script> |
| | | <script src="../../components/WatchDualCrnCard.js"></script> |
| | | <script src="../../components/DevpCard.js"></script> |
| | | <script src="../../components/MapSettingCard.js"></script> |
| | | <script src="../../components/WatchRgvCard.js"></script> |
| | | <script src="../../components/MapCanvas.js"></script> |
| | | <script> |
| | |
| | | systemStatus: true,//系统运行状态 |
| | | consoleInterval: null,//定时器存储变量 |
| | | rgvPosition: [], |
| | | panelCollapsed: false, |
| | | mapViewportPadding: { |
| | | top: 0, |
| | | right: 0, |
| | | bottom: 0, |
| | | left: 0 |
| | | }, |
| | | mapHudPadding: { |
| | | left: 14 |
| | | }, |
| | | stationTaskRange: { |
| | | inbound: null, |
| | | outbound: null |
| | | }, |
| | | panelTransitionTimer: null, |
| | | panelPollTimer: null, |
| | | activateCard: 'crn', |
| | | crnParam: { |
| | | crnNo: 0 |
| | |
| | | dualCrnParam: { |
| | | crnNo: 0 |
| | | }, |
| | | mapSettingParam: { |
| | | zoom: 70 |
| | | }, |
| | | devpParam: { |
| | | stationId: 0 |
| | | }, |
| | | rgvParam: { |
| | | rgvNo: 0 |
| | | }, |
| | | crnStateList: [], |
| | | dualCrnStateList: [], |
| | | stationStateList: [], |
| | | rgvStateList: [], |
| | | locMastData: [],//库位数据 |
| | | wsReconnectTimer: null, |
| | | wsReconnectAttempts: 0, |
| | |
| | | this.init() |
| | | }, |
| | | mounted() { |
| | | this.$nextTick(() => { |
| | | this.updateMapViewportPadding(); |
| | | }); |
| | | window.addEventListener('resize', this.updateMapViewportPadding); |
| | | this.panelPollTimer = setInterval(() => { |
| | | this.refreshWorkbench(this.activateCard); |
| | | }, 1000); |
| | | }, |
| | | beforeDestroy() { |
| | | if (this.wsReconnectTimer) { clearTimeout(this.wsReconnectTimer); this.wsReconnectTimer = null; } |
| | | if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) { try { ws.close(); } catch (e) {} } |
| | | window.removeEventListener('resize', this.updateMapViewportPadding); |
| | | if (this.panelTransitionTimer) { clearTimeout(this.panelTransitionTimer); this.panelTransitionTimer = null; } |
| | | if (this.panelPollTimer) { clearInterval(this.panelPollTimer); this.panelPollTimer = null; } |
| | | }, |
| | | watch: { |
| | | |
| | |
| | | ws.send(data); |
| | | } |
| | | }, |
| | | webSocketOnOpen() { |
| | | console.log("WebSocket连接成功"); |
| | | if (this.wsReconnectTimer) { clearTimeout(this.wsReconnectTimer); this.wsReconnectTimer = null; } |
| | | this.wsReconnectAttempts = 0; |
| | | this.getMap(); |
| | | }, |
| | | webSocketOnOpen() { |
| | | console.log("WebSocket连接成功"); |
| | | if (this.wsReconnectTimer) { clearTimeout(this.wsReconnectTimer); this.wsReconnectTimer = null; } |
| | | this.wsReconnectAttempts = 0; |
| | | this.getMap(); |
| | | this.refreshWorkbench(this.activateCard); |
| | | }, |
| | | webSocketOnError() { |
| | | console.log("WebSocket连接发生错误"); |
| | | this.scheduleWsReconnect(); |
| | |
| | | console.log("WebSocket连接关闭"); |
| | | this.scheduleWsReconnect(); |
| | | }, |
| | | webSocketOnMessage(e) { |
| | | const result = JSON.parse(e.data); |
| | | if (result.url == "/crn/table/crn/state") { |
| | | if(this.$refs.watchCrnCard) { |
| | | this.$refs.watchCrnCard.setCrnList(JSON.parse(result.data)); |
| | | } |
| | | } else if (result.url == "/dualcrn/table/crn/state") { |
| | | if(this.$refs.watchDualCrnCard) { |
| | | this.$refs.watchDualCrnCard.setDualCrnList(JSON.parse(result.data)); |
| | | } |
| | | } else if (result.url == "/console/latest/data/station") { |
| | | if(this.$refs.devpCard) { |
| | | this.$refs.devpCard.setStationList(JSON.parse(result.data)); |
| | | } |
| | | } else if (result.url == "/rgv/table/rgv/state") { |
| | | if(this.$refs.watchRgvCard) { |
| | | this.$refs.watchRgvCard.setRgvList(JSON.parse(result.data)); |
| | | } |
| | | } else if (result.url == "/basMap/lev/" + this.currentLev + "/auth") { |
| | | // 地图数据 |
| | | let res = JSON.parse(result.data); |
| | | webSocketOnMessage(e) { |
| | | const result = JSON.parse(e.data); |
| | | if (result.url == "/crn/table/crn/state") { |
| | | const res = JSON.parse(result.data); |
| | | this.crnStateList = res && res.code === 200 ? (res.data || []) : []; |
| | | } else if (result.url == "/dualcrn/table/crn/state") { |
| | | const res = JSON.parse(result.data); |
| | | this.dualCrnStateList = res && res.code === 200 ? (res.data || []) : []; |
| | | } else if (result.url == "/console/latest/data/station") { |
| | | const res = JSON.parse(result.data); |
| | | this.stationStateList = res && res.code === 200 ? (res.data || []) : []; |
| | | } else if (result.url == "/rgv/table/rgv/state") { |
| | | const res = JSON.parse(result.data); |
| | | this.rgvStateList = res && res.code === 200 ? (res.data || []) : []; |
| | | } else if (result.url == "/basMap/lev/" + this.currentLev + "/auth") { |
| | | // 地图数据 |
| | | let res = JSON.parse(result.data); |
| | | if (res.code === 200) { |
| | | this.map = res.data; |
| | | } |
| | |
| | | |
| | | this.getSystemRunningStatus() //获取系统运行状态 |
| | | this.getLevList() //获取地图层级列表 |
| | | this.getStationTaskRange() // 获取入库/出库工作号范围 |
| | | this.getLocMastData() //获取库位数据 |
| | | }, |
| | | getStationTaskRange() { |
| | | this.fetchWrkLastnoRange(1, 'inbound'); |
| | | this.fetchWrkLastnoRange(101, 'outbound'); |
| | | }, |
| | | fetchWrkLastnoRange(id, key) { |
| | | $.ajax({ |
| | | url: baseUrl + "/wrkLastno/" + id + "/auth", |
| | | headers: { |
| | | 'token': localStorage.getItem('token') |
| | | }, |
| | | method: "get", |
| | | success: (res) => { |
| | | if (!res || res.code !== 200 || !res.data) { return; } |
| | | const data = res.data; |
| | | this.stationTaskRange = Object.assign({}, this.stationTaskRange, { |
| | | [key]: { |
| | | start: data.sNo, |
| | | end: data.eNo |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | }, |
| | | connectWs() { |
| | | if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) { return; } |
| | |
| | | this.currentLev = lev; |
| | | this.getMap() |
| | | this.getLocMastData() |
| | | this.refreshWorkbench(this.activateCard) |
| | | }, |
| | | handleWorkbenchTabChange(type) { |
| | | this.activateCard = type; |
| | | this.refreshWorkbench(type); |
| | | }, |
| | | refreshWorkbench(type) { |
| | | if (!type) { return; } |
| | | if (type === 'crn') { |
| | | this.sendWs(JSON.stringify({ url: "/crn/table/crn/state", data: {} })); |
| | | } else if (type === 'dualCrn') { |
| | | this.sendWs(JSON.stringify({ url: "/dualcrn/table/crn/state", data: {} })); |
| | | } else if (type === 'devp') { |
| | | this.sendWs(JSON.stringify({ url: "/console/latest/data/station", data: {} })); |
| | | } else if (type === 'rgv') { |
| | | this.sendWs(JSON.stringify({ url: "/rgv/table/rgv/state", data: {} })); |
| | | } |
| | | }, |
| | | updateMapViewportPadding() { |
| | | const shell = this.$refs.monitorShell; |
| | | const panelWrap = this.$refs.monitorPanelWrap; |
| | | if (!shell) { return; } |
| | | const shellRect = shell.getBoundingClientRect(); |
| | | let leftPadding = 0; |
| | | let hudLeft = 14; |
| | | if (!this.panelCollapsed && this.$refs.monitorPanel && panelWrap) { |
| | | const wrapRect = panelWrap.getBoundingClientRect(); |
| | | const panelWidth = this.$refs.monitorPanel.offsetWidth || this.$refs.monitorPanel.getBoundingClientRect().width || 0; |
| | | const panelLeft = Math.max(0, Math.ceil(wrapRect.left - shellRect.left)); |
| | | const panelBaseRight = panelLeft + Math.ceil(panelWidth); |
| | | const overlapCompensation = Math.min(56, panelWidth * 0.18); |
| | | leftPadding = Math.max(0, Math.ceil(panelBaseRight - overlapCompensation)); |
| | | hudLeft = Math.max(14, Math.ceil(panelBaseRight + 34)); |
| | | } else { |
| | | leftPadding = 0; |
| | | hudLeft = 14; |
| | | } |
| | | this.mapViewportPadding = { |
| | | top: 0, |
| | | right: 0, |
| | | bottom: 0, |
| | | left: leftPadding |
| | | }; |
| | | this.mapHudPadding = { |
| | | left: hudLeft |
| | | }; |
| | | }, |
| | | scheduleMapViewportPaddingUpdate(delay) { |
| | | if (this.panelTransitionTimer) { |
| | | clearTimeout(this.panelTransitionTimer); |
| | | this.panelTransitionTimer = null; |
| | | } |
| | | this.panelTransitionTimer = setTimeout(() => { |
| | | this.panelTransitionTimer = null; |
| | | this.updateMapViewportPadding(); |
| | | }, delay == null ? 0 : delay); |
| | | }, |
| | | toggleMonitorPanel() { |
| | | this.panelCollapsed = !this.panelCollapsed; |
| | | this.scheduleMapViewportPaddingUpdate(0); |
| | | }, |
| | | openCrn(id) { |
| | | this.panelCollapsed = false; |
| | | this.crnParam.crnNo = id; |
| | | this.activateCard = 'crn'; |
| | | this.scheduleMapViewportPaddingUpdate(0); |
| | | this.refreshWorkbench('crn'); |
| | | }, |
| | | openDualCrn(id) { |
| | | this.panelCollapsed = false; |
| | | this.dualCrnParam.crnNo = id; |
| | | this.activateCard = 'dualCrn'; |
| | | this.scheduleMapViewportPaddingUpdate(0); |
| | | this.refreshWorkbench('dualCrn'); |
| | | }, |
| | | openRgv(id) { |
| | | this.panelCollapsed = false; |
| | | this.rgvParam.rgvNo = id; |
| | | this.activateCard = 'rgv'; |
| | | this.scheduleMapViewportPaddingUpdate(0); |
| | | this.refreshWorkbench('rgv'); |
| | | }, |
| | | openSite(id) { |
| | | this.panelCollapsed = false; |
| | | this.devpParam.stationId = id; |
| | | this.activateCard = 'devp'; |
| | | this.scheduleMapViewportPaddingUpdate(0); |
| | | this.refreshWorkbench('devp'); |
| | | }, |
| | | systemSwitch() { |
| | | // 系统开关 |
| | | let that = this |
| | | if (this.systemStatus) { |
| | | this.$prompt('请输入口令,并停止WCS系统', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | }).then(({ |
| | | value |
| | | }) => { |
| | | that.doSwitch(0, value) |
| | | }).catch(() => { |
| | | |
| | | }); |
| | | const password = window.prompt('请输入口令,并停止WCS系统', ''); |
| | | if (password === null) { |
| | | return; |
| | | } |
| | | this.doSwitch(0, password); |
| | | } else { |
| | | this.doSwitch(1) |
| | | } |
| | | }, |
| | | showPageMessage(message, type) { |
| | | if (!message) { |
| | | return; |
| | | } |
| | | if (typeof this.$message === 'function') { |
| | | this.$message({ |
| | | message: message, |
| | | type: type || 'info' |
| | | }); |
| | | return; |
| | | } |
| | | if (window.ELEMENT && typeof window.ELEMENT.Message === 'function') { |
| | | window.ELEMENT.Message({ |
| | | message: message, |
| | | type: type || 'info' |
| | | }); |
| | | return; |
| | | } |
| | | if (window.layer && typeof window.layer.msg === 'function') { |
| | | const iconMap = { |
| | | success: 1, |
| | | error: 2, |
| | | warning: 0 |
| | | }; |
| | | window.layer.msg(message, { |
| | | icon: iconMap[type] != null ? iconMap[type] : 0, |
| | | time: 1800 |
| | | }); |
| | | return; |
| | | } |
| | | console[type === 'error' ? 'error' : 'log'](message); |
| | | }, |
| | | doSwitch(operatorType, password) { |
| | | let that = this |
| | |
| | | } else if (res.code === 403) { |
| | | parent.location.href = baseUrl + "/login"; |
| | | } else { |
| | | that.$message({ |
| | | message: res.msg, |
| | | type: 'error' |
| | | }); |
| | | that.showPageMessage(res.msg, 'error'); |
| | | } |
| | | } |
| | | }); |
| | |
| | | } else if (res.code === 403) { |
| | | parent.location.href = baseUrl + "/login"; |
| | | } else { |
| | | that.$message({ |
| | | message: res.msg, |
| | | type: 'error' |
| | | }); |
| | | that.showPageMessage(res.msg, 'error'); |
| | | } |
| | | } |
| | | }); |
| | |
| | | return false; |
| | | } |
| | | }, |
| | | handleCardClick(tab, event) { |
| | | |
| | | }, |
| | | //获取库位数据 |
| | | getLocMastData() { |
| | | let that = this; |
| | |
| | | return locInfo.row1 + '-' + locInfo.bay1; |
| | | } |
| | | return ''; |
| | | }, |
| | | } |
| | | }, |
| | | } |
| | | }) |
| | | </script> |
| | | </body> |