|
@@ -1,6 +1,6 @@
|
|
|
<template>
|
|
|
<view class="waiting-room-page">
|
|
|
- <!-- 房间头部信息 -->
|
|
|
+ <!-- 房间头部信息 保持不变 -->
|
|
|
<view class="room-header">
|
|
|
<view class="room-title">
|
|
|
<view class="title">{{ currentRoom?.name || '等待房间' }}</view>
|
|
@@ -14,7 +14,7 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 房间码展示和分享 -->
|
|
|
+ <!-- 房间码展示和分享 保持不变 -->
|
|
|
<RoomCode
|
|
|
:code="currentRoom?.id || ''"
|
|
|
:password="currentRoom?.password"
|
|
@@ -33,7 +33,7 @@
|
|
|
游戏设置
|
|
|
</nut-divider>
|
|
|
|
|
|
- <!-- 主题选择 -->
|
|
|
+ <!-- 1. 主题选择 -->
|
|
|
<view class="setting-item">
|
|
|
<view class="setting-label">主题选择</view>
|
|
|
<nut-cell
|
|
@@ -46,12 +46,12 @@
|
|
|
</nut-cell>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 题目选择 -->
|
|
|
- <view class="setting-item" v-if="selectedThemeId">
|
|
|
- <view class="setting-label">题目选择</view>
|
|
|
+ <!-- 2. 难度选择 -->
|
|
|
+ <view class="setting-item">
|
|
|
+ <view class="setting-label">游戏难度</view>
|
|
|
<nut-cell
|
|
|
- :desc="selectedPuzzle?.text || '请选择游戏题目'"
|
|
|
- @click="showPuzzleSelector = true"
|
|
|
+ :desc="difficultyText"
|
|
|
+ @click="showDifficultySelector = true"
|
|
|
>
|
|
|
<template #link>
|
|
|
<IconFont name="right" size="16"></IconFont>
|
|
@@ -59,12 +59,12 @@
|
|
|
</nut-cell>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 难度选择 -->
|
|
|
- <view class="setting-item">
|
|
|
- <view class="setting-label">游戏难度</view>
|
|
|
+ <!-- 3. 题目选择 (只有当主题和难度都选择后才显示) -->
|
|
|
+ <view class="setting-item" v-if="selectedThemeId && selectedDifficulty">
|
|
|
+ <view class="setting-label">题目选择</view>
|
|
|
<nut-cell
|
|
|
- :desc="difficultyText"
|
|
|
- @click="showDifficultySelector = true"
|
|
|
+ :desc="selectedPuzzle?.text || '请选择游戏题目'"
|
|
|
+ @click="selectedThemeId ? showPuzzleSelector = true : null"
|
|
|
>
|
|
|
<template #link>
|
|
|
<IconFont name="right" size="16"></IconFont>
|
|
@@ -73,7 +73,7 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 玩家列表 -->
|
|
|
+ <!-- 玩家列表 保持不变 -->
|
|
|
<view class="player-list">
|
|
|
<nut-divider
|
|
|
content-position="center"
|
|
@@ -103,7 +103,7 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 主持人操作按钮 -->
|
|
|
+ <!-- 主持人操作按钮 保持不变 -->
|
|
|
<view class="action-buttons">
|
|
|
<nut-button
|
|
|
block
|
|
@@ -117,7 +117,7 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 玩家视图 -->
|
|
|
+ <!-- 玩家视图 保持不变 -->
|
|
|
<view v-else class="player-view">
|
|
|
<!-- 游戏信息展示 -->
|
|
|
<view class="game-info">
|
|
@@ -206,49 +206,22 @@
|
|
|
v-for="theme in themeOptions"
|
|
|
:key="theme.value"
|
|
|
class="theme-option"
|
|
|
- :class="{ 'disabled': theme.disabled, 'selected': selectedThemeId === theme.value }"
|
|
|
- @click="!theme.disabled && handleThemeSelect(theme)"
|
|
|
+ :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 class="lock-text">{{ theme.unlockRequirement }}</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
- <IconFont v-if="selectedThemeId === theme.value" name="check" color="#3C92FB" size="16"></IconFont>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </scroll-view>
|
|
|
- </view>
|
|
|
- </nut-popup>
|
|
|
-
|
|
|
- <!-- 题目选择弹窗 -->
|
|
|
- <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 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-if="selectedPuzzleId === puzzle.value" name="check" color="#3C92FB" size="16"></IconFont>
|
|
|
+ <IconFont v-else-if="selectedThemeId === theme.value" name="check" color="#3C92FB" size="16"></IconFont>
|
|
|
</view>
|
|
|
</view>
|
|
|
</scroll-view>
|
|
@@ -299,6 +272,37 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
</nut-popup>
|
|
|
+
|
|
|
+ <!-- 题目选择弹窗 -->
|
|
|
+ <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>
|
|
|
</view>
|
|
|
<Tabbar></Tabbar>
|
|
|
</template>
|
|
@@ -323,6 +327,7 @@ interface CascaderOption {
|
|
|
disabled?: boolean;
|
|
|
locked?: boolean;
|
|
|
unlockRequirement?: string;
|
|
|
+ price?: string; // 添加价格字段
|
|
|
children?: CascaderOption[];
|
|
|
}
|
|
|
|
|
@@ -349,6 +354,9 @@ export default {
|
|
|
// 房间ID
|
|
|
const roomId = ref('')
|
|
|
|
|
|
+ // 是否可以购买
|
|
|
+ const canPurchase = ref(true) // 默认允许购买
|
|
|
+
|
|
|
// 获取当前房间
|
|
|
const currentRoom = computed(() => roomStore.currentRoom)
|
|
|
|
|
@@ -517,7 +525,8 @@ export default {
|
|
|
description: theme.description,
|
|
|
disabled: theme.isLocked, // 根据是否解锁决定是否可选
|
|
|
locked: theme.isLocked,
|
|
|
- unlockRequirement: theme.unlockRequirement || '完成相关任务'
|
|
|
+ price: theme.price || '5', // 添加价格,默认5元
|
|
|
+ unlockRequirement: theme.isLocked ? (theme.unlockRequirement || '购买解锁') : ''
|
|
|
}))
|
|
|
console.log('已加载主题:', themeOptions.value)
|
|
|
}
|
|
@@ -571,6 +580,27 @@ 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) {
|
|
@@ -591,6 +621,73 @@ export default {
|
|
|
}, 300)
|
|
|
}
|
|
|
|
|
|
+ // 购买主题
|
|
|
+ const purchaseTheme = async (theme: CascaderOption) => {
|
|
|
+ try {
|
|
|
+ Taro.showLoading({ title: '准备支付...' })
|
|
|
+
|
|
|
+ // 调用微信支付接口
|
|
|
+ Taro.requestPayment({
|
|
|
+ timeStamp: Date.now().toString(),
|
|
|
+ nonceStr: Math.random().toString(36).substring(2, 15),
|
|
|
+ package: `prepay_id=wx${Date.now()}`,
|
|
|
+ signType: 'MD5',
|
|
|
+ paySign: 'test_sign', // 实际项目中需要服务端生成真实的支付参数
|
|
|
+ success: async () => {
|
|
|
+ // 支付成功后,解锁主题
|
|
|
+ Taro.hideLoading()
|
|
|
+ Taro.showLoading({ title: '解锁中...' })
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 调用解锁主题API
|
|
|
+ const result = await turtleSoupStore.unlockTheme(theme.value)
|
|
|
+
|
|
|
+ if (result.success) {
|
|
|
+ Taro.showToast({
|
|
|
+ title: '解锁成功',
|
|
|
+ icon: 'success'
|
|
|
+ })
|
|
|
+
|
|
|
+ // 更新主题列表
|
|
|
+ await loadThemes()
|
|
|
+
|
|
|
+ // 选择刚解锁的主题
|
|
|
+ const updatedTheme = themeOptions.value.find(t => t.value === theme.value)
|
|
|
+ if (updatedTheme && !updatedTheme.disabled) {
|
|
|
+ handleThemeSelect(updatedTheme)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ throw new Error('解锁主题失败')
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('解锁主题失败:', error)
|
|
|
+ Taro.showToast({
|
|
|
+ title: '解锁失败,请联系客服',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ } finally {
|
|
|
+ Taro.hideLoading()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fail: (err) => {
|
|
|
+ Taro.hideLoading()
|
|
|
+ console.log('支付失败:', err)
|
|
|
+ Taro.showToast({
|
|
|
+ title: '支付已取消',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } catch (error) {
|
|
|
+ Taro.hideLoading()
|
|
|
+ console.error('发起支付失败:', error)
|
|
|
+ Taro.showToast({
|
|
|
+ title: '支付发起失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 处理难度选择
|
|
|
const handleDifficultySelect = (difficulty: TurtleSoupDifficulty) => {
|
|
|
selectedDifficulty.value = difficulty
|
|
@@ -791,12 +888,15 @@ export default {
|
|
|
startGame,
|
|
|
handleCopy,
|
|
|
handleShare,
|
|
|
+ handleThemeClick,
|
|
|
handleThemeSelect,
|
|
|
handleDifficultySelect,
|
|
|
handlePuzzleSelect,
|
|
|
+ purchaseTheme,
|
|
|
handleAvatarError,
|
|
|
themeScrollHeight,
|
|
|
- puzzleScrollHeight
|
|
|
+ puzzleScrollHeight,
|
|
|
+ canPurchase
|
|
|
}
|
|
|
},
|
|
|
|
|
@@ -1102,6 +1202,10 @@ export default {
|
|
|
margin-left: $spacing-mini;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ .unlock-button {
|
|
|
+ margin-left: $spacing-mini;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|