Files
hx123666/scoring/pages/single-room/index.vue
2025-11-24 15:30:05 +08:00

1284 lines
31 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="warning-tip">
本工具不涉及金钱禁止用于非法行为
</view>
</view>
<!-- 玩家列表 - 添加滚动条功能 -->
<view class="player-list-container">
<!-- 水平滚动容器 -->
<scroll-view
class="player-scroll-view"
scroll-x="true"
:scroll-left="scrollLeft"
@scroll="onScroll"
:show-scrollbar="false"
scroll-with-animation
>
<view class="player-list">
<!-- 玩家信息行 -->
<view class="player-row">
<view class="player-label">玩家 ({{ players.length }})</view>
<view class="player-columns">
<view class="player-column" v-for="(player, index) in players" :key="player.id">
<view class="player-info" @click="editUserInfo(player)">
<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>
<!-- 总分行 -->
<view class="player-row">
<view class="player-label">总分</view>
<view class="player-columns">
<view class="player-column" v-for="player in players" :key="player.id">
<view class="player-score">
{{ formatScore(player.totalScore) }}
</view>
</view>
</view>
</view>
<!-- 每局得分行 -->
<view class="player-row" v-for="(round, roundIndex) in gameRounds" :key="roundIndex">
<view class="player-label">{{ roundIndex + 1 }}</view>
<view class="player-columns">
<view class="player-column" v-for="player in players" :key="player.id">
<view class="round-score" @click="editRoundScore(roundIndex, player.id)">
{{ formatScore(getPlayerRoundScore(roundIndex, player.id)) }}
</view>
</view>
</view>
</view>
</view>
</scroll-view>
<!-- 自定义可拖动滚动条 -->
<view class="custom-scrollbar" v-if="showScrollIndicator">
<view
class="scroll-track"
@touchstart="onTrackTouchStart"
@touchmove.prevent="onTrackTouchMove"
@touchend="onTrackTouchEnd"
:id="trackId"
>
<view
class="scroll-thumb"
:style="{
left: thumbPosition + '%',
width: thumbWidth + '%'
}"
@touchstart="onThumbTouchStart"
@touchmove.prevent="onThumbTouchMove"
@touchend="onThumbTouchEnd"
></view>
</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="openAddVirtualPlayerPopup">手动添加虚拟玩家</button>
</view>
<view class="popup-footer">
<view class="footer-tip">点击自己头像编辑用户头像和昵称~</view>
</view>
</view>
</view>
</view>
<!-- 添加虚拟玩家弹窗 -->
<view v-if="showAddVirtualPlayerPopup" class="popup-mask" @click="closeAddVirtualPlayerPopup">
<view class="add-virtual-popup-content" @click.stop>
<view class="add-virtual-popup-body">
<view class="add-virtual-title">添加玩家</view>
<view class="name-input-section">
<input
class="name-input"
type="text"
placeholder="请输入"
v-model="virtualPlayerName"
maxlength="10"
focus
/>
</view>
<view class="add-virtual-popup-buttons">
<button class="cancel-btn" @click="closeAddVirtualPlayerPopup">取消</button>
<button class="confirm-btn" @click="confirmAddVirtualPlayer">确定</button>
</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, onUnmounted, computed, watch, nextTick } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { getuser } from '@/api/room'
// 房间数据
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',
totalScore: 0,
isSelf: true
}
])
// 游戏对局记录
const gameRounds = ref([])
// 弹窗显示状态
const showAddPlayerPopup = ref(false)
const showAddVirtualPlayerPopup = ref(false)
const showSettlePopup = ref(false)
const showTransferPopup = ref(false)
const rateValue = ref('')
const virtualPlayerName = ref('')
// 滚动条相关数据
const scrollLeft = ref(0)
const scrollWidth = ref(0)
const scrollViewWidth = ref(0)
const trackId = ref('scroll-track-' + Date.now())
// 滚动条拖动状态
const isDragging = ref(false)
const dragStartX = ref(0)
const dragStartScrollLeft = ref(0)
const trackRect = ref({ left: 0, width: 0 })
// 存储最后知道的用户信息,用于比较
let lastUserInfo = null
// 用于保存interval ID的ref
const storageIntervalIds = ref(null)
const userInfoIntervalIds = ref(null)
// 计算属性:是否显示滚动条指示器
const showScrollIndicator = computed(() => {
return scrollWidth.value > scrollViewWidth.value
})
// 计算属性:滚动条滑块宽度
const thumbWidth = computed(() => {
if (scrollWidth.value === 0) return 100
const widthRatio = (scrollViewWidth.value / scrollWidth.value) * 100
return Math.max(20, Math.min(100, widthRatio)) // 最小宽度20%最大100%
})
// 计算属性:滚动条滑块位置
const thumbPosition = computed(() => {
if (scrollWidth.value === 0 || scrollWidth.value <= scrollViewWidth.value) return 0
const maxScroll = scrollWidth.value - scrollViewWidth.value
return (scrollLeft.value / maxScroll) * (100 - thumbWidth.value)
})
// 格式化分数显示
const formatScore = (score) => {
if (score === 0) return '0'
return score > 0 ? `+${score}` : `${score}`
}
// 获取玩家在某一局的得分
const getPlayerRoundScore = (roundIndex, playerId) => {
if (!gameRounds.value[roundIndex]) return 0
const playerScore = gameRounds.value[roundIndex].find(item => item.playerId === playerId)
return playerScore ? playerScore.score : 0
}
// 更新玩家总分
const updateTotalScores = () => {
players.value.forEach(player => {
let total = 0
gameRounds.value.forEach(round => {
const roundScore = round.find(item => item.playerId === player.id)
if (roundScore) {
total += roundScore.score
}
})
player.totalScore = total
})
}
// 滚动事件处理
const onScroll = (e) => {
scrollLeft.value = e.detail.scrollLeft
}
// 监听玩家数量变化,更新滚动区域
watch(players, () => {
// 在下一个tick更新滚动区域尺寸
setTimeout(() => {
updateScrollDimensions()
}, 100)
}, { deep: true })
// 更新滚动区域尺寸
const updateScrollDimensions = () => {
const query = uni.createSelectorQuery()
query.select('.player-scroll-view').boundingClientRect()
query.select('.player-list').boundingClientRect()
query.exec((res) => {
if (res[0] && res[1]) {
scrollViewWidth.value = res[0].width
scrollWidth.value = res[1].width
}
})
}
// 获取轨道位置信息
const getTrackRect = () => {
return new Promise((resolve) => {
const query = uni.createSelectorQuery()
query.select('.custom-scrollbar .scroll-track').boundingClientRect()
query.exec((res) => {
if (res[0]) {
trackRect.value = {
left: res[0].left,
width: res[0].width
}
resolve(trackRect.value)
} else {
resolve(null)
}
})
})
}
// 滚动条滑块触摸开始
const onThumbTouchStart = async (e) => {
isDragging.value = true
dragStartX.value = e.touches[0].clientX
dragStartScrollLeft.value = scrollLeft.value
// 获取轨道位置信息
await getTrackRect()
e.stopPropagation()
}
// 滚动条滑块触摸移动
const onThumbTouchMove = (e) => {
if (!isDragging.value) return
const deltaX = e.touches[0].clientX - dragStartX.value
const maxScroll = Math.max(0, scrollWidth.value - scrollViewWidth.value)
if (maxScroll > 0 && trackRect.value.width > 0) {
const scrollPercent = deltaX / trackRect.value.width
const newScrollLeft = dragStartScrollLeft.value + (scrollPercent * maxScroll)
scrollLeft.value = Math.max(0, Math.min(maxScroll, newScrollLeft))
}
e.stopPropagation()
}
// 滚动条滑块触摸结束
const onThumbTouchEnd = (e) => {
isDragging.value = false
e.stopPropagation()
}
// 滚动条轨道触摸开始
const onTrackTouchStart = async (e) => {
// 获取轨道位置信息
const rect = await getTrackRect()
if (!rect) return
const clickX = e.touches[0].clientX - rect.left
const thumbWidthPx = (thumbWidth.value / 100) * rect.width
const thumbCenter = (thumbPosition.value / 100) * rect.width + thumbWidthPx / 2
// 如果点击位置在滑块中心左侧,滚动到左侧
// 如果点击位置在滑块中心右侧,滚动到右侧
const maxScroll = Math.max(0, scrollWidth.value - scrollViewWidth.value)
if (maxScroll > 0) {
if (clickX < thumbCenter) {
// 向左滚动一页
scrollLeft.value = Math.max(0, scrollLeft.value - scrollViewWidth.value * 0.8)
} else {
// 向右滚动一页
scrollLeft.value = Math.min(maxScroll, scrollLeft.value + scrollViewWidth.value * 0.8)
}
}
}
// 滚动条轨道触摸移动
const onTrackTouchMove = (e) => {
// 轨道拖动可以用于快速跳转,但这里我们主要用滑块拖动
e.stopPropagation()
}
// 滚动条轨道触摸结束
const onTrackTouchEnd = (e) => {
e.stopPropagation()
}
// 编辑用户信息
const editUserInfo = (player) => {
if (player.isSelf) {
// 跳转到用户信息编辑页面
uni.navigateTo({
url: '/pages/edit-user-info/index'
})
} else {
// 如果是其他玩家,可以添加其他操作,比如查看玩家信息等
uni.showToast({
title: '只能编辑自己的信息',
icon: 'none'
})
}
}
// 加载用户信息 - 改进版
const loadUserInfo = () => {
const savedUserInfo = uni.getStorageSync('userInfo')
if (savedUserInfo) {
// 强制更新自己的玩家信息
const selfPlayerIndex = players.value.findIndex(player => player.isSelf)
if (selfPlayerIndex !== -1) {
players.value[selfPlayerIndex].name = savedUserInfo.nickname
players.value[selfPlayerIndex].avatar = savedUserInfo.avatar
// 强制触发视图更新
players.value = [...players.value]
}
}
}
// 加载对局记录
const loadGameRounds = () => {
const savedRounds = uni.getStorageSync('gameRounds')
if (savedRounds) {
gameRounds.value = savedRounds
updateTotalScores()
}
}
// 同步玩家信息
const syncPlayerInfo = () => {
// 从本地存储获取最新的玩家信息
const savedPlayers = uni.getStorageSync('players')
if (savedPlayers && savedPlayers.length > 0) {
// 更新玩家基本信息,但保留当前的总分状态
players.value.forEach((player, index) => {
const savedPlayer = savedPlayers.find(p => p.id === player.id)
if (savedPlayer) {
// 只更新头像和名称,不更新总分
player.avatar = savedPlayer.avatar
player.name = savedPlayer.name
}
})
}
}
// 用户信息变化监听
const setupUserInfoListener = () => {
lastUserInfo = uni.getStorageSync('userInfo')
const intervalId = setInterval(() => {
const currentUserInfo = uni.getStorageSync('userInfo')
if (JSON.stringify(currentUserInfo) !== JSON.stringify(lastUserInfo)) {
console.log('检测到用户信息变化,自动更新')
lastUserInfo = currentUserInfo
loadUserInfo()
syncPlayerInfo()
}
}, 500)
return intervalId
}
// 添加一个全局事件监听器来监听存储变化
const setupStorageListener = () => {
// 监听存储变化,当 gameRounds 更新时重新加载数据
const intervalId = setInterval(() => {
const currentRounds = uni.getStorageSync('gameRounds') || []
if (JSON.stringify(currentRounds) !== JSON.stringify(gameRounds.value)) {
gameRounds.value = currentRounds
updateTotalScores()
}
}, 1000)
return intervalId
}
// 组件挂载后初始化
onMounted(() => {
console.log('组件已挂载')
loadGameRounds()
loadUserInfo()
// 设置监听器并保存ID以便清理
const storageIntervalId = setupStorageListener()
const userInfoIntervalId = setupUserInfoListener()
// 监听用户信息更新事件
uni.$on('userInfoUpdated', () => {
console.log('收到用户信息更新事件')
loadUserInfo()
syncPlayerInfo()
})
// 保存interval ID以便清理
storageIntervalIds.value = storageIntervalId
userInfoIntervalIds.value = userInfoIntervalId
// 初始化滚动区域尺寸
setTimeout(() => {
updateScrollDimensions()
getTrackRect() // 初始化轨道位置信息
}, 500)
})
// 页面显示时刷新
onShow(() => {
console.log('页面显示,刷新数据')
loadGameRounds()
syncPlayerInfo()
loadUserInfo()
// 更新滚动区域尺寸
setTimeout(() => {
updateScrollDimensions()
getTrackRect() // 更新轨道位置信息
}, 100)
})
// 在组件卸载时移除事件监听和定时器
onUnmounted(() => {
uni.$off('userInfoUpdated')
if (storageIntervalIds.value) {
clearInterval(storageIntervalIds.value)
}
if (userInfoIntervalIds.value) {
clearInterval(userInfoIntervalIds.value)
}
})
// 返回上一页
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 openAddVirtualPlayerPopup = () => {
showAddVirtualPlayerPopup.value = true
virtualPlayerName.value = '' // 重置输入
}
// 关闭添加虚拟玩家弹窗
const closeAddVirtualPlayerPopup = () => {
showAddVirtualPlayerPopup.value = false
}
// 确认添加虚拟玩家
const confirmAddVirtualPlayer = () => {
if (!virtualPlayerName.value.trim()) {
uni.showToast({
title: '请输入玩家名称',
icon: 'none'
})
return
}
const newPlayer = {
id: Date.now(),
name: virtualPlayerName.value.trim(),
avatar: 'https://ts3.tc.mm.bing.net/th/id/OIP-C.0FQSOvu3OYJFe-h_sZKA6wHaNK?cb=ucfimg2ucfimg=1&rs=1&pid=ImgDetMain&o=7&rm=3',
totalScore: 0,
isSelf: false
}
players.value.push(newPlayer)
// 保存玩家数据到本地存储
uni.setStorageSync('players', players.value)
// 关闭所有弹窗
closeAddVirtualPlayerPopup()
closeAddPlayerPopup()
uni.showToast({
title: '已添加虚拟玩家',
icon: 'success'
})
}
// 打开结算弹窗
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()
}
}
// 添加台板玩家
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',
totalScore: 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
}
// 保存玩家数据到本地存储,供结算页面使用
uni.setStorageSync('players', players.value)
// 关闭弹窗
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?players=${encodeURIComponent(JSON.stringify(players.value))}&round=${gameRounds.value.length + 1}`
})
}
// 编辑对局分数
const editRoundScore = (roundIndex, playerId) => {
// 获取该局的所有玩家得分数据
const roundScores = gameRounds.value[roundIndex]
if (!roundScores) {
uni.showToast({
title: '该局数据不存在',
icon: 'none'
})
return
}
// 构建玩家数据,包含当前得分和胜负状态
const playersWithScores = players.value.map(player => {
const playerScore = roundScores.find(score => score.playerId === player.id)
const scoreValue = playerScore ? playerScore.score : 0
return {
...player,
currentScore: Math.abs(scoreValue).toString(),
isWin: scoreValue >= 0,
finalScore: scoreValue
}
})
// 跳转到计分页面,传递玩家数据、对局索引和编辑模式标识
uni.navigateTo({
url: `/pages/scoring/index?players=${encodeURIComponent(JSON.stringify(playersWithScores))}&round=${roundIndex + 1}&mode=edit&roundIndex=${roundIndex}`
})
}
// 分享房间
const shareRoom = () => {
uni.showShareMenu({
withShareTicket: true
})
uni.showToast({
title: '请使用分享功能',
icon: 'none'
})
}
</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;
}
.warning-tip {
font-size: 26rpx;
color: #ff6b6b;
margin-bottom: 10rpx;
}
}
/* 玩家列表容器 - 新增样式 */
.player-list-container {
padding: 0 30rpx 30rpx;
position: relative;
}
/* 滚动视图样式 */
.player-scroll-view {
width: 100%;
white-space: nowrap;
// 隐藏原生滚动条
::-webkit-scrollbar {
display: none;
}
}
/* 玩家列表 - 修改后的样式 */
.player-list {
display: inline-block;
min-width: 100%;
}
.player-row {
display: flex;
padding: 20rpx 0;
border-bottom: 1rpx solid #eee;
&:last-child {
border-bottom: none;
}
.player-label {
width: 120rpx;
font-size: 28rpx;
color: #000;
display: flex;
align-items: center;
flex-shrink: 0;
}
.player-columns {
display: flex;
flex: 1;
justify-content: flex-start;
}
.player-column {
display: flex;
flex-direction: column;
align-items: center;
width: 120rpx;
flex-shrink: 0;
}
.player-info {
display: flex;
flex-direction: column;
align-items: center;
// 添加点击效果
&:active {
opacity: 0.7;
}
.player-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-bottom: 10rpx;
}
.player-name {
font-size: 24rpx;
color: #000;
margin-bottom: 5rpx;
text-align: center;
max-width: 100rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.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;
margin-top: 10rpx;
}
.round-score {
font-size: 28rpx;
color: #333;
margin-top: 10rpx;
padding: 5rpx 10rpx;
border-radius: 5rpx;
&:active {
background-color: #f0f0f0;
}
}
}
/* 自定义可拖动滚动条样式 */
.custom-scrollbar {
margin-top: 20rpx;
padding: 0 20rpx;
.scroll-track {
height: 12rpx;
background-color: #f0f0f0;
border-radius: 6rpx;
position: relative;
// 添加点击区域扩展
&::before {
content: '';
position: absolute;
top: -10rpx;
bottom: -10rpx;
left: 0;
right: 0;
}
}
.scroll-thumb {
position: absolute;
height: 100%;
background-color: #41479b;
border-radius: 6rpx;
transition: all 0.1s ease;
// 添加悬停效果
&:active {
background-color: #33367a;
transform: scale(1.1);
}
}
}
/* 底部操作按钮 */
.action-buttons {
display: flex;
padding: 40rpx;
gap: 40rpx;
margin-top: 500rpx;
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;
}
}
}
}
/* 添加虚拟玩家弹窗样式 */
.add-virtual-popup-content {
width: 600rpx;
background-color: #fff;
border-radius: 16rpx;
overflow: hidden;
.add-virtual-popup-body {
padding: 30rpx;
.add-virtual-title {
font-size: 32rpx;
font-weight: 600;
color: #000;
margin-bottom: 30rpx;
text-align: center;
}
.name-input-section {
margin-bottom: 40rpx;
.name-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;
}
}
}
.add-virtual-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;
}
}
}
}
/* 结算弹窗样式 */
.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>