refactor(game): 重构游戏动作处理和WebSocket连接管理
- 重构sendGameAction函数参数结构,添加上下文支持 - 新增sendStartGame和sendLeaveRoom函数统一处理游戏开始和离开房间逻辑 - 移除路由相关依赖,简化ChengduGamePage组件 - 更新WebSocket客户端实现,添加状态变化订阅功能 - 移除requestId生成函数和相关参数,精简消息结构 - 优化座位玩家卡片数据模型,移除在线状态和金钱字段 - 整理游戏阶段常量定义,添加标签映射 - 移除过期的游戏状态字段如needDraw、lastDiscardTile等 - 添加座位类型定义和改进游戏类型文件组织结构
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import {computed, onBeforeUnmount, onMounted, ref} from 'vue'
|
||||
import {useRoute, useRouter} from 'vue-router'
|
||||
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'
|
||||
@@ -17,66 +16,30 @@ import RightPlayerCard from '../components/game/RightPlayerCard.vue'
|
||||
import BottomPlayerCard from '../components/game/BottomPlayerCard.vue'
|
||||
import LeftPlayerCard from '../components/game/LeftPlayerCard.vue'
|
||||
import type {SeatPlayerCardModel} from '../components/game/seat-player-card'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const {
|
||||
roomState,
|
||||
roomName,
|
||||
loggedInUserName,
|
||||
wsStatus,
|
||||
wsError,
|
||||
wsMessages,
|
||||
leaveRoomPending,
|
||||
seatViews,
|
||||
selectedTile,
|
||||
connectWs,
|
||||
selectTile,
|
||||
backHall,
|
||||
} = useChengduGameRoom(route, router)
|
||||
import type {WsStatus} from "../ws/client.ts";
|
||||
import {wsClient} from "../ws/client.ts";
|
||||
|
||||
const now = ref(Date.now())
|
||||
let clockTimer: number | null = null
|
||||
let unsubscribe: (() => void) | 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') {
|
||||
return '对局中'
|
||||
}
|
||||
if (roomState.value.status === 'finished') {
|
||||
return '已结束'
|
||||
}
|
||||
})
|
||||
|
||||
const currentPhaseText = computed(() => {
|
||||
const phase = roomState.value.game?.state?.phase?.trim()
|
||||
if (!phase) {
|
||||
return roomState.value.status === 'playing' ? '牌局进行中' : '未开局'
|
||||
}
|
||||
|
||||
const phaseLabelMap: Record<string, string> = {
|
||||
dealing: '发牌',
|
||||
discard: '出牌',
|
||||
action: '响应',
|
||||
settle: '结算',
|
||||
finished: '已结束',
|
||||
}
|
||||
|
||||
return phaseLabelMap[phase] ?? phase
|
||||
})
|
||||
|
||||
const networkLabel = computed(() => {
|
||||
if (wsStatus.value === 'connected') {
|
||||
return '已连接'
|
||||
const map: Record<string, string> = {
|
||||
connected: '已连接',
|
||||
connecting: '连接中',
|
||||
error: '连接异常',
|
||||
idle: '未连接',
|
||||
closed: '未连接',
|
||||
}
|
||||
if (wsStatus.value === 'connecting') {
|
||||
return '连接中'
|
||||
}
|
||||
return '未连接'
|
||||
|
||||
return map[wsStatus.value] ?? '未连接'
|
||||
})
|
||||
|
||||
const formattedClock = computed(() => {
|
||||
@@ -108,10 +71,8 @@ const seatDecor = computed<Record<SeatKey, SeatPlayerCardModel>>(() => {
|
||||
const emptySeat = (avatar: string): SeatPlayerCardModel => ({
|
||||
avatar,
|
||||
name: '空位',
|
||||
money: '--',
|
||||
dealer: false,
|
||||
isTurn: false,
|
||||
isOnline: false,
|
||||
missingSuitLabel: defaultMissingSuitLabel,
|
||||
})
|
||||
|
||||
@@ -233,25 +194,43 @@ function handleGlobalEsc(event: KeyboardEvent): void {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
const handler = (status: any) => {
|
||||
WsStatus.value = status
|
||||
}
|
||||
|
||||
// 保存取消订阅函数
|
||||
unsubscribe = wsClient.onStatusChange(handler)
|
||||
|
||||
clockTimer = window.setInterval(() => {
|
||||
now.value = Date.now()
|
||||
}, 1000)
|
||||
|
||||
window.addEventListener('click', handleGlobalClick)
|
||||
window.addEventListener('keydown', handleGlobalEsc)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
// 取消 ws 订阅
|
||||
if (unsubscribe) {
|
||||
unsubscribe()
|
||||
unsubscribe = null
|
||||
}
|
||||
|
||||
if (clockTimer !== null) {
|
||||
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
|
||||
@@ -273,11 +252,11 @@ onBeforeUnmount(() => {
|
||||
<div class="top-left-tools">
|
||||
<div class="menu-trigger-wrap">
|
||||
<button
|
||||
class="metal-circle menu-trigger"
|
||||
:class="{ 'is-feedback': menuTriggerActive }"
|
||||
type="button"
|
||||
:disabled="leaveRoomPending"
|
||||
@click.stop="toggleMenu"
|
||||
class="metal-circle menu-trigger"
|
||||
:class="{ 'is-feedback': menuTriggerActive }"
|
||||
type="button"
|
||||
:disabled="leaveRoomPending"
|
||||
@click.stop="toggleMenu"
|
||||
>
|
||||
<span class="menu-trigger-icon">☰</span>
|
||||
</button>
|
||||
@@ -286,18 +265,18 @@ onBeforeUnmount(() => {
|
||||
<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="" />
|
||||
<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"
|
||||
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="" />
|
||||
<img :src="exitIcon" alt=""/>
|
||||
</span>
|
||||
<span>{{ leaveRoomPending ? '退出中...' : '退出' }}</span>
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user