Compare commits

...

1 Commits

Author SHA1 Message Date
e495dc6070 feat(chengdu): 更新结算界面添加准备状态和房间管理功能
- 添加玩家准备状态显示和切换功能
- 实现房主控制下一局开始的游戏流程
- 添加退出房间按钮和相关状态管理
- 集成准备状态的计算逻辑和UI展示
- 更新组件props传递准备和房间状态数据
- 重构结算界面按钮布局和交互逻辑
2026-04-07 13:36:28 +08:00
3 changed files with 77 additions and 23 deletions

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
defineProps<{ import { computed } from 'vue'
const props = defineProps<{
show: boolean show: boolean
isLastRound: boolean isLastRound: boolean
currentRound: number currentRound: number
@@ -10,16 +12,27 @@ defineProps<{
score: number score: number
isWinner: boolean isWinner: boolean
seatIndex: number seatIndex: number
isReady: boolean
}> }>
loggedInUserId: string loggedInUserId: string
nextRoundPending: boolean isRoomOwner: boolean
selfIsReady: boolean
readyTogglePending: boolean
startNextRoundPending: boolean
leaveRoomPending: boolean
settlementCountdown: number | null settlementCountdown: number | null
}>() }>()
const emit = defineEmits<{ const emit = defineEmits<{
nextRound: [] ready: []
startNextRound: []
exit: []
backHall: [] backHall: []
}>() }>()
const allPlayersReady = computed(() =>
props.settlementPlayers.length > 0 && props.settlementPlayers.every((p) => p.isReady),
)
</script> </script>
<template> <template>
@@ -44,29 +57,63 @@ const emit = defineEmits<{
<span class="settlement-score" :class="{ 'is-positive': item.score > 0, 'is-negative': item.score < 0 }"> <span class="settlement-score" :class="{ 'is-positive': item.score > 0, 'is-negative': item.score < 0 }">
{{ item.score > 0 ? '+' : '' }}{{ item.score }} {{ item.score > 0 ? '+' : '' }}{{ item.score }}
</span> </span>
<span class="settlement-ready-badge" :class="{ 'is-ready': item.isReady }">
{{ item.isReady ? '已准备' : '等待...' }}
</span>
</div> </div>
</div> </div>
<div class="settlement-actions"> <div class="settlement-actions">
<button <!-- 非末局准备按钮 + 房主开始游戏按钮 -->
v-if="!isLastRound" <template v-if="!isLastRound">
class="ready-toggle ready-toggle-inline settlement-btn" <button
type="button" class="ready-toggle ready-toggle-inline settlement-btn"
:disabled="nextRoundPending" :class="{ 'is-ready': selfIsReady }"
@click="emit('nextRound')" type="button"
> :disabled="selfIsReady || readyTogglePending"
<span class="ready-toggle-label"> @click="emit('ready')"
{{ >
nextRoundPending <span class="ready-toggle-label">
? '准备中...' {{
: settlementCountdown != null && settlementCountdown > 0 readyTogglePending
? `下一局 (${settlementCountdown}s)` ? '请求中...'
: '下一局' : selfIsReady
}} ? '已准备'
</span> : '准备'
</button> }}
</span>
</button>
<button
v-if="isRoomOwner"
class="ready-toggle ready-toggle-inline settlement-btn"
type="button"
:disabled="!allPlayersReady || startNextRoundPending"
@click="emit('startNextRound')"
>
<span class="ready-toggle-label">
{{
startNextRoundPending
? '开始中...'
: allPlayersReady
? '开始游戏'
: `开始游戏 (${settlementPlayers.filter((p) => p.isReady).length}/${settlementPlayers.length})`
}}
</span>
</button>
<p v-else-if="allPlayersReady" class="settlement-waiting-owner">等待房主开始...</p>
</template>
<!-- 末局返回大厅 -->
<button v-else class="ready-toggle ready-toggle-inline settlement-btn" type="button" @click="emit('backHall')"> <button v-else class="ready-toggle ready-toggle-inline settlement-btn" type="button" @click="emit('backHall')">
<span class="ready-toggle-label">返回大厅</span> <span class="ready-toggle-label">返回大厅</span>
</button> </button>
<!-- 退出按钮始终显示 -->
<button
class="ready-toggle ready-toggle-inline settlement-btn settlement-btn-exit"
type="button"
:disabled="leaveRoomPending"
@click="emit('exit')"
>
<span class="ready-toggle-label">{{ leaveRoomPending ? '退出中...' : '退出' }}</span>
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -41,11 +41,11 @@ const {
roomCountdown, roomCountdown,
leaveRoomPending, leaveRoomPending,
readyTogglePending, readyTogglePending,
nextRoundPending: startNextRoundPending,
dingQuePending, dingQuePending,
discardPending, discardPending,
claimActionPending, claimActionPending,
turnActionPending, turnActionPending,
nextRoundPending,
selectedDiscardTileId, selectedDiscardTileId,
menuOpen, menuOpen,
isTrustMode, isTrustMode,
@@ -263,9 +263,15 @@ function handleLeaveRoom(): void {
:total-rounds="gameStore.totalRounds" :total-rounds="gameStore.totalRounds"
:settlement-players="settlementPlayers" :settlement-players="settlementPlayers"
:logged-in-user-id="loggedInUserId" :logged-in-user-id="loggedInUserId"
:next-round-pending="nextRoundPending" :is-room-owner="isRoomOwner"
:self-is-ready="myReadyState"
:ready-toggle-pending="readyTogglePending"
:start-next-round-pending="startNextRoundPending"
:leave-room-pending="leaveRoomPending"
:settlement-countdown="settlementCountdown" :settlement-countdown="settlementCountdown"
@next-round="nextRound" @ready="toggleReadyState"
@start-next-round="nextRound"
@exit="backHall"
@back-hall="backHall" @back-hall="backHall"
/> />

View File

@@ -230,6 +230,7 @@ export function useChengduTableView(deps: TableViewDeps): TableViewResult {
score: deps.gameStore.scores[player.playerId] ?? 0, score: deps.gameStore.scores[player.playerId] ?? 0,
isWinner: winnerSet.has(player.playerId), isWinner: winnerSet.has(player.playerId),
seatIndex: player.seatIndex, seatIndex: player.seatIndex,
isReady: Boolean(player.isReady),
})) }))
.sort((a, b) => b.score - a.score) .sort((a, b) => b.score - a.score)
}) })