|
@@ -1,25 +1,15 @@
|
|
|
<template>
|
|
|
<view class="waiting-room-page">
|
|
|
<!-- 顶部标题 -->
|
|
|
- <view
|
|
|
- class="room-header"
|
|
|
- :class="{ 'host-background': isHost, 'player-background': !isHost }"
|
|
|
- >
|
|
|
- <view
|
|
|
- class="room-title"
|
|
|
- :class="{ 'host-title': isHost, 'player-title': !isHost }"
|
|
|
- >
|
|
|
- {{ currentRoom?.name || '等待房间' }}
|
|
|
- </view>
|
|
|
- <view
|
|
|
- class="room-status"
|
|
|
- :class="{ 'host-status': isHost, 'player-status': !isHost }"
|
|
|
- >
|
|
|
- {{ playerCount }}/{{ currentRoom?.maxPlayers || 0 }} 已加入,{{ statusText }}
|
|
|
- </view>
|
|
|
- </view>
|
|
|
+ <RoomHeader
|
|
|
+ :roomName="currentRoom?.name"
|
|
|
+ :isHost="isHost"
|
|
|
+ :playerCount="playerCount"
|
|
|
+ :maxPlayers="currentRoom?.maxPlayers || 0"
|
|
|
+ :statusText="statusText"
|
|
|
+ />
|
|
|
|
|
|
- <!-- 房间码展示和分享 保持不变 -->
|
|
|
+ <!-- 房间码展示和分享 -->
|
|
|
<RoomCode
|
|
|
:code="currentRoom?.id || ''"
|
|
|
:password="currentRoom?.password"
|
|
@@ -27,287 +17,54 @@
|
|
|
@copy="handleCopy"
|
|
|
/>
|
|
|
|
|
|
- <!-- 主持人视图 -->
|
|
|
- <view v-if="isHost" class="host-view">
|
|
|
- <!-- 游戏设置模块 -->
|
|
|
- <view class="game-settings">
|
|
|
- <nut-divider
|
|
|
- content-position="center"
|
|
|
- :style="{ color: '#3C92FB', borderColor: '#3C92FB', padding: '0 16px', margin: '12px 0 12px 0' }"
|
|
|
- >
|
|
|
- 游戏设置
|
|
|
- </nut-divider>
|
|
|
-
|
|
|
- <!-- 1. 主题选择 -->
|
|
|
- <view class="setting-item">
|
|
|
- <view class="setting-label">主题选择</view>
|
|
|
- <nut-cell
|
|
|
- :desc="selectedTheme?.text || '请选择游戏主题'"
|
|
|
- @click="showThemeSelector = true"
|
|
|
- >
|
|
|
- <template #link>
|
|
|
- <IconFont name="right" size="16"></IconFont>
|
|
|
- </template>
|
|
|
- </nut-cell>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 2. 难度选择 -->
|
|
|
- <view class="setting-item">
|
|
|
- <view class="setting-label">游戏难度</view>
|
|
|
- <nut-cell
|
|
|
- :desc="difficultyText"
|
|
|
- @click="showDifficultySelector = true"
|
|
|
- >
|
|
|
- <template #link>
|
|
|
- <IconFont name="right" size="16"></IconFont>
|
|
|
- </template>
|
|
|
- </nut-cell>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 3. 题目选择 (只有当主题和难度都选择后才显示) -->
|
|
|
- <view class="setting-item" v-if="selectedThemeId && selectedDifficulty">
|
|
|
- <view class="setting-label">题目选择</view>
|
|
|
- <nut-cell
|
|
|
- :desc="selectedPuzzle?.text || '请选择游戏题目'"
|
|
|
- @click="selectedThemeId ? showPuzzleSelector = true : null"
|
|
|
- >
|
|
|
- <template #link>
|
|
|
- <IconFont name="right" size="16"></IconFont>
|
|
|
- </template>
|
|
|
- </nut-cell>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 玩家列表 保持不变 -->
|
|
|
- <view class="player-list">
|
|
|
- <nut-divider
|
|
|
- content-position="center"
|
|
|
- :style="{ color: '#3C92FB', borderColor: '#3C92FB', padding: '0 16px', margin: '12px 0 12px 0' }"
|
|
|
- >
|
|
|
- 玩家列表
|
|
|
- </nut-divider>
|
|
|
-
|
|
|
- <view class="players">
|
|
|
- <view
|
|
|
- v-for="user in currentRoom?.users"
|
|
|
- :key="user.openid"
|
|
|
- class="player-item"
|
|
|
- :class="{ 'is-host': user.roomRole === 'hoster' }"
|
|
|
- >
|
|
|
- <view class="player-avatar">
|
|
|
- <image :src="user.avatar || '/assets/default-avatar.png'" mode="aspectFill" @error="handleAvatarError" />
|
|
|
- </view>
|
|
|
- <view class="player-info">
|
|
|
- <view class="player-name">{{ user.nickname }}</view>
|
|
|
- <view class="player-role">{{ user.roomRole === 'hoster' ? '主持人' : '玩家' }}</view>
|
|
|
- </view>
|
|
|
- <view class="player-status" :class="{ 'ready': user.isReady }">
|
|
|
- {{ user.isReady ? '已准备' : '未准备' }}
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 主持人操作按钮 保持不变 -->
|
|
|
- <view class="action-buttons">
|
|
|
- <nut-button
|
|
|
- block
|
|
|
- color="#3C92FB"
|
|
|
- class="start-button"
|
|
|
- :disabled="!canStartGame"
|
|
|
- @click="startGame"
|
|
|
- >
|
|
|
- 开始游戏
|
|
|
- </nut-button>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 玩家视图 保持不变 -->
|
|
|
- <view v-else class="player-view">
|
|
|
- <!-- 游戏信息展示 -->
|
|
|
- <view class="game-info">
|
|
|
- <nut-divider
|
|
|
- content-position="center"
|
|
|
- :style="{ color: '#3C92FB', borderColor: '#3C92FB', padding: '0 16px', margin: '12px 0 12px 0' }"
|
|
|
- >
|
|
|
- 游戏信息
|
|
|
- </nut-divider>
|
|
|
-
|
|
|
- <view class="info-card">
|
|
|
- <view class="game-title">{{ gameTitle }}</view>
|
|
|
- <view class="game-meta">
|
|
|
- <view class="meta-item">
|
|
|
- <view class="meta-label">游戏主题</view>
|
|
|
- <view class="meta-value">{{ themeTitle || '待定' }}</view>
|
|
|
- </view>
|
|
|
- <view class="meta-item">
|
|
|
- <view class="meta-label">游戏难度</view>
|
|
|
- <view class="meta-value">{{ difficultyText }}</view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <view class="game-desc">
|
|
|
- {{ gameDescription || '正在等待主持人设置游戏...' }}
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 玩家列表 -->
|
|
|
- <view class="player-list">
|
|
|
- <nut-divider
|
|
|
- content-position="center"
|
|
|
- :style="{ color: '#3C92FB', borderColor: '#3C92FB', padding: '0 16px', margin: '12px 0 12px 0' }"
|
|
|
- >
|
|
|
- 玩家列表
|
|
|
- </nut-divider>
|
|
|
-
|
|
|
- <view class="players">
|
|
|
- <view
|
|
|
- v-for="user in currentRoom?.users"
|
|
|
- :key="user.openid"
|
|
|
- class="player-item"
|
|
|
- :class="{ 'is-host': user.roomRole === 'hoster' }"
|
|
|
- >
|
|
|
- <view class="player-avatar">
|
|
|
- <image :src="user.avatar || '/assets/default-avatar.png'" mode="aspectFill" @error="handleAvatarError" />
|
|
|
- </view>
|
|
|
- <view class="player-info">
|
|
|
- <view class="player-name">{{ user.nickname }}</view>
|
|
|
- <view class="player-role">{{ user.roomRole === 'hoster' ? '主持人' : '玩家' }}</view>
|
|
|
- </view>
|
|
|
- <view class="player-status" :class="{ 'ready': user.isReady }">
|
|
|
- {{ user.isReady ? '已准备' : '未准备' }}
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 玩家操作按钮 -->
|
|
|
- <view class="action-buttons">
|
|
|
- <nut-button
|
|
|
- block
|
|
|
- :color="currentUserReady ? '#999' : '#3C92FB'"
|
|
|
- class="ready-button"
|
|
|
- @click="toggleReady"
|
|
|
- >
|
|
|
- {{ currentUserReady ? '取消准备' : '准备' }}
|
|
|
- </nut-button>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 主题选择弹窗 -->
|
|
|
- <nut-popup v-model:visible="showThemeSelector" position="bottom">
|
|
|
- <view class="selector-container">
|
|
|
- <view class="selector-header">
|
|
|
- <view class="selector-title">选择游戏主题</view>
|
|
|
- <nut-button size="small" @click="showThemeSelector = false">取消</nut-button>
|
|
|
- </view>
|
|
|
- <scroll-view
|
|
|
- scroll-y
|
|
|
- class="theme-scroll"
|
|
|
- :style="{ maxHeight: themeScrollHeight + 'px' }"
|
|
|
- >
|
|
|
- <view class="theme-list">
|
|
|
- <view
|
|
|
- v-for="theme in themeOptions"
|
|
|
- :key="theme.value"
|
|
|
- class="theme-option"
|
|
|
- :class="{ 'disabled': theme.disabled && !canPurchase, 'selected': selectedThemeId === theme.value }"
|
|
|
- @click="handleThemeClick(theme)"
|
|
|
- >
|
|
|
- <view class="option-content">
|
|
|
- <view class="option-title">{{ theme.text }}</view>
|
|
|
- <view v-if="theme.description" class="option-desc">{{ theme.description }}</view>
|
|
|
- <view v-if="theme.locked" class="theme-locked">
|
|
|
- <IconFont name="lock" size="12"></IconFont>
|
|
|
- <view class="lock-text">{{ theme.unlockRequirement }}</view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <!-- 添加解锁购买按钮 -->
|
|
|
- <view v-if="theme.locked && canPurchase" class="unlock-button" @click.stop="purchaseTheme(theme)">
|
|
|
- <nut-button size="small" type="primary">解锁 ({{ theme.price || '5' }}元)</nut-button>
|
|
|
- </view>
|
|
|
- <IconFont v-else-if="selectedThemeId === theme.value" name="check" color="#3C92FB" size="16"></IconFont>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </scroll-view>
|
|
|
- </view>
|
|
|
- </nut-popup>
|
|
|
-
|
|
|
- <!-- 难度选择弹窗 -->
|
|
|
- <nut-popup v-model:visible="showDifficultySelector" position="bottom">
|
|
|
- <view class="selector-container">
|
|
|
- <view class="selector-header">
|
|
|
- <view class="selector-title">选择游戏难度</view>
|
|
|
- <nut-button size="small" @click="showDifficultySelector = false">取消</nut-button>
|
|
|
- </view>
|
|
|
- <view class="difficulty-list">
|
|
|
- <view
|
|
|
- class="difficulty-option"
|
|
|
- :class="{ 'selected': selectedDifficulty === TurtleSoupDifficulty.EASY }"
|
|
|
- @click="handleDifficultySelect(TurtleSoupDifficulty.EASY)"
|
|
|
- >
|
|
|
- <view class="option-content">
|
|
|
- <view class="option-title">简单</view>
|
|
|
- <view class="option-desc">适合新手玩家,游戏时间较短</view>
|
|
|
- </view>
|
|
|
- <IconFont v-if="selectedDifficulty === TurtleSoupDifficulty.EASY" name="check" color="#3C92FB" size="16"></IconFont>
|
|
|
- </view>
|
|
|
- <view
|
|
|
- class="difficulty-option"
|
|
|
- :class="{ 'selected': selectedDifficulty === TurtleSoupDifficulty.MEDIUM }"
|
|
|
- @click="handleDifficultySelect(TurtleSoupDifficulty.MEDIUM)"
|
|
|
- >
|
|
|
- <view class="option-content">
|
|
|
- <view class="option-title">中等</view>
|
|
|
- <view class="option-desc">平衡挑战与乐趣,适合大多数玩家</view>
|
|
|
- </view>
|
|
|
- <IconFont v-if="selectedDifficulty === TurtleSoupDifficulty.MEDIUM" name="check" color="#3C92FB" size="16"></IconFont>
|
|
|
- </view>
|
|
|
- <view
|
|
|
- class="difficulty-option"
|
|
|
- :class="{ 'selected': selectedDifficulty === TurtleSoupDifficulty.HARD }"
|
|
|
- @click="handleDifficultySelect(TurtleSoupDifficulty.HARD)"
|
|
|
- >
|
|
|
- <view class="option-content">
|
|
|
- <view class="option-title">困难</view>
|
|
|
- <view class="option-desc">高难度挑战,适合有经验的玩家</view>
|
|
|
- </view>
|
|
|
- <IconFont v-if="selectedDifficulty === TurtleSoupDifficulty.HARD" name="check" color="#3C92FB" size="16"></IconFont>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </nut-popup>
|
|
|
+ <!-- 主持人/玩家视图 -->
|
|
|
+ <HostView
|
|
|
+ v-if="isHost"
|
|
|
+ :users="currentRoom?.users || []"
|
|
|
+ :selectedTheme="selectedTheme"
|
|
|
+ :selectedPuzzle="selectedPuzzle"
|
|
|
+ :selectedThemeId="selectedThemeId"
|
|
|
+ :selectedDifficulty="selectedDifficulty"
|
|
|
+ :difficultyText="difficultyText"
|
|
|
+ :canStartGame="canStartGame"
|
|
|
+ @show-theme-selector="showThemeSelector = true"
|
|
|
+ @show-difficulty-selector="showDifficultySelector = true"
|
|
|
+ @show-puzzle-selector="showPuzzleSelector = true"
|
|
|
+ @start-game="startGame"
|
|
|
+ />
|
|
|
+ <PlayerView
|
|
|
+ v-else
|
|
|
+ :users="currentRoom?.users || []"
|
|
|
+ :gameTitle="gameTitle"
|
|
|
+ :themeTitle="themeTitle"
|
|
|
+ :difficultyText="difficultyText"
|
|
|
+ :gameDescription="gameDescription"
|
|
|
+ :currentUserReady="currentUserReady"
|
|
|
+ @toggle-ready="toggleReady"
|
|
|
+ />
|
|
|
|
|
|
- <!-- 题目选择弹窗 -->
|
|
|
- <nut-popup v-model:visible="showPuzzleSelector" position="bottom">
|
|
|
- <view class="selector-container">
|
|
|
- <view class="selector-header">
|
|
|
- <view class="selector-title">选择游戏题目</view>
|
|
|
- <nut-button size="small" @click="showPuzzleSelector = false">取消</nut-button>
|
|
|
- </view>
|
|
|
- <scroll-view
|
|
|
- scroll-y
|
|
|
- class="puzzle-scroll"
|
|
|
- :style="{ maxHeight: puzzleScrollHeight + 'px' }"
|
|
|
- >
|
|
|
- <view class="puzzle-list">
|
|
|
- <view
|
|
|
- v-for="puzzle in puzzleOptions"
|
|
|
- :key="puzzle.value"
|
|
|
- class="puzzle-option"
|
|
|
- :class="{ 'disabled': puzzle.disabled, 'selected': selectedPuzzleId === puzzle.value }"
|
|
|
- @click="!puzzle.disabled && handlePuzzleSelect(puzzle)"
|
|
|
- >
|
|
|
- <view class="option-content">
|
|
|
- <view class="option-title">{{ puzzle.text }}</view>
|
|
|
- <view v-if="puzzle.description" class="option-desc">{{ puzzle.description }}</view>
|
|
|
- </view>
|
|
|
- <IconFont v-if="selectedPuzzleId === puzzle.value" name="check" color="#3C92FB" size="16"></IconFont>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </scroll-view>
|
|
|
- </view>
|
|
|
- </nut-popup>
|
|
|
+ <!-- 选择器组件 -->
|
|
|
+ <ThemeSelector
|
|
|
+ v-model:visible="showThemeSelector"
|
|
|
+ :themeOptions="themeOptions"
|
|
|
+ :selectedThemeId="selectedThemeId"
|
|
|
+ :scrollHeight="themeScrollHeight"
|
|
|
+ :canPurchase="canPurchase"
|
|
|
+ @select-theme="handleThemeSelect"
|
|
|
+ @purchase-theme="purchaseTheme"
|
|
|
+ />
|
|
|
+ <DifficultySelector
|
|
|
+ v-model:visible="showDifficultySelector"
|
|
|
+ :selectedDifficulty="selectedDifficulty"
|
|
|
+ @select-difficulty="handleDifficultySelect"
|
|
|
+ />
|
|
|
+ <PuzzleSelector
|
|
|
+ v-model:visible="showPuzzleSelector"
|
|
|
+ :puzzleOptions="puzzleOptions"
|
|
|
+ :selectedPuzzleId="selectedPuzzleId"
|
|
|
+ :scrollHeight="puzzleScrollHeight"
|
|
|
+ @select-puzzle="handlePuzzleSelect"
|
|
|
+ />
|
|
|
</view>
|
|
|
<Tabbar></Tabbar>
|
|
|
</template>
|
|
@@ -321,27 +78,31 @@ import { useTabBarStore } from '@/stores/tabbar'
|
|
|
import { useTurtleSoupStore } from '@/stores/games/turtlesoup'
|
|
|
import Tabbar from '@/components/Tabbar.vue'
|
|
|
import RoomCode from '@/components/RoomCode/index.vue'
|
|
|
-import { IconFont } from '@nutui/icons-vue-taro'
|
|
|
+
|
|
|
+// 导入重构的组件
|
|
|
+import RoomHeader from '@/components/room/RoomHeader.vue'
|
|
|
+import PlayerList from '@/components/room/PlayerList.vue'
|
|
|
+import HostView from '@/components/room/host/HostView.vue'
|
|
|
+import PlayerView from '@/components/room/player/PlayerView.vue'
|
|
|
+import ThemeSelector from '@/components/room/selectors/ThemeSelector.vue'
|
|
|
+import DifficultySelector from '@/components/room/selectors/DifficultySelector.vue'
|
|
|
+import PuzzleSelector from '@/components/room/selectors/PuzzleSelector.vue'
|
|
|
+
|
|
|
import { RoomRole, RoomStatus } from '@/types/room'
|
|
|
import { TurtleSoupDifficulty } from '@/types/games/turtlesoup'
|
|
|
-
|
|
|
-// 主题和题目的数据类型
|
|
|
-interface CascaderOption {
|
|
|
- value: string;
|
|
|
- text: string;
|
|
|
- description?: string;
|
|
|
- disabled?: boolean;
|
|
|
- locked?: boolean;
|
|
|
- unlockRequirement?: string;
|
|
|
- price?: string; // 添加价格字段
|
|
|
- children?: CascaderOption[];
|
|
|
-}
|
|
|
+import { type CascaderOption } from '@/types/cascader'
|
|
|
|
|
|
export default {
|
|
|
components: {
|
|
|
Tabbar,
|
|
|
RoomCode,
|
|
|
- IconFont
|
|
|
+ RoomHeader,
|
|
|
+ PlayerList,
|
|
|
+ HostView,
|
|
|
+ PlayerView,
|
|
|
+ ThemeSelector,
|
|
|
+ DifficultySelector,
|
|
|
+ PuzzleSelector
|
|
|
},
|
|
|
|
|
|
// 生命周期钩子 - 页面显示
|
|
@@ -402,13 +163,6 @@ export default {
|
|
|
return currentUser ? currentUser.isReady : false
|
|
|
})
|
|
|
|
|
|
- // 处理头像加载错误
|
|
|
- const handleAvatarError = (e: any) => {
|
|
|
- console.log('头像加载失败:', e);
|
|
|
- // 设置默认头像
|
|
|
- e.target.src = '/assets/default-avatar.png';
|
|
|
- }
|
|
|
-
|
|
|
// 是否可以开始游戏(主持人功能)
|
|
|
const canStartGame = computed(() => {
|
|
|
if (!currentRoom.value) return false
|
|
@@ -421,15 +175,15 @@ export default {
|
|
|
const allReady = players.every(p => p.isReady)
|
|
|
|
|
|
// 主题和题目已选择
|
|
|
- const settingsReady = selectedThemeId.value && selectedPuzzleId.value
|
|
|
-
|
|
|
+ const settingsReady = !!selectedThemeId.value && !!selectedPuzzleId.value
|
|
|
+
|
|
|
return allReady && settingsReady
|
|
|
})
|
|
|
|
|
|
// 游戏设置相关变量
|
|
|
const selectedDifficulty = ref(TurtleSoupDifficulty.MEDIUM)
|
|
|
- const selectedThemeId = ref('') // 添加选中主题ID
|
|
|
- const selectedPuzzleId = ref('') // 添加选中题目ID
|
|
|
+ const selectedThemeId = ref('')
|
|
|
+ const selectedPuzzleId = ref('')
|
|
|
const selectedTheme = ref<CascaderOption | null>(null)
|
|
|
const selectedPuzzle = ref<CascaderOption | null>(null)
|
|
|
const showThemeSelector = ref(false)
|
|
@@ -443,8 +197,8 @@ export default {
|
|
|
const puzzleOptions = ref<CascaderOption[]>([])
|
|
|
|
|
|
// 设置滚动区域高度限制
|
|
|
- const themeScrollHeight = ref(300) // 最多显示约3个选项
|
|
|
- const puzzleScrollHeight = ref(300) // 最多显示约3个选项
|
|
|
+ const themeScrollHeight = ref(300)
|
|
|
+ const puzzleScrollHeight = ref(300)
|
|
|
|
|
|
// 游戏信息(玩家视图)
|
|
|
const gameTitle = computed(() => currentRoom.value?.gameTitle || '')
|
|
@@ -530,9 +284,9 @@ export default {
|
|
|
value: theme.id,
|
|
|
text: theme.name,
|
|
|
description: theme.description,
|
|
|
- disabled: theme.isLocked, // 根据是否解锁决定是否可选
|
|
|
+ disabled: theme.isLocked,
|
|
|
locked: theme.isLocked,
|
|
|
- price: theme.price ? String(theme.price) : '5' // 添加价格,默认5元
|
|
|
+ price: theme.price ? String(theme.price) : '5'
|
|
|
}))
|
|
|
console.log('已加载主题:', themeOptions.value)
|
|
|
}
|
|
@@ -586,40 +340,10 @@ export default {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 处理主题点击
|
|
|
- const handleThemeClick = (theme: CascaderOption) => {
|
|
|
- // 如果主题被锁定且不可购买,则不做任何操作
|
|
|
- if (theme.disabled && !canPurchase) {
|
|
|
- Taro.showToast({
|
|
|
- title: '该主题暂未解锁',
|
|
|
- icon: 'none'
|
|
|
- })
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- // 如果主题被锁定且可购买,弹出购买提示
|
|
|
- if (theme.locked && canPurchase) {
|
|
|
- // 购买流程在 purchaseTheme 中处理
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- // 正常选择主题
|
|
|
- handleThemeSelect(theme)
|
|
|
- }
|
|
|
-
|
|
|
// 处理主题选择
|
|
|
const handleThemeSelect = (theme: CascaderOption) => {
|
|
|
- if (theme.disabled) {
|
|
|
- Taro.showToast({
|
|
|
- title: '该主题暂未解锁',
|
|
|
- icon: 'none'
|
|
|
- })
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
selectedTheme.value = theme
|
|
|
- selectedThemeId.value = theme.value // 设置选中的主题ID
|
|
|
- showThemeSelector.value = false
|
|
|
+ selectedThemeId.value = theme.value
|
|
|
|
|
|
// 选择主题后提示选择难度
|
|
|
setTimeout(() => {
|
|
@@ -638,7 +362,7 @@ export default {
|
|
|
nonceStr: Math.random().toString(36).substring(2, 15),
|
|
|
package: `prepay_id=wx${Date.now()}`,
|
|
|
signType: 'MD5',
|
|
|
- paySign: 'test_sign', // 实际项目中需要服务端生成真实的支付参数
|
|
|
+ paySign: 'test_sign', // 实际项目中需要服务端生成
|
|
|
success: async () => {
|
|
|
// 支付成功后,解锁主题
|
|
|
Taro.hideLoading()
|
|
@@ -710,16 +434,8 @@ export default {
|
|
|
|
|
|
// 处理题目选择
|
|
|
const handlePuzzleSelect = (puzzle: CascaderOption) => {
|
|
|
- if (puzzle.disabled) {
|
|
|
- Taro.showToast({
|
|
|
- title: '该题目暂未解锁',
|
|
|
- icon: 'none'
|
|
|
- })
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
selectedPuzzle.value = puzzle
|
|
|
- selectedPuzzleId.value = puzzle.value // 设置选中的题目ID
|
|
|
+ selectedPuzzleId.value = puzzle.value
|
|
|
showPuzzleSelector.value = false
|
|
|
}
|
|
|
|
|
@@ -899,21 +615,14 @@ export default {
|
|
|
startGame,
|
|
|
handleCopy,
|
|
|
handleShare,
|
|
|
- handleThemeClick,
|
|
|
handleThemeSelect,
|
|
|
handleDifficultySelect,
|
|
|
handlePuzzleSelect,
|
|
|
purchaseTheme,
|
|
|
- handleAvatarError,
|
|
|
themeScrollHeight,
|
|
|
puzzleScrollHeight,
|
|
|
canPurchase
|
|
|
}
|
|
|
- },
|
|
|
-
|
|
|
- // 生命周期钩子 - 页面加载
|
|
|
- onLoad() {
|
|
|
- // 使用setup方法处理页面加载
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
@@ -924,297 +633,5 @@ export default {
|
|
|
background-color: $background-color-base;
|
|
|
min-height: 100vh;
|
|
|
padding-bottom: $spacing-large * 4; // 为底部tabbar留出空间
|
|
|
-
|
|
|
- .room-header {
|
|
|
- padding: $spacing-base;
|
|
|
- height: 45px;
|
|
|
- text-align: center;
|
|
|
-
|
|
|
- .room-title {
|
|
|
- font-size: 12px;
|
|
|
- font-weight: bold;
|
|
|
- margin-bottom: 4px;
|
|
|
-
|
|
|
- &.host-title {
|
|
|
- color: $text-color-orange;
|
|
|
- }
|
|
|
-
|
|
|
- &.player-title {
|
|
|
- color: $text-color-blue;
|
|
|
- }
|
|
|
- }
|
|
|
- .room-status {
|
|
|
- font-size: 8px;
|
|
|
- margin-bottom: 4px;
|
|
|
-
|
|
|
- &.host-status {
|
|
|
- color: $text-color-orange;
|
|
|
- }
|
|
|
-
|
|
|
- &.player-status {
|
|
|
- color: $text-color-blue;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- &.host-background {
|
|
|
- background-color: $orange-light-color;
|
|
|
- }
|
|
|
-
|
|
|
- &.player-background {
|
|
|
- background-color: $blue-light-color;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .host-view, .player-view {
|
|
|
- margin-top: $spacing-large;
|
|
|
- }
|
|
|
-
|
|
|
- .game-settings {
|
|
|
- background-color: $background-color-light;
|
|
|
- border-radius: $border-radius-small;
|
|
|
- padding: $spacing-base;
|
|
|
- margin-bottom: $spacing-base;
|
|
|
- box-shadow: $shadow-light;
|
|
|
-
|
|
|
- .setting-item {
|
|
|
- margin-bottom: $spacing-base;
|
|
|
-
|
|
|
- .setting-label {
|
|
|
- font-size: $font-size-small;
|
|
|
- color: $text-color-secondary;
|
|
|
- margin-bottom: $spacing-mini;
|
|
|
- font-weight: $font-weight-medium;
|
|
|
- }
|
|
|
-
|
|
|
- .setting-value {
|
|
|
- padding: $spacing-base 0;
|
|
|
- border-bottom: 1px solid $border-color-light;
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- font-size: $font-size-medium;
|
|
|
- color: $text-color-primary;
|
|
|
-
|
|
|
- &:active {
|
|
|
- background-color: $background-color-gray;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .difficulty-options {
|
|
|
- margin-top: $spacing-base;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .game-info {
|
|
|
- background-color: $background-color-light;
|
|
|
- border-radius: $border-radius-small;
|
|
|
- padding: $spacing-base;
|
|
|
- margin-bottom: $spacing-base;
|
|
|
- box-shadow: $shadow-light;
|
|
|
-
|
|
|
- .info-card {
|
|
|
- .game-title {
|
|
|
- font-size: $font-size-medium;
|
|
|
- font-weight: $font-weight-medium;
|
|
|
- color: $text-color-primary;
|
|
|
- margin-bottom: $spacing-base;
|
|
|
- }
|
|
|
-
|
|
|
- .game-meta {
|
|
|
- display: flex;
|
|
|
- flex-wrap: wrap;
|
|
|
- margin-bottom: $spacing-large;
|
|
|
-
|
|
|
- .meta-item {
|
|
|
- flex: 1;
|
|
|
- min-width: 50%;
|
|
|
- margin-bottom: $spacing-base;
|
|
|
-
|
|
|
- .meta-label {
|
|
|
- font-size: $font-size-small;
|
|
|
- color: $text-color-secondary;
|
|
|
- margin-bottom: $spacing-mini;
|
|
|
- }
|
|
|
-
|
|
|
- .meta-value {
|
|
|
- font-size: $font-size-base;
|
|
|
- color: $text-color-primary;
|
|
|
- font-weight: $font-weight-medium;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .game-desc {
|
|
|
- font-size: $font-size-base;
|
|
|
- color: $text-color-regular;
|
|
|
- line-height: $line-height-loose;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .player-list {
|
|
|
- background-color: $background-color-light;
|
|
|
- border-radius: $border-radius-small;
|
|
|
- padding: $spacing-base;
|
|
|
- margin-bottom: $spacing-base;
|
|
|
- box-shadow: $shadow-light;
|
|
|
-
|
|
|
- .players {
|
|
|
- .player-item {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- padding: $spacing-base 0;
|
|
|
- border-bottom: 1px solid $border-color-light;
|
|
|
-
|
|
|
- &:last-child {
|
|
|
- border-bottom: none;
|
|
|
- }
|
|
|
-
|
|
|
- &.is-host {
|
|
|
- background-color: rgba(255, 235, 210, 0.3); // 浅橙色背景
|
|
|
- border-radius: $border-radius-mini;
|
|
|
- padding: $spacing-base;
|
|
|
- }
|
|
|
-
|
|
|
- .player-avatar {
|
|
|
- width: 40px;
|
|
|
- height: 40px;
|
|
|
- margin-right: $spacing-base;
|
|
|
- border-radius: 50%;
|
|
|
- overflow: hidden;
|
|
|
-
|
|
|
- image {
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- border-radius: 50%;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .player-info {
|
|
|
- flex: 1;
|
|
|
-
|
|
|
- .player-name {
|
|
|
- font-size: $font-size-base;
|
|
|
- color: $text-color-primary;
|
|
|
- font-weight: $font-weight-medium;
|
|
|
- }
|
|
|
-
|
|
|
- .player-role {
|
|
|
- font-size: $font-size-small;
|
|
|
- color: $text-color-secondary;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .player-status {
|
|
|
- padding: $spacing-mini $spacing-base;
|
|
|
- border-radius: $border-radius-mini;
|
|
|
- font-size: $font-size-small;
|
|
|
- background-color: $background-color-gray;
|
|
|
- color: $text-color-secondary;
|
|
|
-
|
|
|
- &.ready {
|
|
|
- background-color: $success-color;
|
|
|
- color: white;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .action-buttons {
|
|
|
- margin-top: $spacing-large;
|
|
|
-
|
|
|
- .start-button, .ready-button {
|
|
|
- height: 44px;
|
|
|
- font-size: $font-size-medium;
|
|
|
- border-radius: $border-radius-base;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 选择器相关样式
|
|
|
- .selector-container {
|
|
|
- padding: $spacing-base;
|
|
|
-
|
|
|
- .selector-header {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- padding: $spacing-base 0;
|
|
|
- margin-bottom: $spacing-base;
|
|
|
- border-bottom: 1px solid $border-color-light;
|
|
|
-
|
|
|
- .selector-title {
|
|
|
- font-size: $font-size-medium;
|
|
|
- font-weight: $font-weight-medium;
|
|
|
- color: $text-color-primary;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .theme-scroll, .puzzle-scroll {
|
|
|
- border: 1px solid $border-color-light;
|
|
|
- border-radius: $border-radius-small;
|
|
|
- margin-top: $spacing-base;
|
|
|
- background-color: $background-color-light;
|
|
|
- }
|
|
|
-
|
|
|
- .theme-list, .puzzle-list, .difficulty-list {
|
|
|
- padding: $spacing-small;
|
|
|
-
|
|
|
- .theme-option, .puzzle-option, .difficulty-option {
|
|
|
- background-color: $background-color-base;
|
|
|
- padding: $spacing-base;
|
|
|
- border-radius: $border-radius-mini;
|
|
|
- margin-bottom: $spacing-small;
|
|
|
- box-shadow: $shadow-light;
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
-
|
|
|
- &:last-child {
|
|
|
- margin-bottom: 0;
|
|
|
- }
|
|
|
-
|
|
|
- &.disabled {
|
|
|
- opacity: 0.5;
|
|
|
- }
|
|
|
-
|
|
|
- &.selected {
|
|
|
- background-color: rgba(60, 146, 251, 0.1);
|
|
|
- }
|
|
|
-
|
|
|
- .option-content {
|
|
|
- flex: 1;
|
|
|
-
|
|
|
- .option-title {
|
|
|
- font-size: $font-size-base;
|
|
|
- color: $text-color-primary;
|
|
|
- margin-bottom: $spacing-mini;
|
|
|
- }
|
|
|
-
|
|
|
- .option-desc {
|
|
|
- font-size: $font-size-small;
|
|
|
- color: $text-color-secondary;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .theme-locked {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- margin-top: $spacing-mini;
|
|
|
- font-size: $font-size-small;
|
|
|
- color: $text-color-disabled;
|
|
|
-
|
|
|
- .lock-text {
|
|
|
- margin-left: $spacing-mini;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .unlock-button {
|
|
|
- margin-left: $spacing-mini;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
</style>
|