Jelajahi Sumber

新增playertools组件

wuzj 11 jam lalu
induk
melakukan
c3e29cb823

+ 1 - 0
components.d.ts

@@ -30,6 +30,7 @@ declare module 'vue' {
     NutTabs: typeof import('@nutui/nutui-taro')['Tabs']
     NutTag: typeof import('@nutui/nutui-taro')['Tag']
     PlayerList: typeof import('./src/components/room/PlayerList.vue')['default']
+    PlayerTools: typeof import('./src/components/room/player/PlayerTools.vue')['default']
     PlayerView: typeof import('./src/components/room/player/PlayerView.vue')['default']
     RoomCode: typeof import('./src/components/room/RoomCode.vue')['default']
     RoomHeader: typeof import('./src/components/room/RoomHeader.vue')['default']

+ 17 - 11
src/components/room/host/gamesettings/TurtleSoupSettings.vue

@@ -57,7 +57,7 @@
                   <div class="theme-name">{{ theme.name }}</div>
                   <div class="theme-price">{{ theme.price }}</div>
                 </div>
-                <div class="theme-desc">{{ theme.desc }}</div>
+                <div class="theme-desc">{{ theme.description }}</div>
               </div>
               <div v-if="!theme.isLocked" class="theme-status theme-status-unlocked">
                 已解锁
@@ -86,7 +86,7 @@
               :type="selectedSettings.difficulty === diff.id ? 'primary' : 'default'"
               :color="selectedSettings.difficulty === diff.id ? '#FF9F2D' : ''"
               class="difficulty-btn"
-              @click="selectDifficulty(diff)">
+              @click="selectDifficulty(diff.id)">
               {{ diff.name }}
             </nut-button>
           </div>
@@ -137,9 +137,9 @@
                 @click="selectPuzzle(puzzle)">
               <div class="puzzle-header">
                 <div class="puzzle-name">{{ puzzle.title }}</div>
-                <div class="puzzle-meta">{{ difficultyName }} · {{ puzzle.duration }}</div>
+                <div class="puzzle-meta">{{ difficultyName }} · {{ puzzle.averageDuration }}分钟</div>
               </div>
-              <div class="puzzle-desc">{{ puzzle.desc }}</div>
+              <div class="puzzle-desc">{{ puzzle.scenario }}</div>
               <IconFont v-if="selectedSettings.puzzleId === puzzle.puzzleId" 
                        name="check" 
                        size="16" 
@@ -247,7 +247,7 @@ const getIconName = (theme: TurtleSoupTheme) => {
     'fantasy': 'magic'
   };
   
-  return iconMap[theme.id] || 'bookmark';
+  return iconMap[theme.themeId] || 'bookmark';
 };
 
 // 加载主题列表
