修复bug,添加功能
This commit is contained in:
@@ -158,5 +158,9 @@ module.exports = {
|
||||
calibrationsuccessful: 'Calibration Successful',
|
||||
calibrationfailed: 'Calibration Failed',
|
||||
calibrationresultabnormal: 'Calibration Result Abnormal',
|
||||
calibrationprogramabnormal: 'Calibration Program Abnormal'
|
||||
calibrationprogramabnormal: 'Calibration Program Abnormal',
|
||||
service: 'Service',
|
||||
vehicle: ' Vehicle',
|
||||
scheduling: 'Scheduling',
|
||||
taskscurrentlynotcarried: 'There are tasks in progress currently, so mapping cannot be carried out.'
|
||||
}
|
||||
|
||||
@@ -158,5 +158,9 @@ module.exports = {
|
||||
calibrationsuccessful: '标定成功',
|
||||
calibrationfailed: '标定失败',
|
||||
calibrationresultabnormal: '标定结果异常',
|
||||
calibrationprogramabnormal: '标定程序异常'
|
||||
calibrationprogramabnormal: '标定程序异常',
|
||||
service: '服务',
|
||||
vehicle: '车辆',
|
||||
scheduling: '调度',
|
||||
taskscurrentlynotcarried: '当前有任务正在进行,不能建图'
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import store from './vuex/store'
|
||||
import './style/reset.css'
|
||||
import { Row, Col, Button, Icon, Dialog, Form, FormItem, Input, Select, Option, Table, TableColumn, Tabs, TabPane, Popover, Loading, MessageBox, Message, Progress, Upload, Menu, MenuItem } from 'element-ui'
|
||||
import 'element-ui/lib/theme-chalk/index.css'
|
||||
import './style/iconfont/iconfont.css'
|
||||
import './style/common.styl'
|
||||
import i18n from './i18n/i18n'
|
||||
import './config/rem.js'
|
||||
|
||||
@@ -234,7 +234,8 @@ export default {
|
||||
this.loading.close()
|
||||
this.$confirm(this.$t('Whetherdrivebackpoint'), this.$t('Prompt'), {
|
||||
confirmButtonText: this.$t('yes'),
|
||||
cancelButtonText: this.$t('no')
|
||||
cancelButtonText: this.$t('no'),
|
||||
closeOnClickModal: false
|
||||
}).then(() => {
|
||||
this._sendAutoBack('0')
|
||||
this.backActive = false
|
||||
@@ -567,6 +568,7 @@ export default {
|
||||
cancelButtonText: this.$t('Cancel')
|
||||
}).then(() => {
|
||||
this.tipShow = false
|
||||
this.recordPath = true
|
||||
}).catch(() => {})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,14 +19,14 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['userRole']),
|
||||
...mapGetters(['userRole', 'taskSeq']),
|
||||
nav () {
|
||||
return [
|
||||
{ title: '操作', zh_title: '操作', en_title: 'Operate', router: '/index/device', icon: 'RF1', isVisible: true },
|
||||
{ title: '建图', zh_title: '建图', en_title: 'Map - building', router: '/index/building', icon: 'RF2', isVisible: this.userRole === 1 },
|
||||
{ title: '地图', zh_title: '地图', en_title: 'Map', router: '/index/map', icon: 'RF3', isVisible: true },
|
||||
{ title: '重定位', zh_title: '重定位', en_title: 'Relocate', router: '/index/relocation', icon: 'RF4', isVisible: true },
|
||||
{ title: '一键标定', zh_title: '一键标定', en_title: 'One - Click Calibration', router: '/index/calibration', icon: 'RF7', isVisible: true }
|
||||
{ title: '一键标定', zh_title: '一键标定', en_title: 'One - Click Calibration', router: '/index/calibration', icon: 'RF7', isVisible: this.userRole === 1 }
|
||||
]
|
||||
},
|
||||
visibleNav () {
|
||||
@@ -36,6 +36,13 @@ export default {
|
||||
methods: {
|
||||
toPage (e) {
|
||||
if (e.router === '/index/building') {
|
||||
if (this.taskSeq) {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: '当前有任务正在进行,不能建图'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.$confirm(this.$t('Donewmap'), this.$t('Prompt'), {
|
||||
confirmButtonText: this.$t('Confirm'),
|
||||
cancelButtonText: this.$t('Cancel')
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</el-col>
|
||||
<el-col :span="20">
|
||||
<el-row type="flex" justify="end" align="middle">
|
||||
<div class="warn_image" :class="['warn_image_0', 'warn_image_1', 'warn_image_2'][topInfo.anomalyLevel]" @click="$router.push('/index/warning')"></div>
|
||||
<div class="warn_image" :class="['warn_image_0', 'warn_image_1', 'warn_image_2'][topInfo.anomalyLevel || 0]" @click="$router.push('/index/warning')"></div>
|
||||
<div v-if="JSON.stringify(topInfo) !== '{}'" class="state-item">{{ topInfo.isManual ? $t('ManualMode') : $t('AutomaticMode')}}</div>
|
||||
<div v-if="JSON.stringify(topInfo) !== '{}'" class="state-item">{{ topInfo.state }}</div>
|
||||
<div v-if="JSON.stringify(topInfo) !== '{}'" class="relative elec-qty-wrap" :class="{'elec-wraning': topInfo.batteryPower <= 40}">
|
||||
@@ -35,7 +35,7 @@
|
||||
<div class="absolute hud_left hud_right"></div>
|
||||
<router-view></router-view>
|
||||
</el-row>
|
||||
<div v-if="taskSeq.length > 0" class="task_wraper">
|
||||
<div v-if="taskSeq.length > 0" class="task_wraper" :key="taskSeq.join(',')">
|
||||
<div class="task_content">
|
||||
<div class="step_item" v-for="(e, i) in taskSeq" :key="i" :class="{'step_actived': i <= currentStep - 1, 'step_active': i === currentStep}">
|
||||
<div v-show="i !== 0" class="step_arrow"><img src="../../images/new/arrow.png"></div>
|
||||
@@ -45,20 +45,27 @@
|
||||
</div>
|
||||
<login-modal v-if="loginVisible" ref="loginModal"/>
|
||||
<config-modal v-if="configVisible" ref="configModal" @refreshWebsocket="refreshWebsocket"/>
|
||||
<div v-if="connectionError" class="custom-connection-error" :class="{'show': connectionError, 'hide': !connectionError}">
|
||||
<i class="el-icon-warning"></i>
|
||||
<span>{{ connectionErrorMessage }}</span>
|
||||
</div>
|
||||
<!-- websocket连接状态 -->
|
||||
<Websocket-status
|
||||
v-if="isConnecting"
|
||||
ref="WebsocketStatus"
|
||||
:isConnecting="isConnecting"
|
||||
:wsConnected="isConnected"
|
||||
:vehicleConnected="vehicleConnected"
|
||||
:rcsConnected="rcsConnected"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WebsocketStatus from './websocket-status.vue'
|
||||
import LoginModal from './login-modal.vue'
|
||||
import ConfigModal from './config-modal.vue'
|
||||
import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
name: 'ShellIndex',
|
||||
components: {
|
||||
WebsocketStatus,
|
||||
LoginModal,
|
||||
ConfigModal
|
||||
},
|
||||
@@ -66,8 +73,6 @@ export default {
|
||||
return {
|
||||
websocket: null, // WebSocket实例
|
||||
reconnectTimer: null, // 重连计时器
|
||||
connectionError: false,
|
||||
connectionErrorMessage: '',
|
||||
topInfo: {},
|
||||
// topInfo: {
|
||||
// batteryPower: -1.0,
|
||||
@@ -123,20 +128,36 @@ export default {
|
||||
taskSeq: [],
|
||||
currentStep: null,
|
||||
loginVisible: false,
|
||||
configVisible: false
|
||||
configVisible: false,
|
||||
isInitializing: false,
|
||||
isConnecting: false,
|
||||
isConnected: false,
|
||||
resizeTimer: null,
|
||||
vehicleConnected: false,
|
||||
rcsConnected: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['serverUrl', 'userRole']),
|
||||
exception () {
|
||||
let str = ''
|
||||
if (JSON.stringify(this.topInfo) !== '{}') {
|
||||
str = this.topInfo.errorData.map((item, index) => `${index + 1}.${item[this.$langPre.computedProp('error_name')]};`).join('')
|
||||
}
|
||||
return str
|
||||
if (JSON.stringify(this.topInfo) === '{}') return ''
|
||||
if (!Array.isArray(this.topInfo.errorData)) return ''
|
||||
return this.topInfo.errorData.map((item, index) => {
|
||||
const name = item[this.$langPre.computedProp('error_name')]
|
||||
return `${index + 1}.${name || ''};`
|
||||
}).join('')
|
||||
}
|
||||
},
|
||||
created () {
|
||||
watch: {
|
||||
exception(newVal) {
|
||||
if (newVal !== '') {
|
||||
this.$nextTick(() => {
|
||||
this.checkTextOverflow()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// this.$store.dispatch('setAgvObj', this.topInfo)
|
||||
// if (this.topInfo.task_seq) {
|
||||
// this.taskSeq = this.topInfo.task_seq.split(',')
|
||||
@@ -161,33 +182,33 @@ export default {
|
||||
// clearInterval(generatePointsInterval);
|
||||
// });
|
||||
this.initWebSocket()
|
||||
},
|
||||
mounted () {
|
||||
this.checkTextOverflow()
|
||||
window.addEventListener('resize', this.checkTextOverflow)
|
||||
window.addEventListener('resize', this.handleResize)
|
||||
},
|
||||
beforeDestroy () {
|
||||
window.removeEventListener('resize', this.checkTextOverflow)
|
||||
this.closeWebSocket() // 组件销毁时关闭连接
|
||||
window.removeEventListener('resize', this.handleResize)
|
||||
this.closeWebSocket()
|
||||
if (this.reconnectTimer) clearTimeout(this.reconnectTimer)
|
||||
if (this.$refs.scrollText) {
|
||||
this.$refs.scrollText.style.animation = 'none'
|
||||
}
|
||||
if (this.resizeTimer) clearTimeout(this.resizeTimer)
|
||||
},
|
||||
methods: {
|
||||
handleResize() {
|
||||
// 防抖处理,避免频繁触发
|
||||
if (this.resizeTimer) clearTimeout(this.resizeTimer)
|
||||
this.resizeTimer = setTimeout(() => {
|
||||
this.checkTextOverflow()
|
||||
}, 200)
|
||||
},
|
||||
refreshWebsocket () {
|
||||
this.closeWebSocket()
|
||||
if (this.reconnectTimer) clearTimeout(this.reconnectTimer)
|
||||
this.initWebSocket()
|
||||
},
|
||||
showConnectionError (message) {
|
||||
// 如果消息相同且已经显示,则不重复显示
|
||||
if (this.connectionErrorMessage === message && this.connectionError) {
|
||||
return
|
||||
if (this.reconnectTimer) {
|
||||
clearTimeout(this.reconnectTimer)
|
||||
this.reconnectTimer = null
|
||||
}
|
||||
this.connectionErrorMessage = message
|
||||
this.connectionError = true
|
||||
},
|
||||
hideConnectionError () {
|
||||
this.connectionError = false
|
||||
this.connectionErrorMessage = ''
|
||||
this.closeWebSocket()
|
||||
this.initWebSocket()
|
||||
},
|
||||
// 滚动区域
|
||||
checkTextOverflow () {
|
||||
@@ -221,49 +242,56 @@ export default {
|
||||
},
|
||||
// 初始化WebSocket连接
|
||||
initWebSocket () {
|
||||
this.loading = this.$loading({
|
||||
lock: true,
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.6)'
|
||||
})
|
||||
if (this.isInitializing) return
|
||||
this.isInitializing = true
|
||||
this.isConnecting = true
|
||||
|
||||
if (this.reconnectTimer) clearTimeout(this.reconnectTimer)
|
||||
const wsHost = this.serverUrl.replace(/^https?:\/\//, '')
|
||||
const lang = this.$i18n.locale.slice(0, 2)
|
||||
const wsUrl = `ws://${wsHost}/webSocket/VehicleInfo/${this.userRole}?lang=${lang}`
|
||||
this.closeWebSocket()
|
||||
this.websocket = new WebSocket(wsUrl)
|
||||
this.websocket.onopen = () => {}
|
||||
|
||||
try {
|
||||
this.websocket = new WebSocket(wsUrl)
|
||||
} catch (err) {
|
||||
console.error('WebSocket 创建失败:', err)
|
||||
this.isInitializing = false
|
||||
this.reconnectWebSocket()
|
||||
return
|
||||
}
|
||||
|
||||
this.websocket.onopen = () => {
|
||||
this.isConnected = true
|
||||
this.reconnectTimer && clearTimeout(this.reconnectTimer)
|
||||
this.isInitializing = false
|
||||
}
|
||||
|
||||
this.websocket.onmessage = (event) => {
|
||||
try {
|
||||
const res = JSON.parse(event.data)
|
||||
if (!res.data.rcsConnected && !res.data.vehicleConnected) {
|
||||
this.showConnectionError(this.$t('Dispatchvehiclenotconnected'))
|
||||
return
|
||||
}
|
||||
if (!res.data.rcsConnected && res.data.vehicleConnected) {
|
||||
this.showConnectionError(this.$t('Dispatchnotconnected'))
|
||||
return
|
||||
}
|
||||
if (!res.data.vehicleConnected && res.data.rcsConnected) {
|
||||
this.showConnectionError(this.$t('Vehiclenotconnected'))
|
||||
return
|
||||
}
|
||||
if (res.data.rcsConnected && res.data.vehicleConnected) {
|
||||
this.loading.close()
|
||||
this.hideConnectionError()
|
||||
if (res?.data?.vehicleConnected) this.vehicleConnected = res.data.vehicleConnected
|
||||
if (res?.data?.rcsConnected) this.rcsConnected = res.data.rcsConnected
|
||||
|
||||
if (res?.data?.vehicleConnected && res?.data?.rcsConnected) {
|
||||
this.isConnecting = false
|
||||
this.isConnected = false
|
||||
this.vehicleConnected = false
|
||||
this.rcsConnected = false
|
||||
this.handleWebSocketMessage(res)
|
||||
return
|
||||
}
|
||||
this.hideConnectionError()
|
||||
} catch (error) {
|
||||
console.error('WebSocket消息解析失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
this.websocket.onerror = (error) => {
|
||||
this.showConnectionError(this.$t('WebSocketerror') + ':', error)
|
||||
console.error('WebSocket 创建错误:', error)
|
||||
}
|
||||
|
||||
this.websocket.onclose = () => {
|
||||
this.loading.close()
|
||||
this.isInitializing = false
|
||||
this.topInfo = {}
|
||||
this.taskSeq = []
|
||||
this.currentStep = null
|
||||
@@ -271,19 +299,26 @@ export default {
|
||||
}
|
||||
},
|
||||
handleWebSocketMessage (res) {
|
||||
if (this.reconnectTimer) clearTimeout(this.reconnectTimer)
|
||||
this.topInfo = res.data
|
||||
if (this.topInfo.task_seq) {
|
||||
this.taskSeq = this.topInfo.task_seq.split(',')
|
||||
this.currentStep = this.topInfo.task_seq_index
|
||||
} else {
|
||||
this.taskSeq = []
|
||||
this.currentStep = null
|
||||
try {
|
||||
if (this.reconnectTimer) clearTimeout(this.reconnectTimer)
|
||||
this.topInfo = res.data
|
||||
if (this.topInfo.task_seq) {
|
||||
this.taskSeq = this.topInfo.task_seq.split(',')
|
||||
this.currentStep = this.topInfo.task_seq_index
|
||||
} else {
|
||||
this.taskSeq = []
|
||||
this.currentStep = null
|
||||
}
|
||||
if (this.$store && this.$store.dispatch) {
|
||||
this.$store.dispatch('setAgvObj', this.topInfo)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('处理消息出错', err)
|
||||
}
|
||||
this.$store.dispatch('setAgvObj', this.topInfo)
|
||||
},
|
||||
closeWebSocket () {
|
||||
if (this.websocket) {
|
||||
this.websocket.onclose = null
|
||||
this.websocket.close(1000, '正常关闭')
|
||||
this.websocket = null
|
||||
}
|
||||
@@ -291,9 +326,8 @@ export default {
|
||||
reconnectWebSocket () {
|
||||
if (this.reconnectTimer) clearTimeout(this.reconnectTimer)
|
||||
this.reconnectTimer = setTimeout(() => {
|
||||
this.showConnectionError(this.$t('AttreconnectWebSocket'))
|
||||
this.initWebSocket()
|
||||
}, 3000) // 3秒后重连
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -434,15 +468,17 @@ export default {
|
||||
border-color #fb8f00
|
||||
.step_arrow
|
||||
img
|
||||
top 2px
|
||||
left 0
|
||||
animation: moveRight 3s linear infinite;
|
||||
animation: moveRight 2s linear infinite;
|
||||
will-change: transform; /* 提示浏览器优化 */
|
||||
@keyframes moveRight {
|
||||
from {
|
||||
left: 0;
|
||||
}
|
||||
to {
|
||||
left: calc(100% + 11px);
|
||||
}
|
||||
0% { transform: translateX(0); }
|
||||
100% { transform: translateX(0.5rem); } /* 根据实际容器宽度调整 */
|
||||
}
|
||||
@keyframes scrollText {
|
||||
0% { transform: translateX(0); }
|
||||
100% { transform: translateX(-50%); } /* 根据实际滚动方向调整 */
|
||||
}
|
||||
.task_wraper-t
|
||||
_font(.2rem, .4rem, #fff, ,center)
|
||||
|
||||
392
src/pages/shells/websocket-status.vue
Normal file
392
src/pages/shells/websocket-status.vue
Normal file
@@ -0,0 +1,392 @@
|
||||
<template>
|
||||
<div class="show_modal">
|
||||
<div class="connection-content">
|
||||
<!-- 水平直线:左半部分 + 右半部分 -->
|
||||
<div class="line-wrapper" :class="{ 'animated': isConnecting && !wsConnected, 'full-bright': wsConnected }"></div>
|
||||
|
||||
<!-- 服务器图标 -->
|
||||
<div class="server-icon" :class="{ 'icon-active': wsConnected }">
|
||||
<i class="iconfont icon-fuwuqi"></i>
|
||||
<div class="icon-label">{{$t('service')}}</div>
|
||||
</div>
|
||||
|
||||
<!-- 服务器到分支点的水平线 -->
|
||||
<div class="line-wrapper line-wrapper2" :class="{ 'full-bright': isConnecting && wsConnected }"></div>
|
||||
|
||||
<!-- 分支区域:车辆(上)和调度(下) -->
|
||||
<div class="branches">
|
||||
<!-- 车辆分支 -->
|
||||
<div class="branch-item branch-vehicle">
|
||||
<div
|
||||
class="branch-line-vertical"
|
||||
:class="{
|
||||
'animate-vertical': vehicleAnimActive && vehicleAnimPhase === 'vertical',
|
||||
'full-bright': vehicleConnected || vehicleVerticalFull
|
||||
}"
|
||||
@animationend="handleVehicleVerticalEnd"
|
||||
></div>
|
||||
<div
|
||||
class="branch-line-horizontal"
|
||||
:class="{
|
||||
'animate-horizontal': vehicleAnimActive && vehicleAnimPhase === 'horizontal',
|
||||
'full-bright': vehicleConnected || vehicleHorizontalFull
|
||||
}"
|
||||
@animationend="handleVehicleHorizontalEnd"
|
||||
></div>
|
||||
<div class="branch-icon" :class="{ 'icon-active': vehicleConnected }">
|
||||
<i class="iconfont icon-robot"></i>
|
||||
<div class="icon-label">{{$t('vehicle')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 调度分支 -->
|
||||
<div class="branch-item branch-rcs">
|
||||
<div
|
||||
class="branch-line-vertical_2"
|
||||
:class="{
|
||||
'animate-vertical': rcsAnimActive && rcsAnimPhase === 'vertical',
|
||||
'full-bright': rcsConnected || rcsVerticalFull
|
||||
}"
|
||||
@animationend="handleRcsVerticalEnd"
|
||||
></div>
|
||||
<div
|
||||
class="branch-line-horizontal"
|
||||
:class="{
|
||||
'animate-horizontal': rcsAnimActive && rcsAnimPhase === 'horizontal',
|
||||
'full-bright': rcsConnected || rcsHorizontalFull
|
||||
}"
|
||||
@animationend="handleRcsHorizontalEnd"
|
||||
></div>
|
||||
<div class="branch-icon" :class="{ 'icon-active': rcsConnected }">
|
||||
<i class="iconfont icon-diaodu"></i>
|
||||
<div class="icon-label">{{$t('scheduling')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'WebSocketStatus',
|
||||
props: {
|
||||
isConnecting: { type: Boolean, default: false },
|
||||
wsConnected: { type: Boolean, default: false },
|
||||
vehicleConnected: { type: Boolean, default: false },
|
||||
rcsConnected: { type: Boolean, default: false }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
vehicleAnimPhase: 'vertical', // 'vertical' 或 'horizontal'
|
||||
vehicleAnimActive: false,
|
||||
vehicleVerticalFull: false,
|
||||
vehicleHorizontalFull: false,
|
||||
rcsAnimPhase: 'vertical',
|
||||
rcsAnimActive: false,
|
||||
rcsVerticalFull: false,
|
||||
rcsHorizontalFull: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
shouldAnimateVehicle() {
|
||||
return this.isConnecting && this.wsConnected && !this.vehicleConnected
|
||||
},
|
||||
shouldAnimateRcs() {
|
||||
return this.isConnecting && this.wsConnected && !this.rcsConnected
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
shouldAnimateVehicle: {
|
||||
handler(newVal) {
|
||||
if (newVal && !this.vehicleConnected) {
|
||||
// 启动动画序列,重置所有临时高亮标志
|
||||
this.vehicleVerticalFull = false
|
||||
this.vehicleHorizontalFull = false
|
||||
this.vehicleAnimActive = true
|
||||
this.vehicleAnimPhase = 'vertical'
|
||||
} else {
|
||||
// 停止动画,清除临时高亮
|
||||
this.vehicleAnimActive = false
|
||||
this.vehicleVerticalFull = false
|
||||
this.vehicleHorizontalFull = false
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
shouldAnimateRcs: {
|
||||
handler(newVal) {
|
||||
if (newVal && !this.rcsConnected) {
|
||||
this.rcsVerticalFull = false
|
||||
this.rcsHorizontalFull = false
|
||||
this.rcsAnimActive = true
|
||||
this.rcsAnimPhase = 'vertical'
|
||||
} else {
|
||||
this.rcsAnimActive = false
|
||||
this.rcsVerticalFull = false
|
||||
this.rcsHorizontalFull = false
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
vehicleConnected(val) {
|
||||
if (val) {
|
||||
// 连接成功时停止动画并清除临时高亮
|
||||
this.vehicleAnimActive = false
|
||||
this.vehicleVerticalFull = false
|
||||
this.vehicleHorizontalFull = false
|
||||
}
|
||||
},
|
||||
rcsConnected(val) {
|
||||
if (val) {
|
||||
this.rcsAnimActive = false
|
||||
this.rcsVerticalFull = false
|
||||
this.rcsHorizontalFull = false
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleVehicleVerticalEnd() {
|
||||
if (!this.vehicleAnimActive) return
|
||||
// 垂直动画结束:设置垂直线高亮,切换到水平动画
|
||||
this.vehicleVerticalFull = true
|
||||
this.vehicleAnimPhase = 'horizontal'
|
||||
},
|
||||
handleVehicleHorizontalEnd() {
|
||||
if (!this.vehicleAnimActive) return
|
||||
// 水平动画结束:设置水平线高亮
|
||||
this.vehicleHorizontalFull = true
|
||||
// 延迟重置(让高亮显示短暂时间后重置)
|
||||
setTimeout(() => {
|
||||
if (!this.vehicleAnimActive) return
|
||||
// 重置所有高亮,重新开始垂直动画
|
||||
this.vehicleVerticalFull = false
|
||||
this.vehicleHorizontalFull = false
|
||||
// 强制重新触发垂直动画:先清除phase再重新设置为vertical
|
||||
this.vehicleAnimPhase = ''
|
||||
this.$nextTick(() => {
|
||||
if (this.vehicleAnimActive) {
|
||||
this.vehicleAnimPhase = 'vertical'
|
||||
}
|
||||
})
|
||||
}, 100) // 延迟100ms,使视觉上能看到水平线完成后的全亮状态
|
||||
},
|
||||
handleRcsVerticalEnd() {
|
||||
if (!this.rcsAnimActive) return
|
||||
this.rcsVerticalFull = true
|
||||
this.rcsAnimPhase = 'horizontal'
|
||||
},
|
||||
handleRcsHorizontalEnd() {
|
||||
if (!this.rcsAnimActive) return
|
||||
this.rcsHorizontalFull = true
|
||||
setTimeout(() => {
|
||||
if (!this.rcsAnimActive) return
|
||||
this.rcsVerticalFull = false
|
||||
this.rcsHorizontalFull = false
|
||||
this.rcsAnimPhase = ''
|
||||
this.$nextTick(() => {
|
||||
if (this.rcsAnimActive) {
|
||||
this.rcsAnimPhase = 'vertical'
|
||||
}
|
||||
})
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.show_modal {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.9);
|
||||
z-index: 200;
|
||||
}
|
||||
.connection-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 直线区域 */
|
||||
.line-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 1.6rem;
|
||||
height: 0.04rem;
|
||||
background-color: #2c3e50;
|
||||
border-radius: 0.02rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 服务器图标 */
|
||||
.server-icon {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: #5a6e8a;
|
||||
transition: color 0.3s ease;
|
||||
margin: 0 .2rem;
|
||||
}
|
||||
.server-icon i {
|
||||
font-size: .8rem;
|
||||
line-height: .8rem;
|
||||
padding: .3rem;
|
||||
border-radius: 50%;
|
||||
background-color: #c0c4cc;
|
||||
}
|
||||
.server-icon.icon-active i {
|
||||
color: #fff;
|
||||
background-color: #00d0fc;
|
||||
}
|
||||
.icon-label {
|
||||
position: absolute;
|
||||
font-size: .26rem;
|
||||
bottom: -.4rem;
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
/* 分支区域 */
|
||||
.branches {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .6rem;
|
||||
}
|
||||
.branch-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
/* 水平线段 */
|
||||
.branch-line-horizontal {
|
||||
position: relative;
|
||||
width: 1rem;
|
||||
height: 0.04rem;
|
||||
background-color: #2c3e50;
|
||||
}
|
||||
/* 垂直线段 */
|
||||
.branch-line-vertical {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -.3rem;
|
||||
width: 0.04rem;
|
||||
height: calc(50% + .3rem);
|
||||
background-color: #2c3e50;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
.branch-line-vertical_2 {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: -.3rem;
|
||||
width: 0.04rem;
|
||||
height: calc(50% + .3rem);
|
||||
background-color: #2c3e50;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
/* 车辆分支垂直动画(单次,从下往上) */
|
||||
.branch-line-vertical.animate-vertical::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(0deg, #00d0fc 0%, #00d0fc 50%, #5a6e8a 50%, #5a6e8a 100%);
|
||||
background-size: 100% 200%;
|
||||
animation: progressMoveVertical 2s linear forwards;
|
||||
}
|
||||
/* 调度分支垂直动画(单次,从上往下,根据原样式保留) */
|
||||
.branch-line-vertical_2.animate-vertical::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(0deg, #5a6e8a 0%, #5a6e8a 50%, #00d0fc 50%, #00d0fc 100%);
|
||||
background-size: 100% 200%;
|
||||
animation: progressMoveUp 2s linear forwards;
|
||||
}
|
||||
/* 水平动画(单次,从左到右) */
|
||||
.branch-line-horizontal.animate-horizontal::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #00d0fc 0%, #00d0fc 50%, #5a6e8a 50%, #5a6e8a 100%);
|
||||
background-size: 200% 100%;
|
||||
animation: progressMove 2s linear forwards;
|
||||
}
|
||||
|
||||
/* 关键帧动画定义 */
|
||||
@keyframes progressMoveVertical {
|
||||
0% { background-position: 0 0%; }
|
||||
100% { background-position: 0 100%; }
|
||||
}
|
||||
@keyframes progressMoveUp {
|
||||
0% { background-position: 0 100%; }
|
||||
100% { background-position: 0 0%; }
|
||||
}
|
||||
@keyframes progressMove {
|
||||
0% { background-position: 100% 0; }
|
||||
100% { background-position: 0% 0; }
|
||||
}
|
||||
|
||||
/* 全亮状态(覆盖动画) */
|
||||
.line-wrapper.full-bright,
|
||||
.line-wrapper2.full-bright,
|
||||
.branch-line-vertical.full-bright,
|
||||
.branch-line-vertical_2.full-bright,
|
||||
.branch-line-horizontal.full-bright {
|
||||
background-color: #00d0fc;
|
||||
}
|
||||
.line-wrapper.full-bright::before,
|
||||
.line-wrapper2.full-bright::before,
|
||||
.branch-line-vertical.full-bright::before,
|
||||
.branch-line-vertical_2.full-bright::before,
|
||||
.branch-line-horizontal.full-bright::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 主水平线无限循环动画(保持原有效果) */
|
||||
.line-wrapper.animated::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #00d0fc 0%, #00d0fc 50%, #5a6e8a 50%, #5a6e8a 100%);
|
||||
background-size: 200% 100%;
|
||||
animation: progressMove 2s linear infinite;
|
||||
}
|
||||
|
||||
/* 车辆/调度图标 */
|
||||
.branch-icon {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: #5a6e8a;
|
||||
transition: color 0.3s ease;
|
||||
margin: 0 .2rem;
|
||||
}
|
||||
.branch-icon i {
|
||||
font-size: .8rem;
|
||||
line-height: .8rem;
|
||||
padding: .3rem;
|
||||
border-radius: 50%;
|
||||
background-color: #c0c4cc;
|
||||
}
|
||||
.branch-icon.icon-active i {
|
||||
color: #fff;
|
||||
background-color: #00d0fc;
|
||||
}
|
||||
</style>
|
||||
@@ -1,10 +1,4 @@
|
||||
@import 'mixin.styl'
|
||||
@font-face {
|
||||
font-family: 'iconfont';
|
||||
src: url('iconfont/iconfont.woff2?t=1631676179964') format('woff2'),
|
||||
url('iconfont/iconfont.woff?t=1631676179964') format('woff'),
|
||||
url('iconfont/iconfont.ttf?t=1631676179964') format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: "YouSheBiaoTiHei";
|
||||
src: url('font/YouSheBiaoTiHei.ttf') format('truetype');
|
||||
@@ -236,6 +230,8 @@
|
||||
.el-message-box__message p
|
||||
font-size .2rem
|
||||
line-height: .22rem
|
||||
.el-message-box__btns button:nth-child(2)
|
||||
margin-left 30px
|
||||
.el-progress-bar__inner,.el-progress-bar__outer
|
||||
border-radius 0
|
||||
.el-progress__text
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
.icon_dropdown
|
||||
&::before
|
||||
content: '\e65b'
|
||||
.icon_eyeopen
|
||||
&::before
|
||||
content: '\ee33'
|
||||
.icon_eyeclose
|
||||
&::before
|
||||
content: '\ee34'
|
||||
.icon_admin
|
||||
&::before
|
||||
content: '\e7a3'
|
||||
.icon_close
|
||||
color: #909399
|
||||
&::before
|
||||
content '\e659'
|
||||
.icon_radio
|
||||
position relative
|
||||
color #ffffff
|
||||
&::before
|
||||
content '\e608'
|
||||
31
src/style/iconfont/iconfont.css
Normal file
31
src/style/iconfont/iconfont.css
Normal file
@@ -0,0 +1,31 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 5093318 */
|
||||
src: url('iconfont.woff2?t=1776130387372') format('woff2'),
|
||||
url('iconfont.woff?t=1776130387372') format('woff'),
|
||||
url('iconfont.ttf?t=1776130387372') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-fuwuqi:before {
|
||||
content: "\e6a4";
|
||||
}
|
||||
|
||||
.icon-diaodu:before {
|
||||
content: "\e6ac";
|
||||
}
|
||||
|
||||
.icon-robot:before {
|
||||
content: "\e661";
|
||||
}
|
||||
|
||||
.icon-jiqiren:before {
|
||||
content: "\e613";
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -8,7 +8,8 @@ const state = {
|
||||
autoLoopEnable: '0',
|
||||
autoBackEnable: '',
|
||||
autoBackFinish: '',
|
||||
ready: ''
|
||||
ready: '',
|
||||
taskSeq: '',
|
||||
}
|
||||
|
||||
const getters = {
|
||||
@@ -19,7 +20,8 @@ const getters = {
|
||||
autoLoopEnable: state => state.autoLoopEnable,
|
||||
autoBackEnable: state => state.autoBackEnable,
|
||||
autoBackFinish: state => state.autoBackFinish,
|
||||
ready: state => state.ready
|
||||
ready: state => state.ready,
|
||||
taskSeq: state => state.taskSeq
|
||||
}
|
||||
|
||||
const actions = {
|
||||
@@ -57,6 +59,9 @@ const mutations = {
|
||||
if (Object.prototype.hasOwnProperty.call(data, 'ready')) {
|
||||
state.ready = data.ready
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(data, 'task_seq')) {
|
||||
state.taskSeq = data.task_seq
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user