|
|
|
|
@ -1,5 +1,5 @@
|
|
|
|
|
<template>
|
|
|
|
|
<div ref="dataScreen" class="data-screen" :class="{ 'display-screen': displayMode }">
|
|
|
|
|
<div ref="dataScreen" class="data-screen" :class="{ 'display-screen': displayMode, 'remote-active': displayRemoteActive }">
|
|
|
|
|
|
|
|
|
|
<!-- 标题 -->
|
|
|
|
|
<!-- 标题 -->
|
|
|
|
|
@ -256,7 +256,7 @@
|
|
|
|
|
{{ tab.label }}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<alumni-news :display-mode="displayMode" />
|
|
|
|
|
<alumni-news :display-mode="displayMode" :rotation-paused="displayRemoteActive" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
@ -279,6 +279,8 @@ export default {
|
|
|
|
|
return {
|
|
|
|
|
displayDataState: 'loading',
|
|
|
|
|
displayCourseRowStyle: null,
|
|
|
|
|
displayRemoteActive: false,
|
|
|
|
|
displayRemoteIdleTimer: null,
|
|
|
|
|
displayCourseTimer: null,
|
|
|
|
|
displayMapTimer: null,
|
|
|
|
|
isFullscreen: false,
|
|
|
|
|
@ -559,6 +561,7 @@ export default {
|
|
|
|
|
document.removeEventListener('fullscreenchange', this.onFullscreenChange)
|
|
|
|
|
document.removeEventListener('webkitfullscreenchange', this.onFullscreenChange)
|
|
|
|
|
document.removeEventListener('keydown', this.handleDisplayKeydown, true)
|
|
|
|
|
clearTimeout(this.displayRemoteIdleTimer)
|
|
|
|
|
clearInterval(this.displayCourseTimer)
|
|
|
|
|
clearInterval(this.displayMapTimer)
|
|
|
|
|
}
|
|
|
|
|
@ -621,6 +624,20 @@ export default {
|
|
|
|
|
const button = this.$refs.fullscreenButton || screen.querySelector('.year-button.active, .map-tabs .active')
|
|
|
|
|
if (button) button.focus()
|
|
|
|
|
},
|
|
|
|
|
registerDisplayRemoteActivity() {
|
|
|
|
|
this.displayRemoteActive = true
|
|
|
|
|
clearTimeout(this.displayRemoteIdleTimer)
|
|
|
|
|
this.displayRemoteIdleTimer = setTimeout(() => {
|
|
|
|
|
this.displayRemoteActive = false
|
|
|
|
|
this.startDisplayCourseRotation()
|
|
|
|
|
this.startDisplayMapRotation()
|
|
|
|
|
this.startCourseRotation()
|
|
|
|
|
this.startCourseSystemRotation()
|
|
|
|
|
this.startRankingRotation()
|
|
|
|
|
if (this.mapType === 'national') this.startNationalRankingRotation()
|
|
|
|
|
this.scrollToActiveButton()
|
|
|
|
|
}, 60000)
|
|
|
|
|
},
|
|
|
|
|
handleDisplayKeydown(event) {
|
|
|
|
|
const screen = this.$refs.dataScreen
|
|
|
|
|
const focused = document.activeElement
|
|
|
|
|
@ -629,15 +646,20 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
const legacyKeys = { 37: 'ArrowLeft', 38: 'ArrowUp', 39: 'ArrowRight', 40: 'ArrowDown' }
|
|
|
|
|
const direction = directions[event.key] || directions[legacyKeys[event.keyCode]]
|
|
|
|
|
if (['Enter', 'OK', 'Select'].includes(event.key) || event.keyCode === 13 || event.keyCode === 23) {
|
|
|
|
|
const confirm = ['Enter', 'OK', 'Select'].includes(event.key) || event.keyCode === 13 || event.keyCode === 23
|
|
|
|
|
if (!direction && !confirm) return
|
|
|
|
|
this.registerDisplayRemoteActivity()
|
|
|
|
|
|
|
|
|
|
if (confirm) {
|
|
|
|
|
if (screen.contains(focused) && focused.tagName === 'BUTTON') {
|
|
|
|
|
event.preventDefault()
|
|
|
|
|
event.stopPropagation()
|
|
|
|
|
if (!event.repeat) focused.click()
|
|
|
|
|
} else {
|
|
|
|
|
this.focusDisplayControl()
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (!direction) return
|
|
|
|
|
|
|
|
|
|
event.preventDefault()
|
|
|
|
|
event.stopPropagation()
|
|
|
|
|
@ -669,6 +691,7 @@ export default {
|
|
|
|
|
clearInterval(this.displayCourseTimer)
|
|
|
|
|
if (this.yearConfigs.length <= 1) return
|
|
|
|
|
this.displayCourseTimer = setInterval(() => {
|
|
|
|
|
if (this.displayRemoteActive) return
|
|
|
|
|
this.switchYear((this.currentYearIndex + 1) % this.yearConfigs.length)
|
|
|
|
|
}, 12000)
|
|
|
|
|
},
|
|
|
|
|
@ -679,6 +702,7 @@ export default {
|
|
|
|
|
startDisplayMapRotation() {
|
|
|
|
|
clearInterval(this.displayMapTimer)
|
|
|
|
|
this.displayMapTimer = setInterval(() => {
|
|
|
|
|
if (this.displayRemoteActive) return
|
|
|
|
|
this.mapType = this.mapType === 'suzhou' ? 'national' : 'suzhou'
|
|
|
|
|
}, 12000)
|
|
|
|
|
},
|
|
|
|
|
@ -957,7 +981,7 @@ export default {
|
|
|
|
|
if (!body || !this.currentCourseTypes.length) return
|
|
|
|
|
const available = body.getBoundingClientRect().height
|
|
|
|
|
if (!available) return
|
|
|
|
|
const rowHeight = Math.min(window.innerHeight * 0.03, available / this.currentCourseTypes.length)
|
|
|
|
|
const rowHeight = Math.min(window.innerHeight * 0.042, available / this.currentCourseTypes.length)
|
|
|
|
|
this.displayCourseRowStyle = {
|
|
|
|
|
'--display-course-row-height': `${rowHeight}px`,
|
|
|
|
|
'--display-course-font-size': `${Math.min(window.innerWidth * 0.01, rowHeight * 0.72)}px`
|
|
|
|
|
@ -1079,6 +1103,7 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
if (!this.rankingPages.length || this.rankingPages.length <= 1) return
|
|
|
|
|
this.rankingTimer = setInterval(() => {
|
|
|
|
|
if (this.displayRemoteActive) return
|
|
|
|
|
this.rankingPageIndex = (this.rankingPageIndex + 1) % this.rankingPages.length
|
|
|
|
|
}, 5000)
|
|
|
|
|
},
|
|
|
|
|
@ -1090,6 +1115,7 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
if (!this.nationalRankingPages.length || this.nationalRankingPages.length <= 1) return
|
|
|
|
|
this.nationalRankingTimer = setInterval(() => {
|
|
|
|
|
if (this.displayRemoteActive) return
|
|
|
|
|
this.nationalRankingPageIndex = (this.nationalRankingPageIndex + 1) % this.nationalRankingPages.length
|
|
|
|
|
}, 5000)
|
|
|
|
|
},
|
|
|
|
|
@ -1099,6 +1125,7 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
if (!this.courseGroups.length) return
|
|
|
|
|
this.courseTimer = setInterval(() => {
|
|
|
|
|
if (this.displayRemoteActive) return
|
|
|
|
|
this.courseGroupIndex = (this.courseGroupIndex + 1) % this.courseGroups.length
|
|
|
|
|
}, 5000)
|
|
|
|
|
},
|
|
|
|
|
@ -1108,6 +1135,7 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
if (!this.courseSystemPages.length || this.courseSystemPages.length <= 1) return
|
|
|
|
|
this.courseSystemTimer = setInterval(() => {
|
|
|
|
|
if (this.displayRemoteActive) return
|
|
|
|
|
this.courseSystemPageIndex = (this.courseSystemPageIndex + 1) % this.courseSystemPages.length
|
|
|
|
|
}, 3000)
|
|
|
|
|
},
|
|
|
|
|
@ -1126,7 +1154,7 @@ export default {
|
|
|
|
|
scrollToActiveButton() {
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
const buttonsContainer = this.$refs.yearButtons
|
|
|
|
|
if (!buttonsContainer || (this.displayMode && buttonsContainer.contains(document.activeElement))) return
|
|
|
|
|
if (!buttonsContainer || (this.displayRemoteActive && buttonsContainer.contains(document.activeElement))) return
|
|
|
|
|
|
|
|
|
|
// 通过查询选择器找到激活的按钮
|
|
|
|
|
const activeButton = buttonsContainer.querySelector('.year-button.active')
|
|
|
|
|
@ -2285,8 +2313,24 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
::v-deep button:focus {
|
|
|
|
|
outline: 2px solid #ffe3a1;
|
|
|
|
|
outline-offset: -2px;
|
|
|
|
|
outline: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.map-tabs .tab { transition: none; }
|
|
|
|
|
|
|
|
|
|
&.remote-active {
|
|
|
|
|
::v-deep button:focus {
|
|
|
|
|
outline: 2px solid #ffe3a1;
|
|
|
|
|
outline-offset: -2px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.map-tabs .tab:focus {
|
|
|
|
|
position: relative;
|
|
|
|
|
z-index: 1;
|
|
|
|
|
outline: none;
|
|
|
|
|
color: #ffe3a1;
|
|
|
|
|
filter: drop-shadow(0 0 3px #ffe3a1) drop-shadow(0 0 1px #ffe3a1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.course-system-container .table-cell {
|
|
|
|
|
@ -2316,12 +2360,6 @@ export default {
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.display-controls button:focus,
|
|
|
|
|
.display-status button:focus {
|
|
|
|
|
outline: 2px solid #f4dcae;
|
|
|
|
|
outline-offset: 3px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.display-message {
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: 100%;
|
|
|
|
|
|