@@ -263,9 +263,9 @@ const loadThemes = async () => {
       themes.value = themeData.map(theme => ({
         themeId: theme.themeId,
         name: theme.name,
-        price: theme.price ? `${theme.price}元/小时` : '免费',
-        desc: theme.description || '主题介绍',
-        iconId: theme.icon || 'bookmark',
+        description: theme.description || '主题介绍',
+        type: theme.type,
+        price: theme.price,
         isLocked: theme.isLocked === undefined ? false : theme.isLocked,
         isNew: theme.isNew === undefined ? false : theme.isNew
       }));
@@ -314,11 +314,17 @@ const loadPuzzles = async () => {
     if (puzzleData && puzzleData.length) {
       puzzles.value = puzzleData.map(puzzle => ({
         puzzleId: puzzle.puzzleId,
+        themeId: puzzle.themeId,
         title: puzzle.title || '未命名题目',
+        scenario: puzzle.scenario || '题目描述',
+        truth: puzzle.truth || '答案',
+        keyClues: puzzle.keyClues || ['关键线索1', '关键线索2'],
         difficulty: puzzle.difficulty,
-        duration: puzzle.averageDuration || '平均用时20分钟',
-        desc: puzzle.description || '题目描述',
-        themeId: puzzle.themeId
+        averageDuration: puzzle.averageDuration || 20,
+        price: puzzle.price || 0,
+        isNew: puzzle.isNew || false,
+        isLocked: puzzle.isLocked || false,
+        hints: puzzle.hints || [{ keyword: '提示1', sentence: '提示句子1' }]
       }));
       
       console.log('题目加载成功,数量:', puzzles.value.length);

+ 195 - 0
src/components/room/player/PlayerTools.vue

@@ -0,0 +1,195 @@
+// src/components/room/player/PlayerTools.vue
+<template>
+  <view class="player-tools">
+    <view class="card-title">解谜道具</view>
+    <view class="tool-description">解谜道具可以帮你更快地解开谜题,并获取隐藏线索。</view>
+    
+    <!-- 海龟汤游戏道具 -->
+    <template v-if="gameType === 'TURTLE_SOUP'">
+      <view class="tool-items">
+        <view class="tool-item" @click="showToolDetail('keyword')">
+          <view class="tool-icon">
+            <IconFont name="search" size="20"/>
+          </view>
+          <view class="tool-info">
+            <view class="tool-name">初级道具 - 关键词</view>
+            <view class="tool-desc">提示故事关键词,帮助理解故事要点</view>
+          </view>
+          <view class="tool-price">15元/小时</view>
+          <view class="tool-status" v-if="unlocked.includes('keyword')">已购买</view>
+          <view class="tool-action" v-else>
+            <nut-button size="mini" type="primary">购买</nut-button>
+          </view>
+        </view>
+        
+        <view class="tool-item" @click="showToolDetail('sentence')">
+          <view class="tool-icon">
+            <IconFont name="find" size="20"/>
+          </view>
+          <view class="tool-info">
+            <view class="tool-name">高级道具 - 关键线索</view>
+            <view class="tool-desc">直接提示一条关于谜题的关键线索</view>
+          </view>
+          <view class="tool-price">30元/小时</view>
+          <view class="tool-status" v-if="unlocked.includes('sentence')">已购买</view>
+          <view class="tool-action" v-else>
+            <nut-button size="mini" type="primary">购买</nut-button>
+          </view>
+        </view>
+      </view>
+      
+      <view class="tool-usage-info" v-if="currentTool">
+        <view class="usage-title">当前套餐:{{ currentToolName }} {{ currentTool.price }}元/小时</view>
+        <view class="usage-time">计时中:已使用 {{ usedTime }}分钟,剩余 {{ remainTime }}分钟</view>
+        <nut-button block class="extend-btn">延长套餐时间</nut-button>
+      </view>
+    </template>
+    
+    <!-- 其他游戏道具 -->
+    <template v-else>
+      <view class="empty-tools">该游戏暂无可用道具</view>
+    </template>
+  </view>
+</template>
+
+<script lang="ts" setup>
+import { ref, computed } from 'vue'
+import { IconFont } from '@nutui/icons-vue-taro'
+
+// 定义道具类型
+interface Tool {
+  id: string
+  name: string
+  description: string
+  price: number
+  isUnlocked: boolean
+}
+
+// 接收参数
+const props = defineProps({
+  gameType: {
+    type: String,
+    default: 'TURTLE_SOUP'
+  }
+})
+
+// 数据
+const unlocked = ref(['keyword']) // 已解锁的道具
+const currentTool = ref({
+  id: 'keyword',
+  name: '初级道具',
+  price: 15
+})
+const usedTime = ref(22)
+const remainTime = ref(38)
+
+// 计算属性
+const currentToolName = computed(() => {
+  return currentTool.value ? currentTool.value.name : ''
+})
+
+// 方法
+function showToolDetail(toolId: string) {
+  console.log('Show tool detail:', toolId)
+}
+</script>
+
+<style lang="scss" scoped>
+.player-tools {
+  padding: $spacing-medium;
+  
+  .card-title {
+    font-size: $font-size-medium;
+    font-weight: $font-weight-bold;
+    margin-bottom: $spacing-medium;
+    color: $text-color-primary;
+  }
+  
+  .tool-description {
+    font-size: $font-size-small;
+    color: $text-color-secondary;
+    margin-bottom: $spacing-large;
+  }
+  
+  .tool-items {
+    .tool-item {
+      display: flex;
+      align-items: center;
+      padding: $spacing-medium;
+      border-radius: $border-radius-small;
+      background-color: $background-color-light;
+      margin-bottom: $spacing-medium;
+      box-shadow: $shadow-light;
+      
+      .tool-icon {
+        width: 36px;
+        height: 36px;
+        border-radius: $border-radius-circle;
+        background-color: $background-color-blue;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        margin-right: $spacing-medium;
+        color: $primary-color;
+      }
+      
+      .tool-info {
+        flex: 1;
+        
+        .tool-name {
+          font-size: $font-size-base;
+          font-weight: $font-weight-medium;
+          color: $text-color-primary;
+        }
+        
+        .tool-desc {
+          font-size: $font-size-small;
+          color: $text-color-secondary;
+          margin-top: $spacing-small;
+        }
+      }
+      
+      .tool-price {
+        font-size: $font-size-small;
+        color: $text-color-secondary;
+        margin-right: $spacing-medium;
+      }
+      
+      .tool-status {
+        font-size: $font-size-small;
+        color: $success-color;
+      }
+    }
+  }
+  
+  .tool-usage-info {
+    background-color: $background-color-light;
+    border-radius: $border-radius-small;
+    padding: $spacing-large;
+    margin-top: $spacing-large;
+    
+    .usage-title {
+      font-size: $font-size-base;
+      color: $text-color-primary;
+      margin-bottom: $spacing-medium;
+    }
+    
+    .usage-time {
+      font-size: $font-size-small;
+      color: $text-color-secondary;
+      margin-bottom: $spacing-large;
+    }
+    
+    .extend-btn {
+      margin-top: $spacing-medium;
+    }
+  }
+  
+  .empty-tools {
+    text-align: center;
+    padding: $spacing-xlarge;
+    color: $text-color-secondary;
+    font-size: $font-size-base;
+  }
+}
+</style>

+ 193 - 26
src/pages/room/play/index.vue

@@ -50,7 +50,11 @@
       </view>
       <!-- 设置弹窗 -->
       <nut-dialog v-model:visible="showSettings" title="更换主题">
-        <TurtleSoupSettings @close="showSettings = false"/>
+        <GameSettings 
+          :gameType="gameType" 
+          @settings-change="handleSettingsChange"
+          @close="showSettings = false"
+        />
       </nut-dialog>
     </template>
 
@@ -81,56 +85,220 @@
           <view v-if="revealedCluesList.length === 0" class="no-clues">暂无线索</view>
         </view>
       </view>
-      <!-- 关键词道具解锁(占位) -->
-      <view class="card tool-card">
-        <view class="card-title">关键词道具</view>
-        <nut-button block type="primary" @click="showUnlockTools = true">解锁关键词提示</nut-button>
-      </view>
-      <!-- 道具解锁弹窗(占位) -->
-      <nut-dialog v-model:visible="showUnlockTools" title="解锁道具">
-        <view style="padding:24px;text-align:center;color:#888;">功能开发中,敬请期待!</view>
-      </nut-dialog>
+      
+      <!-- 玩家道具区域 -->
+      <PlayerTools :gameType="gameType" />
     </template>
   </view>
 </template>
 
 <script lang="ts" setup>
-import { ref, computed } from 'vue'
+import Taro from '@tarojs/taro'
+import { ref, computed, onMounted, onUnmounted } from 'vue'
 import { useTurtleSoupStore } from '@/stores/games/turtlesoup'
-import TurtleSoupSettings from '@/components/room/host/gamesettings/TurtleSoupSettings.vue'
+import { useRoomStore } from '@/stores/room'
+import { GameType } from '@/types/game'
+import { TurtleSoupGameStatus } from '@/types/games/turtlesoup'
+import GameSettings from '@/components/room/host/GameSettings.vue'
+import PlayerTools from '@/components/room/player/PlayerTools.vue'
 
+// 初始化stores
 const turtleSoupStore = useTurtleSoupStore()
+const roomStore = useRoomStore()
+
+// 游戏和房间ID
+const gameId = ref('')
+const roomId = ref('')
+const gameType = ref(GameType.TURTLE_SOUP)
+
+// 判断是否为主持人
 const isHost = computed(() => turtleSoupStore.isHost)
+
+// 获取当前视图
 const currentView = computed(() => turtleSoupStore.currentView)
+
+// 游戏信息
 const gameTitle = computed(() => currentView.value?.title || '海龟汤')
 const puzzleTitle = computed(() => currentView.value?.puzzle?.title || '谜题')
 const scenario = computed(() => currentView.value?.puzzle?.scenario || '')
 const solution = computed(() => isHost.value ? currentView.value?.puzzle?.truth : '')
 const gameProgress = computed(() => turtleSoupStore.gameProgress)
 const gameDuration = computed(() => turtleSoupStore.gameDuration)
+
+// 游戏状态文本
 const statusText = computed(() => {
   switch(currentView.value?.status) {
-    case 'active': return '游戏进行中'
-    case 'waiting': return '准备中'
-    case 'completed': return '已完成'
-    default: return ''
+    case TurtleSoupGameStatus.ACTIVE: return '游戏进行中'
+    case TurtleSoupGameStatus.WAITING: return '准备中'
+    case TurtleSoupGameStatus.COMPLETED: return '已完成'
+    default: return '游戏进行中'
   }
 })
 
-// 关键线索(直接取puzzle.keyClues)
+// 关键线索
 const clues = computed(() => currentView.value?.puzzle?.keyClues || [])
-// 主持人已显示线索索引(假设用本地state控制,真实用store/后端同步)
-const revealedClues = ref<number[]>([0, 1]) // 示例,已显示前两条
-function revealClue(idx: number) {
-  if (!revealedClues.value.includes(idx)) revealedClues.value.push(idx)
-}
 
-// 玩家端公开线索(直接取keyClues中已公开的)
-const revealedCluesList = computed(() => clues.value.filter((_, idx) => revealedClues.value.includes(idx)))
+// 已显示的线索
+const revealedClues = ref<number[]>([])
+
+// 玩家端公开线索
+const revealedCluesList = computed(() => 
+  clues.value.filter((_, idx) => revealedClues.value.includes(idx))
+)
 
 // 弹窗控制
 const showSettings = ref(false)
-const showUnlockTools = ref(false)
+
+// 初始化页面
+const initPage = async () => {
+  // 获取路由参数中的房间ID和游戏ID
+  const pages = Taro.getCurrentPages()
+  const currentPage = pages[pages.length - 1]
+  const routeParams = currentPage.$taroParams
+  
+  if (routeParams && routeParams.gameId && routeParams.roomId) {
+    roomId.value = routeParams.roomId
+    gameId.value = routeParams.gameId
+    
+    // 加载游戏信息
+    await loadGameInfo(gameId.value, roomId.value)
+  } else {
+    Taro.showToast({
+      title: '参数错误',
+      icon: 'none'
+    })
+    // 延迟返回
+    setTimeout(() => {
+      Taro.navigateBack()
+    }, 1500)
+  }
+}
+
+// 加载游戏信息
+const loadGameInfo = async (gameId: string, roomId: string) => {
+  try {
+    Taro.showLoading({ title: '加载中...' })
+    
+    // 加载房间信息
+    await roomStore.loadRoomInfo(gameId, roomId)
+    
+    // 加载游戏信息
+    const result = await turtleSoupStore.loadGameInfo(gameId, roomId)
+    
+    if (result.success) {
+      // 更新已显示线索
+      if (result.revealedClues) {
+        revealedClues.value = result.revealedClues
+      }
+    } else {
+      throw new Error(result.message || '加载游戏信息失败')
+    }
+    
+    Taro.hideLoading()
+  } catch (error) {
+    console.error('加载游戏信息失败:', error)
+    Taro.showToast({
+      title: error instanceof Error ? error.message : '加载游戏信息失败',
+      icon: 'none'
+    })
+    Taro.hideLoading()
+  }
+}
+
+// 显示线索
+const revealClue = async (idx: number) => {
+  if (revealedClues.value.includes(idx)) return
+  
+  try {
+    Taro.showLoading({ title: '显示线索中...' })
+    
+    // 调用API显示线索
+    const result = await turtleSoupStore.revealClue(gameId.value, roomId.value, idx)
+    
+    if (result.success) {
+      revealedClues.value.push(idx)
+      // 重新排序
+      revealedClues.value.sort((a, b) => a - b)
+    } else {
+      throw new Error(result.message || '显示线索失败')
+    }
+    
+    Taro.hideLoading()
+  } catch (error) {
+    console.error('显示线索失败:', error)
+    Taro.showToast({
+      title: error instanceof Error ? error.message : '显示线索失败',
+      icon: 'none'
+    })
+    Taro.hideLoading()
+  }
+}
+
+// 处理设置变更
+const handleSettingsChange = async (settings) => {
+  try {
+    Taro.showLoading({ title: '更新设置中...' })
+    
+    // 调用API更新游戏设置
+    const result = await turtleSoupStore.updateGameSettings(gameId.value, roomId.value, settings)
+    
+    if (result.success) {
+      Taro.showToast({
+        title: '设置已更新',
+        icon: 'success'
+      })
+      
+      // 关闭设置窗口
+      showSettings.value = false
+      
+      // 刷新游戏信息
+      await loadGameInfo(gameId.value, roomId.value)
+    } else {
+      throw new Error(result.message || '更新设置失败')
+    }
+    
+    Taro.hideLoading()
+  } catch (error) {
+    console.error('更新设置失败:', error)
+    Taro.showToast({
+      title: error instanceof Error ? error.message : '更新设置失败',
+      icon: 'none'
+    })
+    Taro.hideLoading()
+  }
+}
+
+// 游戏数据监听器
+let gameInterval: NodeJS.Timeout | null = null
+
+// 开始监听游戏数据变化
+const startGameListener = () => {
+  // 定期刷新游戏状态
+  gameInterval = setInterval(async () => {
+    if (gameId.value && roomId.value) {
+      await loadGameInfo(gameId.value, roomId.value)
+    }
+  }, 5000) // 每5秒刷新一次
+}
+
+// 停止监听游戏变化
+const stopGameListener = () => {
+  if (gameInterval) {
+    clearInterval(gameInterval)
+    gameInterval = null
+  }
+}
+
+// 页面加载时初始化
+onMounted(() => {
+  initPage()
+  startGameListener()
+})
+
+// 页面卸载时停止监听
+onUnmounted(() => {
+  stopGameListener()
+})
 </script>
 
 <style lang="scss" scoped>
@@ -180,7 +348,6 @@ const showUnlockTools = ref(false)
   &.scenario-card { }
   &.solution-card { background: #fff6e3; }
   &.clue-card { }
-  &.tool-card { background: #f4faff; }
   &.player { background: #f4faff; }
   .card-title {
     font-size: 16px;

+ 65 - 0
src/services/games/turtlesoup.ts

@@ -224,5 +224,70 @@ export const turtleSoupService = {
       return new Promise(resolve => setTimeout(() => resolve(createSuccess({ success: true })), 200))
     }
     return cloudApi.call<{ success: boolean }>('updateTurtleSoupProgress', { gameId, progress })
+  },
+
+  async checkGameRole(gameId: string): Promise<Result<{ isHost: boolean, revealedClues: number[] }>> {
+    if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
+      return new Promise(resolve => setTimeout(() => {
+        resolve(createSuccess({ 
+          isHost: Math.random() > 0.5, 
+          revealedClues: [0, 1]  
+        }))
+      }, 300))
+    }
+    return cloudApi.call<{ isHost: boolean, revealedClues: number[] }>('checkTurtleSoupRole', { gameId })
+      .then(result => {
+        if (result.success && result.data) {
+          return createSuccess(result.data)
+        }
+        return createError(result.message || '检查游戏角色失败')
+      })
+      .catch(error => createError(error.message || '检查游戏角色失败'))
+  },
+
+  async revealClue(gameId: string, clueIndex: number): Promise<Result<{ success: boolean }>> {
+    if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
+      return new Promise(resolve => setTimeout(() => resolve(createSuccess({ success: true })), 200))
+    }
+    return cloudApi.call<{ success: boolean }>('revealTurtleSoupClue', { gameId, clueIndex })
+  },
+
+  async updateGameSettings(gameId: string, settings: TurtleSoupGameSettings): Promise<Result<{ success: boolean }>> {
+    if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
+      return new Promise(resolve => setTimeout(() => resolve(createSuccess({ success: true })), 200))
+    }
+    return cloudApi.call<{ success: boolean }>('updateTurtleSoupSettings', { gameId, settings })
+  },
+
+  async getThemePaymentParams(themeId: string): Promise<Result<any>> {
+    if (!themeId) return createError('主题ID不能为空')
+    
+    if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
+      // Mock支付参数
+      return new Promise(resolve => setTimeout(() => {
+        resolve(createSuccess({
+          timeStamp: `${Date.now()}`,
+          nonceStr: 'mock_nonce_str',
+          package: 'prepay_id=mock_prepay_id',
+          signType: 'MD5',
+          paySign: 'mock_pay_sign'
+        }))
+      }, 300))
+    }
+    
+    return cloudApi.call<{
+      timeStamp: string,
+      nonceStr: string,
+      package: string,
+      signType: string,
+      paySign: string
+    }>('getThemePaymentParams', { themeId })
+      .then(result => {
+        if (result.success && result.data) {
+          return createSuccess(result.data)
+        }
+        return createError(result.message || '获取支付参数失败')
+      })
+      .catch(error => createError(error.message || '获取支付参数失败'))
   }
 }

+ 128 - 6
src/stores/games/turtlesoup.ts

@@ -74,10 +74,6 @@ export const useTurtleSoupStore = defineStore('turtlesoup', () => {
     isHost.value = role === 'host'
   }
 
-  function updateGameSettings(settings: Partial<TurtleSoupGameSettings>) {
-    gameSettings.value = { ...gameSettings.value, ...settings }
-  }
-
   // 主题
   async function loadThemes() {
     if (availableThemes.value.length > 0) return availableThemes.value
@@ -271,6 +267,129 @@ export const useTurtleSoupStore = defineStore('turtlesoup', () => {
     return isHost.value ? loadHostGame(gameId) : loadPlayerGame(gameId)
   }
 
+  // 加载游戏信息 
+  async function loadGameInfo(gameId: string, roomId: string) {
+    try {
+      error.value = null
+      loading.value = true
+      
+      // 检查当前角色
+      const role = await turtleSoupService.checkGameRole(gameId)
+      
+      if (role.success && role.data) {
+        setViewType(role.data.isHost ? 'host' : 'player')
+        
+        // 根据角色加载相应的游戏视图
+        const loadResult = await refreshGameData(gameId)
+        
+        if (loadResult) {
+          return {
+            success: true,
+            revealedClues: role.data.revealedClues || []
+          }
+        } else {
+          return { success: false, message: error.value || '加载游戏信息失败' }
+        }
+      } else {
+        return { success: false, message: role.message || '检查游戏角色失败' }
+      }
+    } catch (e) {
+      error.value = e instanceof Error ? e.message : '加载游戏信息时发生错误'
+      return { success: false, message: error.value }
+    } finally {
+      loading.value = false
+    }
+  }
+
+  // 主持人显示线索
+  async function revealClue(gameId: string, roomId: string, clueIndex: number) {
+    if (!isHost.value || !hostView.value) {
+      return { success: false, message: '只有主持人可以显示线索' }
+    }
+    
+    submitting.value = true
+    error.value = null
+    
+    try {
+      const result = await turtleSoupService.revealClue(hostView.value.gameId, clueIndex)
+      
+      if (result.success) {
+        // 如果成功,刷新游戏数据
+        await refreshGameData(gameId)
+        return { success: true }
+      } else {
+        error.value = result.message || '显示线索失败'
+        return { success: false, message: error.value }
+      }
+    } catch (e) {
+      error.value = e instanceof Error ? e.message : '显示线索时发生错误'
+      return { success: false, message: error.value }
+    } finally {
+      submitting.value = false
+    }
+  }
+
+  // 主持人更新游戏设置
+  async function updateGameSettings(gameId: string, roomId: string, settings: Partial<TurtleSoupGameSettings>) {
+    if (!isHost.value || !hostView.value) {
+      return { success: false, message: '只有主持人可以更新游戏设置' }
+    }
+    
+    submitting.value = true
+    error.value = null
+    
+    try {
+      const result = await turtleSoupService.updateGameSettings(
+        hostView.value.gameId, 
+        { ...gameSettings.value, ...settings }
+      )
+      
+      if (result.success) {
+        // 更新本地游戏设置
+        gameSettings.value = { ...gameSettings.value, ...settings }
+        // 刷新游戏数据
+        await refreshGameData(gameId)
+        return { success: true }
+      } else {
+        error.value = result.message || '更新游戏设置失败'
+        return { success: false, message: error.value }
+      }
+    } catch (e) {
+      error.value = e instanceof Error ? e.message : '更新游戏设置时发生错误'
+      return { success: false, message: error.value }
+    } finally {
+      submitting.value = false
+    }
+  }
+
+  // 获取主题支付参数
+  async function getThemePaymentParams(themeId: string) {
+    if (!themeId) {
+      error.value = '主题ID不能为空'
+      return null
+    }
+    
+    error.value = null
+    loading.value = true
+    
+    try {
+      // 调用服务获取支付参数
+      const result = await turtleSoupService.getThemePaymentParams(themeId)
+      
+      if (result.success && result.data) {
+        return result.data
+      } else {
+        error.value = result.message || '获取支付参数失败'
+        return null
+      }
+    } catch (e) {
+      error.value = e instanceof Error ? e.message : '获取支付参数时发生错误'
+      return null
+    } finally {
+      loading.value = false
+    }
+  }
+
   return {
     // 状态
     hostView,
@@ -296,7 +415,6 @@ export const useTurtleSoupStore = defineStore('turtlesoup', () => {
     // 操作方法
     resetState,
     setViewType,
-    updateGameSettings,
     loadThemes,
     unlockTheme,
     loadPuzzles,
@@ -306,6 +424,10 @@ export const useTurtleSoupStore = defineStore('turtlesoup', () => {
     gameStatusToRoomStatus,
     startGame,
     updateProgress,
-    refreshGameData
+    refreshGameData,
+    loadGameInfo,
+    revealClue,
+    updateGameSettings,
+    getThemePaymentParams
   }
 })