Files
hx123666/scoring/pages/single-room/index.vue
2025-11-11 18:39:32 +08:00

671 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="single-room">
<!-- 顶部导航栏 -->
<view class="nav-bar">
<view class="nav-back" @click="goBack">
<uni-icons type="arrowleft" size="24" color="#fff"></uni-icons>
</view>
<view class="nav-title">单人 - {{ roomId }}房间</view>
<view class="nav-actions">
<uni-icons type="more" size="24" color="#fff" @click="showMoreOptions"></uni-icons>
</view>
</view>
<!-- 功能栏 -->
<view class="function-bar">
<view class="function-item" @click="openAddPlayerPopup">
<uni-icons type="plus" size="20" color="#fff"></uni-icons>
<text>添加玩家</text>
</view>
<view class="function-item" @click="transferScorer">
<uni-icons type="exchange" size="20" color="#fff"></uni-icons>
<text>转让计分员</text>
</view>
<view class="function-item">
<switch :checked="voiceEnabled" @change="toggleVoice" color="#4CAF50"></switch>
<text>语音播报</text>
</view>
<view class="function-item">
<switch :checked="boardEnabled" @change="toggleBoard" color="#4CAF50"></switch>
<text>台板</text>
</view>
</view>
<!-- 对局记录区域 -->
<view class="record-section">
<view class="record-title">对局记录</view>
<view class="record-tip">点击对局分数进行修改</view>
<view class="record-tip">点击自己头像编辑用户头像和昵称~</view>
</view>
<!-- 玩家列表 -->
<view class="player-list">
<view class="player-item">
<view class="player-label">玩家 ({{ players.length }})</view>
<view class="player-info-container">
<view class="player-info" v-for="(player, index) in players" :key="player.id">
<image class="player-avatar" :src="player.avatar" mode="aspectFit"></image>
<text class="player-name">{{ player.name }}</text>
<view v-if="player.isSelf" class="self-tag">自己</view>
</view>
</view>
</view>
<view class="player-item">
<view class="player-label">总分</view>
<view class="player-score">{{ totalScore }}</view>
</view>
</view>
<!-- 底部操作按钮 -->
<view class="action-buttons">
<button class="start-btn" @click="startScoring">开局计分</button>
<button class="settle-btn" @click="openSettlePopup">结算房间</button>
</view>
<!-- 添加玩家弹窗 -->
<view v-if="showAddPlayerPopup" class="popup-mask" @click="closeAddPlayerPopup">
<view class="popup-content" @click.stop>
<view class="popup-header">
<view class="popup-title">扫码加入房间</view>
<view class="popup-close" @click="closeAddPlayerPopup">
<uni-icons type="close" size="24" color="#999"></uni-icons>
</view>
</view>
<view class="popup-body">
<view class="popup-tip">邀请好友扫描下方二维码加入房间</view>
<view class="qrcode-container">
<image class="qrcode" src="https://tse2-mm.cn.bing.net/th/id/OIP-C.Pbhgd_vCFFNQWXi7y-HynAAAAA?w=209&h=209&c=7&r=0&o=7&cb=ucfimgc2&dpr=1.5&pid=1.7&rm=3" mode="aspectFit"></image>
</view>
<view class="popup-buttons">
<button class="share-btn" @click="shareRoom">分享给好友邀请加入房间</button>
<button class="add-virtual-btn" @click="addVirtualPlayer">手动添加虚拟玩家</button>
</view>
<view class="popup-footer">
<view class="footer-tip">点击自己头像编辑用户头像和昵称~</view>
</view>
</view>
</view>
</view>
<!-- 结算房间弹窗 -->
<view v-if="showSettlePopup" class="popup-mask" @click="closeSettlePopup">
<view class="settle-popup-content" @click.stop>
<view class="settle-popup-body">
<view class="settle-tip">输入倍率快速结算</view>
<view class="rate-input-section">
<input
class="rate-input"
type="number"
placeholder="请输入倍率"
v-model="rateValue"
focus
/>
</view>
<view class="settle-popup-buttons">
<button class="cancel-btn" @click="closeSettlePopup">取消</button>
<button class="confirm-btn" @click="confirmSettlement">确定</button>
</view>
</view>
</view>
</view>
<!-- 转让计分员弹窗 -->
<view v-if="showTransferPopup" class="popup-mask" @click="closeTransferPopup">
<view class="transfer-popup-content" @click.stop>
<view class="transfer-popup-body">
<view class="transfer-tip">房间内暂无扫码或分享加入房间的玩家无法转让计分员</view>
<view class="transfer-popup-buttons">
<button class="confirm-btn" @click="closeTransferPopup">确定</button>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue'
// 房间数据
const roomId = ref('15198520')
const voiceEnabled = ref(false)
const boardEnabled = ref(false)
// 玩家数据
const players = ref([
{
id: 1,
name: '玩家80061',
avatar: 'https://ts1.tc.mm.bing.net/th/id/OIP-C.QQG4bvcAR3CJ0WeQULA9UQAAAA?w=275&h=211&c=8&rs=1&qlt=90&o=6&cb=ucfimgc1&dpr=1.5&pid=3.1&rm=2',
score: 0,
isSelf: true
}
])
// 弹窗显示状态
const showAddPlayerPopup = ref(false)
const showSettlePopup = ref(false)
const showTransferPopup = ref(false)
const rateValue = ref('')
// 计算总分 - 使用普通函数替代 computed
const totalScore = ref(0)
// 更新总分函数
const updateTotalScore = () => {
totalScore.value = players.value.reduce((sum, player) => sum + player.score, 0)
}
// 组件挂载后初始化
onMounted(() => {
console.log('组件已挂载')
updateTotalScore()
})
// 返回上一页
const goBack = () => {
uni.navigateBack()
}
// 显示更多选项
const showMoreOptions = () => {
uni.showActionSheet({
itemList: ['添加到我的小程序', '分享房间', '设置'],
success: (res) => {
if (res.tapIndex === 0) {
uni.showToast({
title: '已添加到我的小程序',
icon: 'success'
})
}
}
})
}
// 打开添加玩家弹窗
const openAddPlayerPopup = () => {
showAddPlayerPopup.value = true
}
// 关闭添加玩家弹窗
const closeAddPlayerPopup = () => {
showAddPlayerPopup.value = false
}
// 打开结算弹窗
const openSettlePopup = () => {
showSettlePopup.value = true
rateValue.value = '' // 重置倍率输入
}
// 关闭结算弹窗
const closeSettlePopup = () => {
showSettlePopup.value = false
}
// 打开转让计分员弹窗
const transferScorer = () => {
showTransferPopup.value = true
}
// 关闭转让计分员弹窗
const closeTransferPopup = () => {
showTransferPopup.value = false
}
// 切换台板
const toggleBoard = (e) => {
boardEnabled.value = e.detail.value
if (boardEnabled.value) {
// 台板开启时添加一个新玩家
addBoardPlayer()
} else {
// 台板关闭时移除台板玩家
removeBoardPlayer()
}
updateTotalScore()
}
// 添加台板玩家
const addBoardPlayer = () => {
const newPlayer = {
id: Date.now(),
name: '台板',
avatar: 'https://tse3-mm.cn.bing.net/th/id/OIP-C.32slU2a6Cq1Sxvd1GV_LvgHaDe?w=292&h=164&c=7&r=0&o=7&cb=ucfimgc2&dpr=1.5&pid=1.7&rm=3',
score: 0,
isSelf: false
}
players.value.push(newPlayer)
}
// 移除台板玩家
const removeBoardPlayer = () => {
players.value = players.value.filter(player => player.name !== '台板')
}
// 确认结算
const confirmSettlement = () => {
if (!rateValue.value) {
uni.showToast({
title: '请输入倍率',
icon: 'none'
})
return
}
// 关闭弹窗
closeSettlePopup()
// 跳转到结算页面,传递倍率参数
uni.navigateTo({
url: `/pages/settle/index?rate=${rateValue.value}`
})
}
// 切换语音播报
const toggleVoice = (e) => {
voiceEnabled.value = e.detail.value
}
// 开局计分
const startScoring = () => {
uni.navigateTo({
url: '/pages/scoring/index'
})
}
// 分享房间
const shareRoom = () => {
uni.showShareMenu({
withShareTicket: true
})
uni.showToast({
title: '请使用分享功能',
icon: 'none'
})
}
// 添加虚拟玩家
const addVirtualPlayer = () => {
const newPlayer = {
id: Date.now(),
name: `玩家${Math.floor(Math.random() * 100000)}`,
avatar: 'https://tse2-mm.cn.bing.net/th/id/OIP-C.Pbhgd_vCFFNQWXi7y-HynAAAAA?w=209&h=209&c=7&r=0&o=7&cb=ucfimgc2&dpr=1.5&pid=1.7&rm=3',
score: 0,
isSelf: false
}
players.value.push(newPlayer)
updateTotalScore()
closeAddPlayerPopup()
uni.showToast({
title: '已添加虚拟玩家',
icon: 'success'
})
}
</script>
<style lang="less" scoped>
.single-room {
background-color: #fff;
min-height: 100vh;
}
/* 顶部导航栏 */
.nav-bar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 30rpx;
background-color: #41479b;
color: #fff;
.nav-back, .nav-actions {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
}
.nav-title {
font-size: 32rpx;
font-weight: 500;
}
}
/* 功能栏 */
.function-bar {
display: flex;
padding: 15rpx 20rpx;
background-color: #41479b;
color: #fff;
border-top: 1rpx solid #555aaf;
border-bottom: 1rpx solid #555aaf;
.function-item {
display: flex;
align-items: center;
margin-right: 30rpx;
text {
margin-left: 10rpx;
font-size: 28rpx;
}
switch {
transform: scale(0.8);
}
}
}
/* 对局记录区域 */
.record-section {
padding: 20rpx 30rpx;
.record-title {
font-size: 32rpx;
font-weight: 600;
color: #000;
margin-bottom: 10rpx;
}
.record-tip {
font-size: 26rpx;
color: #666;
margin-bottom: 10rpx;
}
}
/* 玩家列表 */
.player-list {
padding: 0 30rpx 30rpx;
.player-item {
display: flex;
padding: 20rpx 0;
border-bottom: 1rpx solid #eee;
&:last-child {
border-bottom: none;
}
.player-label {
width: 120rpx;
font-size: 28rpx;
color: #000;
}
.player-info-container {
display: flex;
flex-wrap: wrap;
flex: 1;
}
.player-info {
display: flex;
flex-direction: column;
align-items: center;
margin-right: 30rpx;
.player-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-bottom: 10rpx;
}
.player-name {
font-size: 24rpx;
color: #000;
margin-bottom: 5rpx;
}
.self-tag {
background-color: #007aff;
color: #fff;
font-size: 20rpx;
padding: 2rpx 8rpx;
border-radius: 10rpx;
}
}
.player-score {
font-size: 36rpx;
color: #007aff;
font-weight: 600;
}
}
}
/* 底部操作按钮 */
.action-buttons {
display: flex;
padding: 40rpx;
gap: 40rpx;
margin-top: 600rpx;
button {
flex: 1;
height: 90rpx;
border-radius: 8rpx;
font-size: 32rpx;
font-weight: 600;
}
.start-btn {
background-color: #41479b;
color: #fff;
}
.settle-btn {
background-color: #fff;
color: #41479b;
border: 1rpx solid #41479b;
}
}
/* 弹窗遮罩层 */
.popup-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 999;
}
/* 添加玩家弹窗样式 */
.popup-content {
width: 650rpx;
background-color: #fff;
border-radius: 16rpx;
overflow: hidden;
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #eee;
.popup-title {
font-size: 32rpx;
font-weight: 600;
color: #000;
}
.popup-close {
width: 40rpx;
height: 40rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
.popup-body {
padding: 30rpx;
.popup-tip {
font-size: 28rpx;
color: #666;
text-align: center;
margin-bottom: 40rpx;
}
.qrcode-container {
display: flex;
justify-content: center;
margin-bottom: 40rpx;
.qrcode {
width: 400rpx;
height: 400rpx;
border: 1rpx solid #eee;
}
}
.popup-buttons {
display: flex;
flex-direction: column;
gap: 20rpx;
margin-bottom: 30rpx;
button {
height: 80rpx;
border-radius: 8rpx;
font-size: 30rpx;
font-weight: 500;
}
.share-btn {
background-color: #41479b;
color: #fff;
}
.add-virtual-btn {
background-color: #fff;
color: #41479b;
border: 1rpx solid #41479b;
}
}
.popup-footer {
.footer-tip {
font-size: 24rpx;
color: #999;
text-align: center;
}
}
}
}
/* 结算弹窗样式 */
.settle-popup-content {
width: 600rpx;
background-color: #fff;
border-radius: 16rpx;
overflow: hidden;
.settle-popup-body {
padding: 30rpx;
.settle-tip {
font-size: 32rpx;
font-weight: 600;
color: #000;
margin-bottom: 30rpx;
margin-left: 120rpx;
}
.rate-input-section {
margin-bottom: 40rpx;
.rate-input {
width: 100%;
height: 80rpx;
border: 1rpx solid #ddd;
border-radius: 8rpx;
padding: 0 20rpx;
font-size: 28rpx;
text-align: center;
&:focus {
border-color: #41479b;
}
}
}
.settle-popup-buttons {
display: flex;
gap: 20rpx;
button {
flex: 1;
height: 80rpx;
border-radius: 8rpx;
font-size: 30rpx;
font-weight: 500;
}
.cancel-btn {
background-color: #f5f5f5;
color: #333;
}
.confirm-btn {
background-color: #41479b;
color: #fff;
}
}
}
}
/* 转让计分员弹窗样式 */
.transfer-popup-content {
width: 600rpx;
background-color: #fff;
border-radius: 16rpx;
overflow: hidden;
.transfer-popup-body {
padding: 40rpx 30rpx 30rpx;
.transfer-tip {
font-size: 28rpx;
color: #000;
text-align: center;
margin-bottom: 40rpx;
line-height: 1.5;
}
.transfer-popup-buttons {
display: flex;
justify-content: center;
button {
width: 200rpx;
height: 70rpx;
border-radius: 8rpx;
font-size: 30rpx;
font-weight: 500;
background-color: #41479b;
color: #fff;
}
}
}
}
</style>