123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673 |
- // stores/games/turtlesoup.ts
- import { defineStore } from 'pinia'
- import { turtleSoupService } from '@/services/games/turtlesoup'
- import {
- type TurtleSoupGameHostView,
- type TurtleSoupGamePlayerView,
- type TurtleSoupQuestion,
- type TurtleSoupHint,
- 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', () => {
- // 基本状态
- 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
-
- 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 = ''
-
- // 重置游戏设置到默认值
- 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
-
- loading.value = true
- error.value = null
-
- try {
- const result = await turtleSoupService.getThemes()
-
- 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 unlockTheme(themeId: string) {
- const result = await turtleSoupService.unlockTheme(themeId)
- if (result.success) {
- return result
- }
- return null
- }
-
- // 加载可用的题目列表
- async function loadPuzzles(themeId: string, difficulty?: TurtleSoupDifficulty) {
- loading.value = true
- error.value = null
-
- try {
- const result = await turtleSoupService.getPuzzles(themeId, difficulty)
-
- 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
- }
- }
-
- // 加载主持人游戏视图
- async function loadHostGame(gameId: string) {
- loading.value = true
- error.value = null
- isHost.value = true
-
- try {
- const result = await turtleSoupService.getHostGameData(gameId)
-
- 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
-
- 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
-
- // 创建游戏
- const result = await turtleSoupService.createGame(settings)
-
- if (result.success && result.data) {
- return {
- success: true,
- gameId: result.data.gameId,
- roomId: result.data.roomId
- }
- } 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
- }
-
- submitting.value = true
- error.value = null
-
- try {
- const result = await turtleSoupService.startGame(hostView.value.id)
-
- if (result.success) {
- // 更新游戏状态
- if (hostView.value) {
- hostView.value = {
- ...hostView.value,
- status: TurtleSoupGameStatus.ACTIVE,
- startTime: Date.now(),
- currentTime: Date.now()
- }
- }
-
- 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
- }
-
- submitting.value = true
- error.value = null
-
- try {
- const userStore = useUserStore()
- const result = await turtleSoupService.submitQuestion(playerView.value.id, content)
-
- 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 (playerView.value) {
- playerView.value = {
- ...playerView.value,
- myQuestions: [...playerView.value.myQuestions, newQuestion]
- }
- }
-
- // 清空草稿
- 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
- }
-
- submitting.value = true
- error.value = null
-
- try {
- const result = await turtleSoupService.answerQuestion(questionId, answer)
-
- 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
- })
-
- hostView.value = {
- ...hostView.value,
- questions: updatedQuestions
- }
- }
- 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
- }
-
- submitting.value = true
- error.value = null
-
- try {
- const result = await turtleSoupService.revealHint(hostView.value.id, hintId)
-
- 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
- })
-
- hostView.value = {
- ...hostView.value,
- hints: updatedHints
- }
- }
- 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
-
- try {
- const result = await turtleSoupService.submitSolution(playerView.value.id, solution)
-
- if (result.success) {
- // 解答正确
- if (result.data?.correct) {
- return { success: true, correct: true }
- }
-
- // 解答错误
- 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
-
- try {
- const { gameId, ...resultData } = params
- const endResult = await turtleSoupService.endGame(gameId, resultData)
-
- 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()
- }
- }
-
- 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
-
- try {
- const result = await turtleSoupService.updateProgress(hostView.value.id, progress)
-
- if (result.success) {
- if (hostView.value) {
- hostView.value = {
- ...hostView.value,
- progress
- }
- }
- 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 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,
- unlockTheme,
- loadPuzzles,
- createGame,
- loadHostGame,
- loadPlayerGame,
- gameStatusToRoomStatus,
- startGame,
- submitQuestion,
- answerQuestion,
- revealHint,
- submitSolution,
- endGame,
- saveDraft,
- updateProgress,
- refreshGameData
- }
- })
|