|
@@ -2,430 +2,663 @@
|
|
|
import { defineStore } from 'pinia'
|
|
|
import { turtleSoupService } from '@/services/games/turtlesoup'
|
|
|
import {
|
|
|
- type TurtleSoupGame,
|
|
|
+ type TurtleSoupGameHostView,
|
|
|
+ type TurtleSoupGamePlayerView,
|
|
|
type TurtleSoupQuestion,
|
|
|
type TurtleSoupHint,
|
|
|
- type TurtleSoupGameResult,
|
|
|
- type TurtleSoupAnswerType
|
|
|
+ type TurtleSoupTheme,
|
|
|
+ type TurtleSoupPuzzle,
|
|
|
+ type TurtleSoupGameSettings,
|
|
|
+ TurtleSoupAnswerType,
|
|
|
+ TurtleSoupGameStatus,
|
|
|
+ TurtleSoupDifficulty
|
|
|
} from '@/types/games/turtlesoup'
|
|
|
import { useUserStore } from '@/stores/user'
|
|
|
+import { RoomStatus } from '@/types/room'
|
|
|
+import { ref, computed } from 'vue'
|
|
|
|
|
|
-export const useTurtleSoupStore = defineStore('turtlesoup', {
|
|
|
- state: () => ({
|
|
|
- currentGame: null as TurtleSoupGame | null,
|
|
|
- loading: false,
|
|
|
- submitting: false,
|
|
|
- error: null as string | null,
|
|
|
- userRole: 'player' as 'player' | 'storyteller',
|
|
|
- pendingQuestions: [] as TurtleSoupQuestion[], // 待回答的问题
|
|
|
- isSolved: false,
|
|
|
- // 用于本地临时存储
|
|
|
- localDraft: '', // 问题/解答草稿
|
|
|
- }),
|
|
|
-
|
|
|
- getters: {
|
|
|
- // 获取已公开的提示
|
|
|
- revealedHints(): TurtleSoupHint[] {
|
|
|
- if (!this.currentGame) return [];
|
|
|
- return this.currentGame.hints.filter(hint => hint.revealed);
|
|
|
- },
|
|
|
-
|
|
|
- // 获取未公开的提示
|
|
|
- unrevealedHints(): TurtleSoupHint[] {
|
|
|
- if (!this.currentGame) return [];
|
|
|
- return this.currentGame.hints.filter(hint => !hint.revealed);
|
|
|
- },
|
|
|
+export const useTurtleSoupStore = defineStore('turtlesoup', () => {
|
|
|
+ // 基本状态
|
|
|
+ const hostView = ref<TurtleSoupGameHostView | null>(null)
|
|
|
+ const playerView = ref<TurtleSoupGamePlayerView | null>(null)
|
|
|
+ const loading = ref(false)
|
|
|
+ const submitting = ref(false)
|
|
|
+ const error = ref<string | null>(null)
|
|
|
+ const isHost = ref(false)
|
|
|
+ const localDraft = ref('') // 问题/解答草稿
|
|
|
+
|
|
|
+ // 游戏设置 - 主持人创建或修改游戏时使用
|
|
|
+ const gameSettings = ref<TurtleSoupGameSettings>({
|
|
|
+ themeId: '',
|
|
|
+ puzzleId: '',
|
|
|
+ difficulty: TurtleSoupDifficulty.MEDIUM,
|
|
|
+ maxPlayers: 10,
|
|
|
+ isPrivate: false
|
|
|
+ })
|
|
|
+
|
|
|
+ // 可用主题列表
|
|
|
+ const availableThemes = ref<TurtleSoupTheme[]>([])
|
|
|
+
|
|
|
+ // 可用题目列表
|
|
|
+ const availablePuzzles = ref<TurtleSoupPuzzle[]>([])
|
|
|
+
|
|
|
+ // 计算属性
|
|
|
+ const currentView = computed(() => {
|
|
|
+ return isHost.value ? hostView.value : playerView.value
|
|
|
+ })
|
|
|
+
|
|
|
+ // 获取游戏状态
|
|
|
+ const gameStatus = computed(() => {
|
|
|
+ return currentView.value?.status || TurtleSoupGameStatus.CREATED
|
|
|
+ })
|
|
|
+
|
|
|
+ // 游戏是否激活
|
|
|
+ const isGameActive = computed(() => {
|
|
|
+ return gameStatus.value === TurtleSoupGameStatus.ACTIVE
|
|
|
+ })
|
|
|
+
|
|
|
+ // 获取已公开的提示
|
|
|
+ const revealedHints = computed(() => {
|
|
|
+ if (isHost.value && hostView.value) {
|
|
|
+ return hostView.value.hints.filter(hint => hint.revealed)
|
|
|
+ } else if (playerView.value) {
|
|
|
+ return playerView.value.revealedHints
|
|
|
+ }
|
|
|
+ return []
|
|
|
+ })
|
|
|
+
|
|
|
+ // 获取未公开的提示 (只有主持人可见)
|
|
|
+ const unrevealedHints = computed(() => {
|
|
|
+ if (isHost.value && hostView.value) {
|
|
|
+ return hostView.value.hints.filter(hint => !hint.revealed)
|
|
|
+ }
|
|
|
+ return []
|
|
|
+ })
|
|
|
+
|
|
|
+ // 获取排序后的问题列表(最新的在前)
|
|
|
+ const sortedQuestions = computed(() => {
|
|
|
+ if (isHost.value && hostView.value) {
|
|
|
+ return [...hostView.value.questions].sort((a, b) => b.timestamp - a.timestamp)
|
|
|
+ } else if (playerView.value) {
|
|
|
+ return [...playerView.value.allQuestions].sort((a, b) => b.timestamp - a.timestamp)
|
|
|
+ }
|
|
|
+ return []
|
|
|
+ })
|
|
|
+
|
|
|
+ // 获取待回答的问题(只有主持人可见)
|
|
|
+ const pendingQuestions = computed(() => {
|
|
|
+ if (isHost.value && hostView.value) {
|
|
|
+ return hostView.value.questions.filter(q => !q.answered)
|
|
|
+ .sort((a, b) => b.timestamp - a.timestamp)
|
|
|
+ }
|
|
|
+ return []
|
|
|
+ })
|
|
|
+
|
|
|
+ // 获取我的问题(玩家视图)
|
|
|
+ const myQuestions = computed(() => {
|
|
|
+ if (!isHost.value && playerView.value) {
|
|
|
+ return playerView.value.myQuestions.sort((a, b) => b.timestamp - a.timestamp)
|
|
|
+ }
|
|
|
+ return []
|
|
|
+ })
|
|
|
+
|
|
|
+ // 获取游戏时长(分钟)
|
|
|
+ const gameDuration = computed(() => {
|
|
|
+ const view = currentView.value
|
|
|
+ if (!view || !view.startTime) return 0
|
|
|
|
|
|
- // 获取排序后的问题列表(最新的在前)
|
|
|
- sortedQuestions(): TurtleSoupQuestion[] {
|
|
|
- if (!this.currentGame) return [];
|
|
|
- return [...this.currentGame.questions].sort((a, b) =>
|
|
|
- new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
|
|
|
- );
|
|
|
- },
|
|
|
+ return Math.floor(((view.currentTime || Date.now()) - view.startTime) / 60000)
|
|
|
+ })
|
|
|
+
|
|
|
+ // 获取游戏进度
|
|
|
+ const gameProgress = computed(() => {
|
|
|
+ return currentView.value?.progress || 0
|
|
|
+ })
|
|
|
+
|
|
|
+ // 获取房间代码
|
|
|
+ const roomCode = computed(() => {
|
|
|
+ return isHost.value && hostView.value ? hostView.value.roomCode : ''
|
|
|
+ })
|
|
|
+
|
|
|
+ // 游戏是否已结束
|
|
|
+ const isGameEnded = computed(() => {
|
|
|
+ return gameStatus.value === TurtleSoupGameStatus.COMPLETED ||
|
|
|
+ gameStatus.value === TurtleSoupGameStatus.ABANDONED
|
|
|
+ })
|
|
|
+
|
|
|
+ // Actions
|
|
|
+
|
|
|
+ // 重置状态
|
|
|
+ function resetState() {
|
|
|
+ hostView.value = null
|
|
|
+ playerView.value = null
|
|
|
+ loading.value = false
|
|
|
+ submitting.value = false
|
|
|
+ error.value = null
|
|
|
+ isHost.value = false
|
|
|
+ localDraft.value = ''
|
|
|
|
|
|
- // 游戏是否激活
|
|
|
- isGameActive(): boolean {
|
|
|
- return this.currentGame?.status === 'active';
|
|
|
- },
|
|
|
+ // 重置游戏设置到默认值
|
|
|
+ gameSettings.value = {
|
|
|
+ themeId: '',
|
|
|
+ puzzleId: '',
|
|
|
+ difficulty: TurtleSoupDifficulty.MEDIUM,
|
|
|
+ maxPlayers: 10,
|
|
|
+ isPrivate: false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置游戏视图类型
|
|
|
+ function setViewType(role: 'host' | 'player') {
|
|
|
+ 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
|
|
|
|
|
|
- // 当前用户是否为主持人
|
|
|
- isStoryteller(): boolean {
|
|
|
- if (!this.currentGame) return false;
|
|
|
- const userStore = useUserStore();
|
|
|
- return this.currentGame.storyteller === userStore.openid;
|
|
|
- },
|
|
|
+ loading.value = true
|
|
|
+ error.value = null
|
|
|
|
|
|
- // 获取游戏时长(秒)
|
|
|
- gameDuration(): number {
|
|
|
- if (!this.currentGame || !this.currentGame.startTime) return 0;
|
|
|
+ try {
|
|
|
+ const result = await turtleSoupService.getThemes()
|
|
|
|
|
|
- const start = new Date(this.currentGame.startTime).getTime();
|
|
|
- const end = this.currentGame.endTime
|
|
|
- ? new Date(this.currentGame.endTime).getTime()
|
|
|
- : Date.now();
|
|
|
+ if (result.success && result.data) {
|
|
|
+ availableThemes.value = result.data
|
|
|
+ return result.data
|
|
|
+ } else {
|
|
|
+ error.value = result.message || '加载主题失败'
|
|
|
+ return []
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('加载主题失败:', e)
|
|
|
+ error.value = e instanceof Error ? e.message : '未知错误'
|
|
|
+ return []
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载可用的题目列表
|
|
|
+ async function loadPuzzles(themeId: string, difficulty?: TurtleSoupDifficulty) {
|
|
|
+ loading.value = true
|
|
|
+ error.value = null
|
|
|
+
|
|
|
+ try {
|
|
|
+ const result = await turtleSoupService.getPuzzles(themeId, difficulty)
|
|
|
|
|
|
- return Math.floor((end - start) / 1000);
|
|
|
+ if (result.success && result.data) {
|
|
|
+ availablePuzzles.value = result.data
|
|
|
+ return result.data
|
|
|
+ } else {
|
|
|
+ error.value = result.message || '加载题目失败'
|
|
|
+ return []
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('加载题目失败:', e)
|
|
|
+ error.value = e instanceof Error ? e.message : '未知错误'
|
|
|
+ return []
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
}
|
|
|
- },
|
|
|
-
|
|
|
- actions: {
|
|
|
- // 重置状态
|
|
|
- resetState() {
|
|
|
- this.currentGame = null;
|
|
|
- this.loading = false;
|
|
|
- this.submitting = false;
|
|
|
- this.error = null;
|
|
|
- this.userRole = 'player';
|
|
|
- this.pendingQuestions = [];
|
|
|
- this.isSolved = false;
|
|
|
- this.localDraft = '';
|
|
|
- },
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载主持人游戏视图
|
|
|
+ async function loadHostGame(gameId: string) {
|
|
|
+ loading.value = true
|
|
|
+ error.value = null
|
|
|
+ isHost.value = true
|
|
|
|
|
|
- // 加载游戏数据
|
|
|
- async loadGame(gameId: string, role = 'player') {
|
|
|
- this.loading = true;
|
|
|
- this.error = null;
|
|
|
- this.userRole = role as 'player' | 'storyteller';
|
|
|
+ try {
|
|
|
+ const result = await turtleSoupService.getHostGameData(gameId)
|
|
|
|
|
|
- try {
|
|
|
- const result = await turtleSoupService.getGameData(gameId, role);
|
|
|
-
|
|
|
- if (result.success && result.data) {
|
|
|
- this.currentGame = result.data;
|
|
|
-
|
|
|
- // 如果是讲述者,找出待回答的问题
|
|
|
- if (role === 'storyteller') {
|
|
|
- this.pendingQuestions = result.data.questions.filter(q => !q.answered);
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
- } else {
|
|
|
- this.error = result.message || '加载游戏数据失败';
|
|
|
- return false;
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error('加载海龟汤游戏失败:', error);
|
|
|
- this.error = error instanceof Error ? error.message : '未知错误';
|
|
|
- return false;
|
|
|
- } finally {
|
|
|
- this.loading = false;
|
|
|
+ if (result.success && result.data) {
|
|
|
+ hostView.value = result.data
|
|
|
+ return true
|
|
|
+ } else {
|
|
|
+ error.value = result.message || '加载游戏数据失败'
|
|
|
+ return false
|
|
|
}
|
|
|
- },
|
|
|
+ } catch (e) {
|
|
|
+ console.error('加载主持人游戏视图失败:', e)
|
|
|
+ error.value = e instanceof Error ? e.message : '未知错误'
|
|
|
+ return false
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载玩家游戏视图
|
|
|
+ async function loadPlayerGame(gameId: string) {
|
|
|
+ loading.value = true
|
|
|
+ error.value = null
|
|
|
+ isHost.value = false
|
|
|
|
|
|
- // 提交问题
|
|
|
- async submitQuestion(content: string) {
|
|
|
- if (!this.currentGame || !content.trim()) {
|
|
|
- this.error = '无效的问题或游戏未加载';
|
|
|
- return false;
|
|
|
+ try {
|
|
|
+ const result = await turtleSoupService.getPlayerGameData(gameId)
|
|
|
+
|
|
|
+ if (result.success && result.data) {
|
|
|
+ playerView.value = result.data
|
|
|
+ return true
|
|
|
+ } else {
|
|
|
+ error.value = result.message || '加载游戏数据失败'
|
|
|
+ return false
|
|
|
}
|
|
|
+ } catch (e) {
|
|
|
+ console.error('加载玩家游戏视图失败:', e)
|
|
|
+ error.value = e instanceof Error ? e.message : '未知错误'
|
|
|
+ return false
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 转换游戏状态为房间状态
|
|
|
+ function gameStatusToRoomStatus(status: TurtleSoupGameStatus): RoomStatus {
|
|
|
+ switch (status) {
|
|
|
+ case TurtleSoupGameStatus.CREATED:
|
|
|
+ case TurtleSoupGameStatus.WAITING:
|
|
|
+ return RoomStatus.WAITING
|
|
|
+ case TurtleSoupGameStatus.ACTIVE:
|
|
|
+ return RoomStatus.PLAYING
|
|
|
+ case TurtleSoupGameStatus.COMPLETED:
|
|
|
+ case TurtleSoupGameStatus.ABANDONED:
|
|
|
+ return RoomStatus.ENDED
|
|
|
+ default:
|
|
|
+ return RoomStatus.WAITING
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建新游戏 - 只处理游戏部分的数据
|
|
|
+ async function createGame(settings: TurtleSoupGameSettings) {
|
|
|
+ submitting.value = true
|
|
|
+ error.value = null
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 保存游戏设置
|
|
|
+ gameSettings.value = settings
|
|
|
|
|
|
- this.submitting = true;
|
|
|
- this.error = null;
|
|
|
+ // 创建游戏
|
|
|
+ const result = await turtleSoupService.createGame(settings)
|
|
|
|
|
|
- try {
|
|
|
- const result = await turtleSoupService.submitQuestion(this.currentGame.id, content);
|
|
|
-
|
|
|
- if (result.success && result.data?.questionId) {
|
|
|
- // 获取用户信息
|
|
|
- const userStore = useUserStore();
|
|
|
-
|
|
|
- // 创建新问题对象
|
|
|
- const newQuestion: TurtleSoupQuestion = {
|
|
|
- id: result.data.questionId,
|
|
|
- content,
|
|
|
- askedBy: userStore.openid,
|
|
|
- askedByName: userStore.userInfo?.nickname,
|
|
|
- timestamp: new Date().toISOString(),
|
|
|
- answered: false
|
|
|
- };
|
|
|
-
|
|
|
- // 更新本地游戏状态
|
|
|
- if (this.currentGame) {
|
|
|
- this.currentGame = {
|
|
|
- ...this.currentGame,
|
|
|
- questions: [...this.currentGame.questions, newQuestion]
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- // 清空草稿
|
|
|
- this.localDraft = '';
|
|
|
- return true;
|
|
|
- } else {
|
|
|
- this.error = result.message || '提交问题失败';
|
|
|
- return false;
|
|
|
+ if (result.success && result.data) {
|
|
|
+ return {
|
|
|
+ success: true,
|
|
|
+ gameId: result.data.gameId,
|
|
|
+ roomId: result.data.roomId
|
|
|
}
|
|
|
- } catch (error) {
|
|
|
- console.error('提交问题失败:', error);
|
|
|
- this.error = error instanceof Error ? error.message : '提交问题时发生错误';
|
|
|
- return false;
|
|
|
- } finally {
|
|
|
- this.submitting = false;
|
|
|
+ } else {
|
|
|
+ error.value = result.message || '创建游戏失败'
|
|
|
+ return { success: false, message: error.value }
|
|
|
}
|
|
|
- },
|
|
|
+ } catch (e) {
|
|
|
+ console.error('创建游戏失败:', e)
|
|
|
+ error.value = e instanceof Error ? e.message : '创建游戏时发生错误'
|
|
|
+ return { success: false, message: error.value }
|
|
|
+ } finally {
|
|
|
+ submitting.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 开始游戏
|
|
|
+ async function startGame() {
|
|
|
+ if (!isHost.value || !hostView.value) {
|
|
|
+ error.value = '主持人视图未加载'
|
|
|
+ return false
|
|
|
+ }
|
|
|
|
|
|
- // 回答问题(讲述者)
|
|
|
- async answerQuestion(questionId: string, answer: TurtleSoupAnswerType) {
|
|
|
- if (!this.currentGame || this.userRole !== 'storyteller') {
|
|
|
- this.error = '无权限回答问题';
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- this.submitting = true;
|
|
|
- this.error = null;
|
|
|
+ submitting.value = true
|
|
|
+ error.value = null
|
|
|
+
|
|
|
+ try {
|
|
|
+ const result = await turtleSoupService.startGame(hostView.value.id)
|
|
|
|
|
|
- try {
|
|
|
- const result = await turtleSoupService.answerQuestion(questionId, answer);
|
|
|
-
|
|
|
- if (result.success && result.data?.success) {
|
|
|
- // 更新本地状态
|
|
|
- if (this.currentGame) {
|
|
|
- const updatedQuestions = this.currentGame.questions.map(q => {
|
|
|
- if (q.id === questionId) {
|
|
|
- return {
|
|
|
- ...q,
|
|
|
- answer,
|
|
|
- answered: true,
|
|
|
- answeredAt: new Date().toISOString()
|
|
|
- };
|
|
|
- }
|
|
|
- return q;
|
|
|
- });
|
|
|
-
|
|
|
- this.currentGame = {
|
|
|
- ...this.currentGame,
|
|
|
- questions: updatedQuestions
|
|
|
- };
|
|
|
-
|
|
|
- // 从待回答列表中移除
|
|
|
- this.pendingQuestions = this.pendingQuestions.filter(q => q.id !== questionId);
|
|
|
+ if (result.success) {
|
|
|
+ // 更新游戏状态
|
|
|
+ if (hostView.value) {
|
|
|
+ hostView.value = {
|
|
|
+ ...hostView.value,
|
|
|
+ status: TurtleSoupGameStatus.ACTIVE,
|
|
|
+ startTime: Date.now(),
|
|
|
+ currentTime: Date.now()
|
|
|
}
|
|
|
- return true;
|
|
|
- } else {
|
|
|
- this.error = result.message || '回答问题失败';
|
|
|
- return false;
|
|
|
}
|
|
|
- } catch (error) {
|
|
|
- console.error('回答问题失败:', error);
|
|
|
- this.error = error instanceof Error ? error.message : '回答问题时发生错误';
|
|
|
- return false;
|
|
|
- } finally {
|
|
|
- this.submitting = false;
|
|
|
+
|
|
|
+ return true
|
|
|
+ } else {
|
|
|
+ error.value = result.message || '开始游戏失败'
|
|
|
+ return false
|
|
|
}
|
|
|
- },
|
|
|
+ } catch (e) {
|
|
|
+ console.error('开始游戏失败:', e)
|
|
|
+ error.value = e instanceof Error ? e.message : '开始游戏时发生错误'
|
|
|
+ return false
|
|
|
+ } finally {
|
|
|
+ submitting.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提交问题 (玩家)
|
|
|
+ async function submitQuestion(content: string) {
|
|
|
+ if (!playerView.value || !content.trim()) {
|
|
|
+ error.value = '无效的问题或游戏未加载'
|
|
|
+ return false
|
|
|
+ }
|
|
|
|
|
|
- // 公开提示
|
|
|
- async revealHint(hintIndex: number) {
|
|
|
- if (!this.currentGame || this.userRole !== 'storyteller') {
|
|
|
- this.error = '无权限公开提示';
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- // 检查索引是否有效
|
|
|
- if (hintIndex < 0 || hintIndex >= (this.currentGame.hints?.length || 0)) {
|
|
|
- this.error = '无效的提示索引';
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- this.submitting = true;
|
|
|
- this.error = null;
|
|
|
+ submitting.value = true
|
|
|
+ error.value = null
|
|
|
+
|
|
|
+ try {
|
|
|
+ const userStore = useUserStore()
|
|
|
+ const result = await turtleSoupService.submitQuestion(playerView.value.id, content)
|
|
|
|
|
|
- try {
|
|
|
- const result = await turtleSoupService.revealHint(this.currentGame.id, hintIndex);
|
|
|
+ if (result.success && result.data) {
|
|
|
+ // 创建新问题对象
|
|
|
+ const newQuestion: TurtleSoupQuestion = {
|
|
|
+ id: result.data.questionId,
|
|
|
+ content,
|
|
|
+ askedBy: userStore.openid,
|
|
|
+ askedByName: userStore.nickname,
|
|
|
+ timestamp: Date.now(),
|
|
|
+ answered: false
|
|
|
+ }
|
|
|
|
|
|
- if (result.success && result.data?.success) {
|
|
|
- // 更新本地状态
|
|
|
- if (this.currentGame) {
|
|
|
- const updatedHints = this.currentGame.hints.map((hint, index) => {
|
|
|
- if (index === hintIndex) {
|
|
|
- return {
|
|
|
- ...hint,
|
|
|
- revealed: true,
|
|
|
- revealedAt: new Date().toISOString()
|
|
|
- };
|
|
|
- }
|
|
|
- return hint;
|
|
|
- });
|
|
|
-
|
|
|
- this.currentGame = {
|
|
|
- ...this.currentGame,
|
|
|
- hints: updatedHints
|
|
|
- };
|
|
|
+ // 更新本地玩家视图
|
|
|
+ if (playerView.value) {
|
|
|
+ playerView.value = {
|
|
|
+ ...playerView.value,
|
|
|
+ myQuestions: [...playerView.value.myQuestions, newQuestion]
|
|
|
}
|
|
|
- return true;
|
|
|
- } else {
|
|
|
- this.error = result.message || '公开提示失败';
|
|
|
- return false;
|
|
|
}
|
|
|
- } catch (error) {
|
|
|
- console.error('公开提示失败:', error);
|
|
|
- this.error = error instanceof Error ? error.message : '公开提示时发生错误';
|
|
|
- return false;
|
|
|
- } finally {
|
|
|
- this.submitting = false;
|
|
|
+
|
|
|
+ // 清空草稿
|
|
|
+ localDraft.value = ''
|
|
|
+ return true
|
|
|
+ } else {
|
|
|
+ error.value = result.message || '提交问题失败'
|
|
|
+ return false
|
|
|
}
|
|
|
- },
|
|
|
+ } catch (e) {
|
|
|
+ console.error('提交问题失败:', e)
|
|
|
+ error.value = e instanceof Error ? e.message : '提交问题时发生错误'
|
|
|
+ return false
|
|
|
+ } finally {
|
|
|
+ submitting.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 回答问题 (主持人)
|
|
|
+ async function answerQuestion(questionId: string, answer: TurtleSoupAnswerType) {
|
|
|
+ if (!isHost.value || !hostView.value) {
|
|
|
+ error.value = '主持人视图未加载'
|
|
|
+ return false
|
|
|
+ }
|
|
|
|
|
|
- // 提交解答
|
|
|
- async submitSolution(solution: string) {
|
|
|
- if (!this.currentGame || !solution.trim()) {
|
|
|
- this.error = '无效的解答或游戏未加载';
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- this.submitting = true;
|
|
|
- this.error = null;
|
|
|
+ submitting.value = true
|
|
|
+ error.value = null
|
|
|
+
|
|
|
+ try {
|
|
|
+ const result = await turtleSoupService.answerQuestion(questionId, answer)
|
|
|
|
|
|
- try {
|
|
|
- const result = await turtleSoupService.submitSolution(this.currentGame.id, solution);
|
|
|
-
|
|
|
- if (result.success) {
|
|
|
- // 如果答案正确
|
|
|
- if (result.data?.correct) {
|
|
|
- this.isSolved = true;
|
|
|
- // 获取用户信息
|
|
|
- const userStore = useUserStore();
|
|
|
-
|
|
|
- // 结束游戏
|
|
|
- await this.endGame({
|
|
|
- solved: true,
|
|
|
- solvedBy: userStore.openid
|
|
|
- });
|
|
|
-
|
|
|
- return { success: true, correct: true };
|
|
|
- }
|
|
|
+ if (result.success) {
|
|
|
+ // 更新本地状态
|
|
|
+ if (hostView.value) {
|
|
|
+ const updatedQuestions = hostView.value.questions.map(q => {
|
|
|
+ if (q.id === questionId) {
|
|
|
+ return {
|
|
|
+ ...q,
|
|
|
+ answer,
|
|
|
+ answered: true,
|
|
|
+ answeredAt: Date.now()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return q
|
|
|
+ })
|
|
|
|
|
|
- // 答案错误
|
|
|
- return { success: true, correct: false };
|
|
|
- } else {
|
|
|
- this.error = result.message || '提交解答失败';
|
|
|
- return { success: false, correct: false };
|
|
|
+ hostView.value = {
|
|
|
+ ...hostView.value,
|
|
|
+ questions: updatedQuestions
|
|
|
+ }
|
|
|
}
|
|
|
- } catch (error) {
|
|
|
- console.error('提交解答失败:', error);
|
|
|
- this.error = error instanceof Error ? error.message : '提交解答时发生错误';
|
|
|
- return { success: false, correct: false };
|
|
|
- } finally {
|
|
|
- this.submitting = false;
|
|
|
+ return true
|
|
|
+ } else {
|
|
|
+ error.value = result.message || '回答问题失败'
|
|
|
+ return false
|
|
|
}
|
|
|
- },
|
|
|
+ } catch (e) {
|
|
|
+ console.error('回答问题失败:', e)
|
|
|
+ error.value = e instanceof Error ? e.message : '回答问题时发生错误'
|
|
|
+ return false
|
|
|
+ } finally {
|
|
|
+ submitting.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 公开提示 (主持人)
|
|
|
+ async function revealHint(hintId: string) {
|
|
|
+ if (!isHost.value || !hostView.value) {
|
|
|
+ error.value = '主持人视图未加载'
|
|
|
+ return false
|
|
|
+ }
|
|
|
|
|
|
- // 结束游戏
|
|
|
- async endGame(result: { solved: boolean; solvedBy?: string }) {
|
|
|
- if (!this.currentGame) {
|
|
|
- this.error = '游戏未加载';
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- this.submitting = true;
|
|
|
- this.error = null;
|
|
|
+ submitting.value = true
|
|
|
+ error.value = null
|
|
|
+
|
|
|
+ try {
|
|
|
+ const result = await turtleSoupService.revealHint(hostView.value.id, hintId)
|
|
|
|
|
|
- try {
|
|
|
- const response = await turtleSoupService.endGame(this.currentGame.id, result);
|
|
|
-
|
|
|
- if (response.success && response.data) {
|
|
|
- // 更新游戏状态
|
|
|
- if (this.currentGame) {
|
|
|
- this.currentGame = {
|
|
|
- ...this.currentGame,
|
|
|
- status: 'completed',
|
|
|
- endTime: new Date().toISOString()
|
|
|
- };
|
|
|
- }
|
|
|
+ if (result.success) {
|
|
|
+ // 更新本地状态
|
|
|
+ if (hostView.value) {
|
|
|
+ const updatedHints = hostView.value.hints.map(hint => {
|
|
|
+ if (hint.id === hintId) {
|
|
|
+ return {
|
|
|
+ ...hint,
|
|
|
+ revealed: true,
|
|
|
+ revealedAt: Date.now()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return hint
|
|
|
+ })
|
|
|
|
|
|
- return response.data;
|
|
|
- } else {
|
|
|
- this.error = response.message || '结束游戏失败';
|
|
|
- return null;
|
|
|
+ hostView.value = {
|
|
|
+ ...hostView.value,
|
|
|
+ hints: updatedHints
|
|
|
+ }
|
|
|
}
|
|
|
- } catch (error) {
|
|
|
- console.error('结束游戏失败:', error);
|
|
|
- this.error = error instanceof Error ? error.message : '结束游戏时发生错误';
|
|
|
- return null;
|
|
|
- } finally {
|
|
|
- this.submitting = false;
|
|
|
+ return true
|
|
|
+ } else {
|
|
|
+ error.value = result.message || '公开提示失败'
|
|
|
+ return false
|
|
|
}
|
|
|
- },
|
|
|
+ } catch (e) {
|
|
|
+ console.error('公开提示失败:', e)
|
|
|
+ error.value = e instanceof Error ? e.message : '公开提示时发生错误'
|
|
|
+ return false
|
|
|
+ } finally {
|
|
|
+ submitting.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提交解答 (玩家)
|
|
|
+ async function submitSolution(solution: string) {
|
|
|
+ if (!playerView.value || !solution.trim()) {
|
|
|
+ error.value = '无效的解答或游戏未加载'
|
|
|
+ return { success: false, correct: false }
|
|
|
+ }
|
|
|
+
|
|
|
+ submitting.value = true
|
|
|
+ error.value = null
|
|
|
|
|
|
- // 创建新游戏
|
|
|
- async createGame(gameData: {
|
|
|
- title: string;
|
|
|
- description: string;
|
|
|
- solution: string;
|
|
|
- hints: string[];
|
|
|
- difficulty: string;
|
|
|
- }) {
|
|
|
- this.submitting = true;
|
|
|
- this.error = null;
|
|
|
+ try {
|
|
|
+ const result = await turtleSoupService.submitSolution(playerView.value.id, solution)
|
|
|
|
|
|
- try {
|
|
|
- const result = await turtleSoupService.createGame(gameData);
|
|
|
-
|
|
|
- if (result.success && result.data?.gameId) {
|
|
|
- // 成功创建游戏
|
|
|
- return result.data.gameId;
|
|
|
- } else {
|
|
|
- this.error = result.message || '创建游戏失败';
|
|
|
- return null;
|
|
|
+ if (result.success) {
|
|
|
+ // 解答正确
|
|
|
+ if (result.data?.correct) {
|
|
|
+ return { success: true, correct: true }
|
|
|
}
|
|
|
- } catch (error) {
|
|
|
- console.error('创建游戏失败:', error);
|
|
|
- this.error = error instanceof Error ? error.message : '创建游戏时发生错误';
|
|
|
- return null;
|
|
|
- } finally {
|
|
|
- this.submitting = false;
|
|
|
+
|
|
|
+ // 解答错误
|
|
|
+ return { success: true, correct: false }
|
|
|
+ } else {
|
|
|
+ error.value = result.message || '提交解答失败'
|
|
|
+ return { success: false, correct: false }
|
|
|
}
|
|
|
- },
|
|
|
+ } catch (e) {
|
|
|
+ console.error('提交解答失败:', e)
|
|
|
+ error.value = e instanceof Error ? e.message : '提交解答时发生错误'
|
|
|
+ return { success: false, correct: false }
|
|
|
+ } finally {
|
|
|
+ submitting.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 结束游戏 - 只更新状态,不处理房间
|
|
|
+ async function endGame(params: {
|
|
|
+ gameId: string,
|
|
|
+ solved: boolean,
|
|
|
+ solvedBy?: string,
|
|
|
+ solvedByName?: string,
|
|
|
+ solution?: string
|
|
|
+ }) {
|
|
|
+ submitting.value = true
|
|
|
+ error.value = null
|
|
|
|
|
|
- // 获取用户创建的游戏列表
|
|
|
- async fetchCreatedGames() {
|
|
|
- this.loading = true;
|
|
|
- this.error = null;
|
|
|
+ try {
|
|
|
+ const { gameId, ...resultData } = params
|
|
|
+ const endResult = await turtleSoupService.endGame(gameId, resultData)
|
|
|
|
|
|
- try {
|
|
|
- const result = await turtleSoupService.getCreatedGames();
|
|
|
-
|
|
|
- if (result.success) {
|
|
|
- return result.data || [];
|
|
|
- } else {
|
|
|
- this.error = result.message || '获取创建的游戏列表失败';
|
|
|
- return [];
|
|
|
+ if (endResult.success && endResult.data) {
|
|
|
+ // 更新游戏状态
|
|
|
+ if (isHost.value && hostView.value && hostView.value.id === gameId) {
|
|
|
+ hostView.value = {
|
|
|
+ ...hostView.value,
|
|
|
+ status: TurtleSoupGameStatus.COMPLETED,
|
|
|
+ currentTime: Date.now()
|
|
|
+ }
|
|
|
+ } else if (playerView.value && playerView.value.id === gameId) {
|
|
|
+ playerView.value = {
|
|
|
+ ...playerView.value,
|
|
|
+ status: TurtleSoupGameStatus.COMPLETED,
|
|
|
+ currentTime: Date.now()
|
|
|
+ }
|
|
|
}
|
|
|
- } catch (error) {
|
|
|
- console.error('获取创建的游戏列表失败:', error);
|
|
|
- this.error = error instanceof Error ? error.message : '获取游戏列表时发生错误';
|
|
|
- return [];
|
|
|
- } finally {
|
|
|
- this.loading = false;
|
|
|
+
|
|
|
+ return endResult.data
|
|
|
+ } else {
|
|
|
+ error.value = endResult.message || '结束游戏失败'
|
|
|
+ return null
|
|
|
}
|
|
|
- },
|
|
|
+ } catch (e) {
|
|
|
+ console.error('结束游戏失败:', e)
|
|
|
+ error.value = e instanceof Error ? e.message : '结束游戏时发生错误'
|
|
|
+ return null
|
|
|
+ } finally {
|
|
|
+ submitting.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 保存问题草稿
|
|
|
+ function saveDraft(content: string) {
|
|
|
+ localDraft.value = content
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新游戏进度 (主持人)
|
|
|
+ async function updateProgress(progress: number) {
|
|
|
+ if (!isHost.value || !hostView.value) {
|
|
|
+ error.value = '主持人视图未加载'
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ submitting.value = true
|
|
|
|
|
|
- // 获取用户参与的游戏列表
|
|
|
- async fetchJoinedGames() {
|
|
|
- this.loading = true;
|
|
|
- this.error = null;
|
|
|
+ try {
|
|
|
+ const result = await turtleSoupService.updateProgress(hostView.value.id, progress)
|
|
|
|
|
|
- try {
|
|
|
- const result = await turtleSoupService.getJoinedGames();
|
|
|
-
|
|
|
- if (result.success) {
|
|
|
- return result.data || [];
|
|
|
- } else {
|
|
|
- this.error = result.message || '获取参与的游戏列表失败';
|
|
|
- return [];
|
|
|
+ if (result.success) {
|
|
|
+ if (hostView.value) {
|
|
|
+ hostView.value = {
|
|
|
+ ...hostView.value,
|
|
|
+ progress
|
|
|
+ }
|
|
|
}
|
|
|
- } catch (error) {
|
|
|
- console.error('获取参与的游戏列表失败:', error);
|
|
|
- this.error = error instanceof Error ? error.message : '获取游戏列表时发生错误';
|
|
|
- return [];
|
|
|
- } finally {
|
|
|
- this.loading = false;
|
|
|
+ return true
|
|
|
+ } else {
|
|
|
+ error.value = result.message || '更新游戏进度失败'
|
|
|
+ return false
|
|
|
}
|
|
|
- },
|
|
|
-
|
|
|
- // 保存问题草稿
|
|
|
- saveDraft(content: string) {
|
|
|
- this.localDraft = content;
|
|
|
+ } catch (e) {
|
|
|
+ console.error('更新游戏进度失败:', e)
|
|
|
+ error.value = e instanceof Error ? e.message : '更新进度时发生错误'
|
|
|
+ return false
|
|
|
+ } finally {
|
|
|
+ submitting.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 刷新游戏数据
|
|
|
+ async function refreshGameData(gameId: string) {
|
|
|
+ if (isHost.value) {
|
|
|
+ return loadHostGame(gameId)
|
|
|
+ } else {
|
|
|
+ return loadPlayerGame(gameId)
|
|
|
}
|
|
|
}
|
|
|
-});
|
|
|
+
|
|
|
+ return {
|
|
|
+ // 状态
|
|
|
+ hostView,
|
|
|
+ playerView,
|
|
|
+ loading,
|
|
|
+ submitting,
|
|
|
+ error,
|
|
|
+ isHost,
|
|
|
+ localDraft,
|
|
|
+ gameSettings,
|
|
|
+ availableThemes,
|
|
|
+ availablePuzzles,
|
|
|
+
|
|
|
+ // 计算属性
|
|
|
+ currentView,
|
|
|
+ gameStatus,
|
|
|
+ isGameActive,
|
|
|
+ isGameEnded,
|
|
|
+ revealedHints,
|
|
|
+ unrevealedHints,
|
|
|
+ sortedQuestions,
|
|
|
+ pendingQuestions,
|
|
|
+ myQuestions,
|
|
|
+ gameDuration,
|
|
|
+ gameProgress,
|
|
|
+ roomCode,
|
|
|
+
|
|
|
+ // 操作方法
|
|
|
+ resetState,
|
|
|
+ setViewType,
|
|
|
+ updateGameSettings,
|
|
|
+ loadThemes,
|
|
|
+ loadPuzzles,
|
|
|
+ createGame,
|
|
|
+ loadHostGame,
|
|
|
+ loadPlayerGame,
|
|
|
+ gameStatusToRoomStatus,
|
|
|
+ startGame,
|
|
|
+ submitQuestion,
|
|
|
+ answerQuestion,
|
|
|
+ revealHint,
|
|
|
+ submitSolution,
|
|
|
+ endGame,
|
|
|
+ saveDraft,
|
|
|
+ updateProgress,
|
|
|
+ refreshGameData
|
|
|
+ }
|
|
|
+})
|