feat(game): 添加定缺功能支持
- 在游戏页面添加 dingQuePending 状态管理 - 实现 showDingQueChooser 计算属性控制定缺选择器显示 - 添加 chooseDingQue 函数处理定缺选择逻辑 - 集成 WebSocket 消息发送定缺选择结果 - 更新底部控制面板添加定缺选择按钮界面 - 添加相应的 CSS 样式支持定缺选择器布局和交互 - 修复房间状态更新时重置定缺待处理状态
This commit is contained in:
@@ -896,11 +896,57 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.bottom-action-bar {
|
.bottom-action-bar {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
min-height: 56px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ding-que-bar {
|
||||||
|
position: absolute;
|
||||||
|
right: 150px;
|
||||||
|
top: -90px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ding-que-button {
|
||||||
|
min-width: 64px;
|
||||||
|
height: 46px;
|
||||||
|
border: 1px solid rgba(220, 191, 118, 0.24);
|
||||||
|
border-radius: 999px;
|
||||||
|
color: #e5c472;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(14, 55, 40, 0.92), rgba(8, 36, 27, 0.96)),
|
||||||
|
radial-gradient(circle at 20% 24%, rgba(237, 214, 157, 0.08), transparent 34%);
|
||||||
|
box-shadow:
|
||||||
|
inset 0 1px 0 rgba(255, 244, 214, 0.1),
|
||||||
|
inset 0 -1px 0 rgba(0, 0, 0, 0.22),
|
||||||
|
0 8px 18px rgba(0, 0, 0, 0.2);
|
||||||
|
text-shadow:
|
||||||
|
-1px 0 rgba(0, 0, 0, 0.38),
|
||||||
|
0 1px rgba(0, 0, 0, 0.38),
|
||||||
|
1px 0 rgba(0, 0, 0, 0.38),
|
||||||
|
0 -1px rgba(0, 0, 0, 0.38);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ding-que-button:active {
|
||||||
|
transform: translateY(1px) scale(0.96);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ding-que-button:disabled {
|
||||||
|
opacity: 0.56;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
.control-copy {
|
.control-copy {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ const wsError = ref('')
|
|||||||
const leaveRoomPending = ref(false)
|
const leaveRoomPending = ref(false)
|
||||||
const readyTogglePending = ref(false)
|
const readyTogglePending = ref(false)
|
||||||
const startGamePending = ref(false)
|
const startGamePending = ref(false)
|
||||||
|
const dingQuePending = ref(false)
|
||||||
let clockTimer: number | null = null
|
let clockTimer: number | null = null
|
||||||
let unsubscribe: (() => void) | null = null
|
let unsubscribe: (() => void) | null = null
|
||||||
let pendingRoomInfoRequest = false
|
let pendingRoomInfoRequest = false
|
||||||
@@ -345,6 +346,19 @@ const showReadyToggle = computed(() => {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const showDingQueChooser = computed(() => {
|
||||||
|
const player = myPlayer.value
|
||||||
|
if (!player) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gameStore.phase === 'waiting' || gameStore.phase === 'settlement') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return player.handTiles.length > 0 && !player.missingSuit
|
||||||
|
})
|
||||||
|
|
||||||
function applyPlayerReadyState(playerId: string, ready: boolean): void {
|
function applyPlayerReadyState(playerId: string, ready: boolean): void {
|
||||||
const player = gameStore.players[playerId]
|
const player = gameStore.players[playerId]
|
||||||
if (player) {
|
if (player) {
|
||||||
@@ -796,6 +810,7 @@ function handleRoomInfoResponse(message: unknown): void {
|
|||||||
gameStore.roomId = roomId
|
gameStore.roomId = roomId
|
||||||
if (Object.keys(nextPlayers).length > 0) {
|
if (Object.keys(nextPlayers).length > 0) {
|
||||||
gameStore.players = nextPlayers
|
gameStore.players = nextPlayers
|
||||||
|
dingQuePending.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const phaseMap: Record<string, typeof gameStore.phase> = {
|
const phaseMap: Record<string, typeof gameStore.phase> = {
|
||||||
@@ -1115,6 +1130,7 @@ function handlePlayerHandResponse(message: unknown): void {
|
|||||||
existingPlayer.handTiles = handTiles
|
existingPlayer.handTiles = handTiles
|
||||||
existingPlayer.handCount = handTiles.length
|
existingPlayer.handCount = handTiles.length
|
||||||
}
|
}
|
||||||
|
dingQuePending.value = false
|
||||||
|
|
||||||
const room = activeRoom.value
|
const room = activeRoom.value
|
||||||
if (room && room.roomId === (roomId || gameStore.roomId)) {
|
if (room && room.roomId === (roomId || gameStore.roomId)) {
|
||||||
@@ -1455,6 +1471,21 @@ function startGame(): void {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function chooseDingQue(suit: Tile['suit']): void {
|
||||||
|
if (dingQuePending.value || !showDingQueChooser.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dingQuePending.value = true
|
||||||
|
sendWsMessage({
|
||||||
|
type: 'ding_que',
|
||||||
|
roomId: gameStore.roomId,
|
||||||
|
payload: {
|
||||||
|
suit,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function handleLeaveRoom(): void {
|
function handleLeaveRoom(): void {
|
||||||
menuOpen.value = false
|
menuOpen.value = false
|
||||||
backHall()
|
backHall()
|
||||||
@@ -1763,7 +1794,34 @@ onBeforeUnmount(() => {
|
|||||||
|
|
||||||
|
|
||||||
<div class="bottom-control-panel">
|
<div class="bottom-control-panel">
|
||||||
<div v-if="showReadyToggle || showStartGameButton" class="bottom-action-bar">
|
<div v-if="showDingQueChooser || showReadyToggle || showStartGameButton" class="bottom-action-bar">
|
||||||
|
<div v-if="showDingQueChooser" class="ding-que-bar">
|
||||||
|
<button
|
||||||
|
class="ding-que-button"
|
||||||
|
type="button"
|
||||||
|
:disabled="dingQuePending"
|
||||||
|
@click="chooseDingQue('W')"
|
||||||
|
>
|
||||||
|
万
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="ding-que-button"
|
||||||
|
type="button"
|
||||||
|
:disabled="dingQuePending"
|
||||||
|
@click="chooseDingQue('T')"
|
||||||
|
>
|
||||||
|
筒
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="ding-que-button"
|
||||||
|
type="button"
|
||||||
|
:disabled="dingQuePending"
|
||||||
|
@click="chooseDingQue('B')"
|
||||||
|
>
|
||||||
|
条
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
v-if="showReadyToggle"
|
v-if="showReadyToggle"
|
||||||
class="ready-toggle ready-toggle-inline"
|
class="ready-toggle ready-toggle-inline"
|
||||||
|
|||||||
Reference in New Issue
Block a user