feat(game): 添加游戏房间菜单和托管功能
- 引入机器人和退出图标资源 - 实现游戏房间顶部菜单触发器和弹出菜单 - 添加托管模式切换功能 - 实现退出房间功能 - 添加全局点击和ESC键关闭菜单事件监听 - 优化菜单动画效果和交互反馈 - 移除侧边按钮区域的聊天、赞赏和开局按钮 - 调整时钟位置以适应新菜单布局
This commit is contained in:
@@ -5,6 +5,8 @@ import deskImage from '../assets/images/desk/desk_01.png'
|
||||
import wanIcon from '../assets/images/flowerClolor/wan.png'
|
||||
import tongIcon from '../assets/images/flowerClolor/tong.png'
|
||||
import tiaoIcon from '../assets/images/flowerClolor/tiao.png'
|
||||
import robotIcon from '../assets/images/icons/robot.svg'
|
||||
import exitIcon from '../assets/images/icons/exit.svg'
|
||||
import '../assets/styles/room.css'
|
||||
import topBackImage from '../assets/images/tiles/top/tbgs_2.png'
|
||||
import rightBackImage from '../assets/images/tiles/right/tbgs_1.png'
|
||||
@@ -42,6 +44,11 @@ const {
|
||||
|
||||
const now = ref(Date.now())
|
||||
let clockTimer: number | null = null
|
||||
const menuOpen = ref(false)
|
||||
const isTrustMode = ref(false)
|
||||
const menuTriggerActive = ref(false)
|
||||
let menuTriggerTimer: number | null = null
|
||||
let menuOpenTimer: number | null = null
|
||||
|
||||
const roomStatusText = computed(() => {
|
||||
if (roomState.value.status === 'playing') {
|
||||
@@ -220,10 +227,65 @@ function actionTheme(type: string): 'gold' | 'jade' | 'blue' {
|
||||
return 'blue'
|
||||
}
|
||||
|
||||
function toggleMenu(): void {
|
||||
menuTriggerActive.value = true
|
||||
if (menuTriggerTimer !== null) {
|
||||
window.clearTimeout(menuTriggerTimer)
|
||||
}
|
||||
menuTriggerTimer = window.setTimeout(() => {
|
||||
menuTriggerActive.value = false
|
||||
menuTriggerTimer = null
|
||||
}, 180)
|
||||
|
||||
if (menuOpen.value) {
|
||||
menuOpen.value = false
|
||||
return
|
||||
}
|
||||
|
||||
if (menuOpenTimer !== null) {
|
||||
window.clearTimeout(menuOpenTimer)
|
||||
}
|
||||
menuOpenTimer = window.setTimeout(() => {
|
||||
menuOpen.value = true
|
||||
menuOpenTimer = null
|
||||
}, 85)
|
||||
}
|
||||
|
||||
function toggleTrustMode(): void {
|
||||
isTrustMode.value = !isTrustMode.value
|
||||
menuOpen.value = false
|
||||
}
|
||||
|
||||
function handleLeaveRoom(): void {
|
||||
menuOpen.value = false
|
||||
backHall()
|
||||
}
|
||||
|
||||
function handleGlobalClick(event: MouseEvent): void {
|
||||
const target = event.target as HTMLElement | null
|
||||
if (!target) {
|
||||
return
|
||||
}
|
||||
|
||||
if (target.closest('.menu-trigger-wrap')) {
|
||||
return
|
||||
}
|
||||
|
||||
menuOpen.value = false
|
||||
}
|
||||
|
||||
function handleGlobalEsc(event: KeyboardEvent): void {
|
||||
if (event.key === 'Escape') {
|
||||
menuOpen.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
clockTimer = window.setInterval(() => {
|
||||
now.value = Date.now()
|
||||
}, 1000)
|
||||
window.addEventListener('click', handleGlobalClick)
|
||||
window.addEventListener('keydown', handleGlobalEsc)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@@ -231,6 +293,16 @@ onBeforeUnmount(() => {
|
||||
window.clearInterval(clockTimer)
|
||||
clockTimer = null
|
||||
}
|
||||
window.removeEventListener('click', handleGlobalClick)
|
||||
window.removeEventListener('keydown', handleGlobalEsc)
|
||||
if (menuTriggerTimer !== null) {
|
||||
window.clearTimeout(menuTriggerTimer)
|
||||
menuTriggerTimer = null
|
||||
}
|
||||
if (menuOpenTimer !== null) {
|
||||
window.clearTimeout(menuOpenTimer)
|
||||
menuOpenTimer = null
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -247,11 +319,45 @@ onBeforeUnmount(() => {
|
||||
<div class="inner-outline diamond"></div>
|
||||
|
||||
<div class="top-left-tools">
|
||||
<button class="metal-circle" type="button" :disabled="leaveRoomPending" @click="backHall">☰</button>
|
||||
<div class="menu-trigger-wrap">
|
||||
<button
|
||||
class="metal-circle menu-trigger"
|
||||
:class="{ 'is-feedback': menuTriggerActive }"
|
||||
type="button"
|
||||
:disabled="leaveRoomPending"
|
||||
@click.stop="toggleMenu"
|
||||
>
|
||||
<span class="menu-trigger-icon">☰</span>
|
||||
</button>
|
||||
<transition name="menu-pop">
|
||||
<div v-if="menuOpen" class="menu-popover" @click.stop>
|
||||
<div class="menu-list">
|
||||
<button class="menu-item menu-item-delay-1" type="button" @click="toggleTrustMode">
|
||||
<span class="menu-item-icon">
|
||||
<img :src="robotIcon" alt="" />
|
||||
</span>
|
||||
<span>{{ isTrustMode ? '取消托管' : '托管' }}</span>
|
||||
</button>
|
||||
<button
|
||||
class="menu-item menu-item-danger menu-item-delay-2"
|
||||
type="button"
|
||||
:disabled="leaveRoomPending"
|
||||
@click="handleLeaveRoom"
|
||||
>
|
||||
<span class="menu-item-icon">
|
||||
<img :src="exitIcon" alt="" />
|
||||
</span>
|
||||
<span>{{ leaveRoomPending ? '退出中...' : '退出' }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
<div class="left-counter">
|
||||
<span class="counter-light"></span>
|
||||
<strong>{{ roomState.game?.state?.wall.length ?? 48 }}</strong>
|
||||
</div>
|
||||
<span v-if="isTrustMode" class="trust-chip">托管中</span>
|
||||
</div>
|
||||
|
||||
<div class="top-right-clock">
|
||||
@@ -346,19 +452,6 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
<p v-else class="empty-hand">等待服务端下发 `my_hand`。</p>
|
||||
</div>
|
||||
|
||||
<div class="table-side-buttons">
|
||||
<button class="side-round" type="button" @click="connectWs">聊</button>
|
||||
<button class="side-round" type="button">赏</button>
|
||||
<button
|
||||
class="side-round gold"
|
||||
type="button"
|
||||
:disabled="!canStartGame || startGamePending"
|
||||
@click="sendStartGame"
|
||||
>
|
||||
{{ startGamePending ? '开局中' : '开局' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user