|
@@ -3,204 +3,423 @@ import { Result, createSuccess, createError } from '@/types/result'
|
|
import { cloudApi } from '@/api'
|
|
import { cloudApi } from '@/api'
|
|
import { USE_MOCK } from '@/services'
|
|
import { USE_MOCK } from '@/services'
|
|
import {
|
|
import {
|
|
- type TurtleSoupGame,
|
|
|
|
- type TurtleSoupQuestion,
|
|
|
|
|
|
+ type TurtleSoupGameHostView,
|
|
|
|
+ type TurtleSoupGamePlayerView,
|
|
|
|
+ type TurtleSoupQuestion,
|
|
|
|
+ type TurtleSoupHint,
|
|
|
|
+ type TurtleSoupGameSettings,
|
|
type TurtleSoupGameResult,
|
|
type TurtleSoupGameResult,
|
|
- type TurtleSoupGameStatus,
|
|
|
|
- type TurtleSoupDifficulty,
|
|
|
|
- type CreateTurtleSoupGameParams
|
|
|
|
|
|
+ type TurtleSoupTheme,
|
|
|
|
+ type TurtleSoupPuzzle,
|
|
|
|
+ TurtleSoupGameStatus,
|
|
|
|
+ TurtleSoupDifficulty,
|
|
|
|
+ TurtleSoupAnswerType,
|
|
|
|
+ TurtleSoupThemeType
|
|
} from '@/types/games/turtlesoup'
|
|
} from '@/types/games/turtlesoup'
|
|
|
|
|
|
-// Mock数据
|
|
|
|
-const mockGame: TurtleSoupGame = {
|
|
|
|
- id: 'mock-ts-1',
|
|
|
|
- title: '死亡的摄影师',
|
|
|
|
- description: '一个摄影师在自己的工作室里死亡,周围没有任何人,死因是什么?',
|
|
|
|
- storyteller: 'user-123',
|
|
|
|
- status: 'active',
|
|
|
|
- solution: '这个摄影师在深海拍摄鲨鱼时,使用了闪光灯,引来了鲨鱼攻击并死亡。',
|
|
|
|
- difficulty: 'medium',
|
|
|
|
- createTime: new Date().toISOString(),
|
|
|
|
|
|
+// Mock 主题数据
|
|
|
|
+const mockThemes: TurtleSoupTheme[] = [
|
|
|
|
+ {
|
|
|
|
+ id: 'theme-1',
|
|
|
|
+ name: '经典解谜',
|
|
|
|
+ description: '基础主题 · 免费',
|
|
|
|
+ type: TurtleSoupThemeType.BASIC,
|
|
|
|
+ isLocked: false
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'theme-2',
|
|
|
|
+ name: '环球影城',
|
|
|
|
+ description: '特色主题 · 20元/小时',
|
|
|
|
+ type: TurtleSoupThemeType.PREMIUM,
|
|
|
|
+ price: 20,
|
|
|
|
+ isNew: true,
|
|
|
|
+ isLocked: true
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'theme-3',
|
|
|
|
+ name: '迪士尼奇幻',
|
|
|
|
+ description: '特色主题 · 15元/小时',
|
|
|
|
+ type: TurtleSoupThemeType.PREMIUM,
|
|
|
|
+ price: 15,
|
|
|
|
+ isLocked: true
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'theme-4',
|
|
|
|
+ name: '奇幻冒险',
|
|
|
|
+ description: '特色主题 · 12元/小时',
|
|
|
|
+ type: TurtleSoupThemeType.PREMIUM,
|
|
|
|
+ price: 12,
|
|
|
|
+ isLocked: true
|
|
|
|
+ }
|
|
|
|
+]
|
|
|
|
+
|
|
|
|
+// Mock 题目数据
|
|
|
|
+const mockPuzzles: TurtleSoupPuzzle[] = [
|
|
|
|
+ {
|
|
|
|
+ id: 'puzzle-1',
|
|
|
|
+ title: '神秘的手表',
|
|
|
|
+ description: '简单 · 平均用时25分钟',
|
|
|
|
+ difficulty: TurtleSoupDifficulty.EASY,
|
|
|
|
+ averageDuration: 25
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'puzzle-2',
|
|
|
|
+ title: '迷路的青蛙',
|
|
|
|
+ description: '中等 · 平均用时35分钟',
|
|
|
|
+ difficulty: TurtleSoupDifficulty.MEDIUM,
|
|
|
|
+ averageDuration: 35
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'puzzle-3',
|
|
|
|
+ title: '消失的邮轮',
|
|
|
|
+ description: '困难 · 平均用时50分钟',
|
|
|
|
+ difficulty: TurtleSoupDifficulty.HARD,
|
|
|
|
+ averageDuration: 50
|
|
|
|
+ }
|
|
|
|
+]
|
|
|
|
+
|
|
|
|
+// Mock 主持人视图数据
|
|
|
|
+const mockHostView: TurtleSoupGameHostView = {
|
|
|
|
+ id: 'game-1',
|
|
|
|
+ roomId: 'room-1',
|
|
|
|
+ title: '欢乐海龟汤',
|
|
|
|
+ roomCode: 'ABC123',
|
|
|
|
+ description: '一个男人收到了一块神秘的手表,戴上后就再也无法取下来,一周后他自杀了,为什么?',
|
|
|
|
+ solution: '这个手表可以预知未来24小时内将发生的事情。男人看到了自己将在一周后死亡,尝试了各种方法改变命运但都失败了。最终,由于无法承受这种预知但无法改变的煎熬,他选择了自杀。这反而实现了手表的预言。',
|
|
hints: [
|
|
hints: [
|
|
- { content: '死亡地点不是工作室', revealed: false },
|
|
|
|
- { content: '摄影师当时正在进行水下摄影', revealed: false },
|
|
|
|
- { content: '死亡与水中的生物有关', revealed: false }
|
|
|
|
|
|
+ {
|
|
|
|
+ id: 'hint-1',
|
|
|
|
+ content: '这块手表有特殊功能,不是普通手表。',
|
|
|
|
+ revealed: true,
|
|
|
|
+ revealedAt: Date.now() - 600000 // 10分钟前
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'hint-2',
|
|
|
|
+ content: '手表可以显示未来将发生的事情。',
|
|
|
|
+ revealed: true,
|
|
|
|
+ revealedAt: Date.now() - 300000 // 5分钟前
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'hint-3',
|
|
|
|
+ content: '男人尝试了多种方法改命运,但都失败了。',
|
|
|
|
+ revealed: false
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'hint-4',
|
|
|
|
+ content: '手表预测的是他的死亡,但没有预测到真体方式。',
|
|
|
|
+ revealed: false
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'hint-5',
|
|
|
|
+ content: '手表的预言总是会实现,但方式可能有所不同。',
|
|
|
|
+ revealed: false
|
|
|
|
+ }
|
|
|
|
+ ],
|
|
|
|
+ questions: [
|
|
|
|
+ {
|
|
|
|
+ id: 'q-1',
|
|
|
|
+ content: '手表是有特殊功能的吗?',
|
|
|
|
+ askedBy: 'user-1',
|
|
|
|
+ askedByName: '小明',
|
|
|
|
+ timestamp: Date.now() - 900000, // 15分钟前
|
|
|
|
+ answered: true,
|
|
|
|
+ answer: TurtleSoupAnswerType.YES,
|
|
|
|
+ answeredAt: Date.now() - 890000 // 14分50秒前
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'q-2',
|
|
|
|
+ content: '这块手表能预测未来吗?',
|
|
|
|
+ askedBy: 'user-2',
|
|
|
|
+ askedByName: '小红',
|
|
|
|
+ timestamp: Date.now() - 600000, // 10分钟前
|
|
|
|
+ answered: true,
|
|
|
|
+ answer: TurtleSoupAnswerType.YES,
|
|
|
|
+ answeredAt: Date.now() - 590000 // 9分50秒前
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'q-3',
|
|
|
|
+ content: '是因为手表带来厄运吗?',
|
|
|
|
+ askedBy: 'user-1',
|
|
|
|
+ askedByName: '小明',
|
|
|
|
+ timestamp: Date.now() - 300000, // 5分钟前
|
|
|
|
+ answered: false
|
|
|
|
+ }
|
|
],
|
|
],
|
|
- questions: [],
|
|
|
|
|
|
+ status: TurtleSoupGameStatus.ACTIVE,
|
|
|
|
+ createTime: Date.now() - 3600000, // 1小时前
|
|
|
|
+ startTime: Date.now() - 1800000, // 30分钟前
|
|
|
|
+ currentTime: Date.now(),
|
|
|
|
+ duration: 30, // 30分钟
|
|
|
|
+ hostId: 'host-user',
|
|
|
|
+ hostName: '小明 (我)',
|
|
players: [
|
|
players: [
|
|
- { id: 'user-456', name: '玩家1', avatar: 'https://example.com/avatar1.png', joinedAt: new Date().toISOString() },
|
|
|
|
- { id: 'user-789', name: '玩家2', avatar: 'https://example.com/avatar2.png', joinedAt: new Date().toISOString() }
|
|
|
|
|
|
+ {
|
|
|
|
+ id: 'user-1',
|
|
|
|
+ name: '小红',
|
|
|
|
+ avatar: 'https://example.com/avatar1.png',
|
|
|
|
+ joinedAt: Date.now() - 3000000, // 50分钟前
|
|
|
|
+ questionCount: 2
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'user-2',
|
|
|
|
+ name: '小李',
|
|
|
|
+ avatar: 'https://example.com/avatar2.png',
|
|
|
|
+ joinedAt: Date.now() - 2700000, // 45分钟前
|
|
|
|
+ questionCount: 1
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'user-3',
|
|
|
|
+ name: '丽丽',
|
|
|
|
+ avatar: 'https://example.com/avatar3.png',
|
|
|
|
+ joinedAt: Date.now() - 1800000, // 30分钟前
|
|
|
|
+ questionCount: 0
|
|
|
|
+ }
|
|
|
|
+ ],
|
|
|
|
+ settings: {
|
|
|
|
+ themeId: 'theme-1',
|
|
|
|
+ puzzleId: 'puzzle-1',
|
|
|
|
+ difficulty: TurtleSoupDifficulty.MEDIUM,
|
|
|
|
+ maxPlayers: 10,
|
|
|
|
+ isPrivate: false
|
|
|
|
+ },
|
|
|
|
+ playerCount: 3,
|
|
|
|
+ progress: 40 // 40%
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Mock 玩家视图数据
|
|
|
|
+const mockPlayerView: TurtleSoupGamePlayerView = {
|
|
|
|
+ id: 'game-1',
|
|
|
|
+ roomId: 'room-1',
|
|
|
|
+ title: '欢乐海龟汤',
|
|
|
|
+ description: '一个男人收到了一块神秘的手表,戴上后就再也无法取下来,一周后他自杀了,为什么?',
|
|
|
|
+ revealedHints: [
|
|
|
|
+ {
|
|
|
|
+ id: 'hint-1',
|
|
|
|
+ content: '这块手表有特殊功能,不是普通手表。',
|
|
|
|
+ revealedAt: Date.now() - 600000 // 10分钟前
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'hint-2',
|
|
|
|
+ content: '手表可以显示未来将发生的事情。',
|
|
|
|
+ revealedAt: Date.now() - 300000 // 5分钟前
|
|
|
|
+ }
|
|
|
|
+ ],
|
|
|
|
+ myQuestions: [
|
|
|
|
+ {
|
|
|
|
+ id: 'q-1',
|
|
|
|
+ content: '手表是有特殊功能的吗?',
|
|
|
|
+ askedBy: 'user-1',
|
|
|
|
+ askedByName: '小明 (我)',
|
|
|
|
+ timestamp: Date.now() - 900000, // 15分钟前
|
|
|
|
+ answered: true,
|
|
|
|
+ answer: TurtleSoupAnswerType.YES,
|
|
|
|
+ answeredAt: Date.now() - 890000 // 14分50秒前
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'q-3',
|
|
|
|
+ content: '是因为手表带来厄运吗?',
|
|
|
|
+ askedBy: 'user-1',
|
|
|
|
+ askedByName: '小明 (我)',
|
|
|
|
+ timestamp: Date.now() - 300000, // 5分钟前
|
|
|
|
+ answered: false
|
|
|
|
+ }
|
|
|
|
+ ],
|
|
|
|
+ allQuestions: [
|
|
|
|
+ {
|
|
|
|
+ id: 'q-1',
|
|
|
|
+ content: '手表是有特殊功能的吗?',
|
|
|
|
+ askedByName: '小明 (我)',
|
|
|
|
+ answer: TurtleSoupAnswerType.YES,
|
|
|
|
+ timestamp: Date.now() - 900000 // 15分钟前
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'q-2',
|
|
|
|
+ content: '这块手表能预测未来吗?',
|
|
|
|
+ askedByName: '小红',
|
|
|
|
+ answer: TurtleSoupAnswerType.YES,
|
|
|
|
+ timestamp: Date.now() - 600000 // 10分钟前
|
|
|
|
+ }
|
|
|
|
+ ],
|
|
|
|
+ status: TurtleSoupGameStatus.ACTIVE,
|
|
|
|
+ startTime: Date.now() - 1800000, // 30分钟前
|
|
|
|
+ currentTime: Date.now(),
|
|
|
|
+ duration: 30, // 30分钟
|
|
|
|
+ hostId: 'host-user',
|
|
|
|
+ hostName: '小明',
|
|
|
|
+ progress: 40, // 40%
|
|
|
|
+ difficulty: TurtleSoupDifficulty.MEDIUM,
|
|
|
|
+ otherPlayers: [
|
|
|
|
+ {
|
|
|
|
+ id: 'user-2',
|
|
|
|
+ name: '小红',
|
|
|
|
+ avatar: 'https://example.com/avatar2.png'
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'user-3',
|
|
|
|
+ name: '小李',
|
|
|
|
+ avatar: 'https://example.com/avatar3.png'
|
|
|
|
+ }
|
|
]
|
|
]
|
|
}
|
|
}
|
|
|
|
|
|
// 海龟汤游戏服务
|
|
// 海龟汤游戏服务
|
|
export const turtleSoupService = {
|
|
export const turtleSoupService = {
|
|
/**
|
|
/**
|
|
- * 获取游戏数据
|
|
|
|
- * @param gameId 游戏ID
|
|
|
|
- * @param role 用户角色 (storyteller/player)
|
|
|
|
|
|
+ * 获取主题列表
|
|
*/
|
|
*/
|
|
- async getGameData(gameId: string, role: string): Promise<Result<TurtleSoupGame>> {
|
|
|
|
|
|
+ async getThemes(): Promise<Result<TurtleSoupTheme[]>> {
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
return new Promise(resolve => {
|
|
return new Promise(resolve => {
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
- // 根据角色调整返回的数据
|
|
|
|
- if (role === 'storyteller') {
|
|
|
|
- // 主持人可以看到所有信息
|
|
|
|
- resolve(createSuccess({
|
|
|
|
- ...mockGame,
|
|
|
|
- hints: mockGame.hints.map(h => ({ ...h, revealed: true }))
|
|
|
|
- }));
|
|
|
|
- } else {
|
|
|
|
- // 普通玩家只能看到已揭示的提示
|
|
|
|
- resolve(createSuccess(mockGame));
|
|
|
|
- }
|
|
|
|
|
|
+ resolve(createSuccess(mockThemes));
|
|
}, 300);
|
|
}, 300);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
// 使用cloudApi调用云函数
|
|
// 使用cloudApi调用云函数
|
|
- return cloudApi.call<{ game: TurtleSoupGame }>('getTurtleSoupGame', { gameId, role })
|
|
|
|
|
|
+ return cloudApi.call<{ themes: TurtleSoupTheme[] }>('getTurtleSoupThemes')
|
|
.then(result => {
|
|
.then(result => {
|
|
- if (result.success && result.data && result.data.game) {
|
|
|
|
- // 确保返回的是TurtleSoupGame对象
|
|
|
|
- return createSuccess(result.data.game);
|
|
|
|
|
|
+ if (result.success && result.data?.themes) {
|
|
|
|
+ return createSuccess(result.data.themes);
|
|
}
|
|
}
|
|
-
|
|
|
|
- // 如果云函数调用成功但没有返回游戏数据
|
|
|
|
- return createError('未找到游戏数据');
|
|
|
|
|
|
+ return createError(result.message || '获取主题列表失败');
|
|
})
|
|
})
|
|
.catch(error => {
|
|
.catch(error => {
|
|
- console.error('获取海龟汤游戏数据失败:', error);
|
|
|
|
- return createError(error.message || '获取游戏数据失败');
|
|
|
|
|
|
+ console.error('获取主题列表失败:', error);
|
|
|
|
+ return createError(error.message || '获取主题列表失败');
|
|
});
|
|
});
|
|
},
|
|
},
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * 提交问题
|
|
|
|
- * @param gameId 游戏ID
|
|
|
|
- * @param content 问题内容
|
|
|
|
|
|
+ * 获取题目列表
|
|
|
|
+ * @param themeId 主题ID
|
|
|
|
+ * @param difficulty 可选的难度筛选
|
|
*/
|
|
*/
|
|
- async submitQuestion(gameId: string, content: string): Promise<Result<{ questionId: string }>> {
|
|
|
|
- if (!content.trim()) {
|
|
|
|
- return createError('问题内容不能为空');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ async getPuzzles(themeId: string, difficulty?: TurtleSoupDifficulty): Promise<Result<TurtleSoupPuzzle[]>> {
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
return new Promise(resolve => {
|
|
return new Promise(resolve => {
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
- const questionId = `q-${Date.now()}`;
|
|
|
|
- resolve(createSuccess({ questionId }));
|
|
|
|
|
|
+ let puzzles = [...mockPuzzles];
|
|
|
|
+
|
|
|
|
+ // 如果指定了难度,进行过滤
|
|
|
|
+ if (difficulty) {
|
|
|
|
+ puzzles = puzzles.filter(p => p.difficulty === difficulty);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ resolve(createSuccess(puzzles));
|
|
}, 300);
|
|
}, 300);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
// 使用cloudApi调用云函数
|
|
// 使用cloudApi调用云函数
|
|
- return cloudApi.call<{ questionId: string }>('submitTurtleSoupQuestion', { gameId, content });
|
|
|
|
|
|
+ return cloudApi.call<{ puzzles: TurtleSoupPuzzle[] }>('getTurtleSoupPuzzles', { themeId, difficulty })
|
|
|
|
+ .then(result => {
|
|
|
|
+ if (result.success && result.data?.puzzles) {
|
|
|
|
+ return createSuccess(result.data.puzzles);
|
|
|
|
+ }
|
|
|
|
+ return createError(result.message || '获取题目列表失败');
|
|
|
|
+ })
|
|
|
|
+ .catch(error => {
|
|
|
|
+ console.error('获取题目列表失败:', error);
|
|
|
|
+ return createError(error.message || '获取题目列表失败');
|
|
|
|
+ });
|
|
},
|
|
},
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * 回答问题
|
|
|
|
- * @param questionId 问题ID
|
|
|
|
- * @param answer 答案 ('yes', 'no', 'irrelevant')
|
|
|
|
|
|
+ * 获取主持人游戏数据
|
|
|
|
+ * @param gameId 游戏ID
|
|
*/
|
|
*/
|
|
- async answerQuestion(questionId: string, answer: string): Promise<Result<{ success: boolean }>> {
|
|
|
|
- const validAnswers = ['yes', 'no', 'irrelevant'];
|
|
|
|
-
|
|
|
|
- if (!validAnswers.includes(answer)) {
|
|
|
|
- return createError('无效的答案,只能是"yes"、"no"或"irrelevant"');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ async getHostGameData(gameId: string): Promise<Result<TurtleSoupGameHostView>> {
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
return new Promise(resolve => {
|
|
return new Promise(resolve => {
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
- resolve(createSuccess({ success: true }));
|
|
|
|
- }, 200);
|
|
|
|
|
|
+ resolve(createSuccess(mockHostView));
|
|
|
|
+ }, 300);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
// 使用cloudApi调用云函数
|
|
// 使用cloudApi调用云函数
|
|
- return cloudApi.call<{ success: boolean }>('answerTurtleSoupQuestion', { questionId, answer });
|
|
|
|
|
|
+ return cloudApi.call<{ game: TurtleSoupGameHostView }>('getTurtleSoupHostGame', { gameId })
|
|
|
|
+ .then(result => {
|
|
|
|
+ if (result.success && result.data?.game) {
|
|
|
|
+ return createSuccess(result.data.game);
|
|
|
|
+ }
|
|
|
|
+ return createError(result.message || '获取游戏数据失败');
|
|
|
|
+ })
|
|
|
|
+ .catch(error => {
|
|
|
|
+ console.error('获取主持人游戏数据失败:', error);
|
|
|
|
+ return createError(error.message || '获取游戏数据失败');
|
|
|
|
+ });
|
|
},
|
|
},
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * 公开提示
|
|
|
|
|
|
+ * 获取玩家游戏数据
|
|
* @param gameId 游戏ID
|
|
* @param gameId 游戏ID
|
|
- * @param hintIndex 提示索引
|
|
|
|
*/
|
|
*/
|
|
- async revealHint(gameId: string, hintIndex: number): Promise<Result<{ success: boolean }>> {
|
|
|
|
- if (hintIndex < 0) {
|
|
|
|
- return createError('提示索引无效');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ async getPlayerGameData(gameId: string): Promise<Result<TurtleSoupGamePlayerView>> {
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
return new Promise(resolve => {
|
|
return new Promise(resolve => {
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
- // 检查提示索引是否有效
|
|
|
|
- if (hintIndex >= mockGame.hints.length) {
|
|
|
|
- resolve(createError('提示索引超出范围'));
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- resolve(createSuccess({ success: true }));
|
|
|
|
- }, 200);
|
|
|
|
|
|
+ resolve(createSuccess(mockPlayerView));
|
|
|
|
+ }, 300);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
// 使用cloudApi调用云函数
|
|
// 使用cloudApi调用云函数
|
|
- return cloudApi.call<{ success: boolean }>('revealTurtleSoupHint', { gameId, hintIndex });
|
|
|
|
|
|
+ return cloudApi.call<{ game: TurtleSoupGamePlayerView }>('getTurtleSoupPlayerGame', { gameId })
|
|
|
|
+ .then(result => {
|
|
|
|
+ if (result.success && result.data?.game) {
|
|
|
|
+ return createSuccess(result.data.game);
|
|
|
|
+ }
|
|
|
|
+ return createError(result.message || '获取游戏数据失败');
|
|
|
|
+ })
|
|
|
|
+ .catch(error => {
|
|
|
|
+ console.error('获取玩家游戏数据失败:', error);
|
|
|
|
+ return createError(error.message || '获取游戏数据失败');
|
|
|
|
+ });
|
|
},
|
|
},
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * 结束游戏
|
|
|
|
- * @param gameId 游戏ID
|
|
|
|
- * @param result 游戏结果对象
|
|
|
|
|
|
+ * 创建新游戏
|
|
|
|
+ * @param settings 游戏设置
|
|
*/
|
|
*/
|
|
- async endGame(gameId: string, result: { solved: boolean; solvedBy?: string }): Promise<Result<TurtleSoupGameResult>> {
|
|
|
|
|
|
+ async createGame(settings: TurtleSoupGameSettings): Promise<Result<{ gameId: string, roomId: string, title: string }>> {
|
|
|
|
+ // 数据验证
|
|
|
|
+ if (!settings.themeId) return createError('请选择游戏主题');
|
|
|
|
+ if (!settings.puzzleId) return createError('请选择游戏题目');
|
|
|
|
+
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
return new Promise(resolve => {
|
|
return new Promise(resolve => {
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
- const gameResult: TurtleSoupGameResult = {
|
|
|
|
- gameId,
|
|
|
|
- solved: result.solved,
|
|
|
|
- solvedBy: result.solvedBy,
|
|
|
|
- duration: 1800, // 30分钟
|
|
|
|
- questionCount: 15,
|
|
|
|
- hintsRevealed: 2,
|
|
|
|
- completionTime: new Date().toISOString()
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- resolve(createSuccess(gameResult));
|
|
|
|
- }, 400);
|
|
|
|
|
|
+ const gameId = `game-${Date.now()}`;
|
|
|
|
+ const roomId = `room-${Date.now()}`;
|
|
|
|
+ resolve(createSuccess({
|
|
|
|
+ gameId,
|
|
|
|
+ roomId,
|
|
|
|
+ title: mockPuzzles.find(p => p.id === settings.puzzleId)?.title || '新游戏'
|
|
|
|
+ }));
|
|
|
|
+ }, 500);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
// 使用cloudApi调用云函数
|
|
// 使用cloudApi调用云函数
|
|
- return cloudApi.call<{ gameResult: TurtleSoupGameResult }>('endTurtleSoupGame', { gameId, result })
|
|
|
|
- .then(response => {
|
|
|
|
- if (response.success && response.data && response.data.gameResult) {
|
|
|
|
- return createSuccess(response.data.gameResult);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return createError(response.message || '结束游戏失败');
|
|
|
|
- });
|
|
|
|
|
|
+ return cloudApi.call<{ gameId: string, roomId: string, title: string }>('createTurtleSoupGame', settings);
|
|
},
|
|
},
|
|
|
|
|
|
/**
|
|
/**
|
|
- * 创建新游戏
|
|
|
|
- * @param gameData 游戏数据
|
|
|
|
|
|
+ * 为已有房间创建游戏
|
|
|
|
+ * @param roomId 房间ID
|
|
|
|
+ * @param settings 游戏设置
|
|
*/
|
|
*/
|
|
- async createGame(gameData: CreateTurtleSoupGameParams): Promise<Result<{ gameId: string }>> {
|
|
|
|
|
|
+ async createGameForRoom(roomId: string, settings: TurtleSoupGameSettings): Promise<Result<{ gameId: string }>> {
|
|
// 数据验证
|
|
// 数据验证
|
|
- if (!gameData.title.trim()) return createError('游戏标题不能为空');
|
|
|
|
- if (!gameData.description.trim()) return createError('游戏描述不能为空');
|
|
|
|
- if (!gameData.solution.trim()) return createError('游戏答案不能为空');
|
|
|
|
- if (!gameData.hints || gameData.hints.length === 0) return createError('至少需要提供一个提示');
|
|
|
|
|
|
+ if (!settings.themeId) return createError('请选择游戏主题');
|
|
|
|
+ if (!settings.puzzleId) return createError('请选择游戏题目');
|
|
|
|
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
@@ -213,143 +432,171 @@ export const turtleSoupService = {
|
|
}
|
|
}
|
|
|
|
|
|
// 使用cloudApi调用云函数
|
|
// 使用cloudApi调用云函数
|
|
- return cloudApi.call<{ gameId: string }>('createTurtleSoupGame', gameData);
|
|
|
|
|
|
+ return cloudApi.call<{ gameId: string }>('createTurtleSoupGameForRoom', { roomId, settings });
|
|
},
|
|
},
|
|
|
|
|
|
/**
|
|
/**
|
|
- * 获取用户创建的游戏列表
|
|
|
|
|
|
+ * 开始游戏
|
|
|
|
+ * @param gameId 游戏ID
|
|
*/
|
|
*/
|
|
- async getCreatedGames(): Promise<Result<TurtleSoupGame[]>> {
|
|
|
|
|
|
+ async startGame(gameId: string): Promise<Result<{ success: boolean }>> {
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
return new Promise(resolve => {
|
|
return new Promise(resolve => {
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
- resolve(createSuccess([mockGame]));
|
|
|
|
- }, 400);
|
|
|
|
|
|
+ resolve(createSuccess({ success: true }));
|
|
|
|
+ }, 300);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
// 使用cloudApi调用云函数
|
|
// 使用cloudApi调用云函数
|
|
- return cloudApi.call<{ games: TurtleSoupGame[] }>('getCreatedTurtleSoupGames')
|
|
|
|
- .then(result => {
|
|
|
|
- if (result.success && result.data && result.data.games) {
|
|
|
|
- return createSuccess(result.data.games);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (result.success) {
|
|
|
|
- return createSuccess([]);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return createError(result.message || '获取游戏列表失败');
|
|
|
|
- });
|
|
|
|
|
|
+ return cloudApi.call<{ success: boolean }>('startTurtleSoupGame', { gameId });
|
|
},
|
|
},
|
|
|
|
|
|
/**
|
|
/**
|
|
- * 获取用户参与的游戏列表
|
|
|
|
|
|
+ * 提交问题
|
|
|
|
+ * @param gameId 游戏ID
|
|
|
|
+ * @param content 问题内容
|
|
*/
|
|
*/
|
|
- async getJoinedGames(): Promise<Result<TurtleSoupGame[]>> {
|
|
|
|
|
|
+ async submitQuestion(gameId: string, content: string): Promise<Result<{ questionId: string }>> {
|
|
|
|
+ if (!content.trim()) {
|
|
|
|
+ return createError('问题内容不能为空');
|
|
|
|
+ }
|
|
|
|
+
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
return new Promise(resolve => {
|
|
return new Promise(resolve => {
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
- resolve(createSuccess([{...mockGame, storyteller: 'other-user'}]));
|
|
|
|
- }, 400);
|
|
|
|
|
|
+ const questionId = `q-${Date.now()}`;
|
|
|
|
+ resolve(createSuccess({ questionId }));
|
|
|
|
+ }, 300);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
// 使用cloudApi调用云函数
|
|
// 使用cloudApi调用云函数
|
|
- return cloudApi.call<{ games: TurtleSoupGame[] }>('getJoinedTurtleSoupGames')
|
|
|
|
- .then(result => {
|
|
|
|
- if (result.success && result.data && result.data.games) {
|
|
|
|
- return createSuccess(result.data.games);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (result.success) {
|
|
|
|
- return createSuccess([]);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return createError(result.message || '获取游戏列表失败');
|
|
|
|
- });
|
|
|
|
|
|
+ return cloudApi.call<{ questionId: string }>('submitTurtleSoupQuestion', { gameId, content });
|
|
},
|
|
},
|
|
|
|
|
|
/**
|
|
/**
|
|
- * 提交游戏解答
|
|
|
|
- * @param gameId 游戏ID
|
|
|
|
- * @param solution 玩家提交的解答
|
|
|
|
|
|
+ * 回答问题
|
|
|
|
+ * @param questionId 问题ID
|
|
|
|
+ * @param answer 答案类型
|
|
*/
|
|
*/
|
|
- async submitSolution(gameId: string, solution: string): Promise<Result<{ correct: boolean }>> {
|
|
|
|
- if (!solution.trim()) {
|
|
|
|
- return createError('解答内容不能为空');
|
|
|
|
|
|
+ async answerQuestion(questionId: string, answer: TurtleSoupAnswerType): Promise<Result<{ success: boolean }>> {
|
|
|
|
+ // 如果在开发环境或非小程序环境,使用Mock数据
|
|
|
|
+ if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
|
|
+ return new Promise(resolve => {
|
|
|
|
+ setTimeout(() => {
|
|
|
|
+ resolve(createSuccess({ success: true }));
|
|
|
|
+ }, 200);
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // 使用cloudApi调用云函数
|
|
|
|
+ return cloudApi.call<{ success: boolean }>('answerTurtleSoupQuestion', { questionId, answer });
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 公开提示
|
|
|
|
+ * @param gameId 游戏ID
|
|
|
|
+ * @param hintId 提示ID
|
|
|
|
+ */
|
|
|
|
+ async revealHint(gameId: string, hintId: string): Promise<Result<{ success: boolean }>> {
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
return new Promise(resolve => {
|
|
return new Promise(resolve => {
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
- // 模拟50%的概率答对
|
|
|
|
- const correct = Math.random() > 0.5;
|
|
|
|
- resolve(createSuccess({ correct }));
|
|
|
|
- }, 300);
|
|
|
|
|
|
+ resolve(createSuccess({ success: true }));
|
|
|
|
+ }, 200);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
// 使用cloudApi调用云函数
|
|
// 使用cloudApi调用云函数
|
|
- return cloudApi.call<{ correct: boolean }>('submitTurtleSoupSolution', { gameId, solution });
|
|
|
|
|
|
+ return cloudApi.call<{ success: boolean }>('revealTurtleSoupHint', { gameId, hintId });
|
|
},
|
|
},
|
|
|
|
|
|
/**
|
|
/**
|
|
- * 加入游戏
|
|
|
|
|
|
+ * 提交解答
|
|
* @param gameId 游戏ID
|
|
* @param gameId 游戏ID
|
|
- * @param code 游戏邀请码(私人游戏需要)
|
|
|
|
|
|
+ * @param solution 玩家提交的解答
|
|
*/
|
|
*/
|
|
- async joinGame(gameId: string, code?: string): Promise<Result<{ success: boolean }>> {
|
|
|
|
|
|
+ async submitSolution(gameId: string, solution: string): Promise<Result<{ correct: boolean }>> {
|
|
|
|
+ if (!solution.trim()) {
|
|
|
|
+ return createError('解答内容不能为空');
|
|
|
|
+ }
|
|
|
|
+
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
return new Promise(resolve => {
|
|
return new Promise(resolve => {
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
- resolve(createSuccess({ success: true }));
|
|
|
|
|
|
+ // 模拟50%的概率答对
|
|
|
|
+ const correct = Math.random() > 0.5;
|
|
|
|
+ resolve(createSuccess({ correct }));
|
|
}, 300);
|
|
}, 300);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
// 使用cloudApi调用云函数
|
|
// 使用cloudApi调用云函数
|
|
- return cloudApi.call<{ success: boolean }>('joinTurtleSoupGame', { gameId, code });
|
|
|
|
|
|
+ return cloudApi.call<{ correct: boolean }>('submitTurtleSoupSolution', { gameId, solution });
|
|
},
|
|
},
|
|
|
|
|
|
/**
|
|
/**
|
|
- * 离开游戏
|
|
|
|
|
|
+ * 结束游戏
|
|
* @param gameId 游戏ID
|
|
* @param gameId 游戏ID
|
|
|
|
+ * @param result 游戏结果数据
|
|
*/
|
|
*/
|
|
- async leaveGame(gameId: string): Promise<Result<{ success: boolean }>> {
|
|
|
|
|
|
+ async endGame(gameId: string, result: {
|
|
|
|
+ solved: boolean;
|
|
|
|
+ solvedBy?: string;
|
|
|
|
+ solvedByName?: string;
|
|
|
|
+ solution?: string;
|
|
|
|
+ }): Promise<Result<TurtleSoupGameResult>> {
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
return new Promise(resolve => {
|
|
return new Promise(resolve => {
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
- resolve(createSuccess({ success: true }));
|
|
|
|
- }, 300);
|
|
|
|
|
|
+ const gameResult: TurtleSoupGameResult = {
|
|
|
|
+ gameId,
|
|
|
|
+ solved: result.solved,
|
|
|
|
+ solvedBy: result.solvedBy,
|
|
|
|
+ solvedByName: result.solvedByName,
|
|
|
|
+ solution: result.solution,
|
|
|
|
+ duration: 30, // 30分钟
|
|
|
|
+ questionCount: 15,
|
|
|
|
+ hintsRevealed: 2,
|
|
|
|
+ completionTime: Date.now(),
|
|
|
|
+ playerCount: 4
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ resolve(createSuccess(gameResult));
|
|
|
|
+ }, 400);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
// 使用cloudApi调用云函数
|
|
// 使用cloudApi调用云函数
|
|
- return cloudApi.call<{ success: boolean }>('leaveTurtleSoupGame', { gameId });
|
|
|
|
|
|
+ return cloudApi.call<TurtleSoupGameResult>('endTurtleSoupGame', { gameId, result });
|
|
},
|
|
},
|
|
|
|
|
|
/**
|
|
/**
|
|
- * 更新游戏状态
|
|
|
|
|
|
+ * 更新游戏进度
|
|
* @param gameId 游戏ID
|
|
* @param gameId 游戏ID
|
|
- * @param status 新状态
|
|
|
|
|
|
+ * @param progress 进度百分比(0-100)
|
|
*/
|
|
*/
|
|
- async updateGameStatus(gameId: string, status: TurtleSoupGameStatus): Promise<Result<{ success: boolean }>> {
|
|
|
|
|
|
+ async updateProgress(gameId: string, progress: number): Promise<Result<{ success: boolean }>> {
|
|
|
|
+ if (progress < 0 || progress > 100) {
|
|
|
|
+ return createError('进度值必须在0-100之间');
|
|
|
|
+ }
|
|
|
|
+
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
// 如果在开发环境或非小程序环境,使用Mock数据
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
|
|
return new Promise(resolve => {
|
|
return new Promise(resolve => {
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
resolve(createSuccess({ success: true }));
|
|
resolve(createSuccess({ success: true }));
|
|
- }, 300);
|
|
|
|
|
|
+ }, 200);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
// 使用cloudApi调用云函数
|
|
// 使用cloudApi调用云函数
|
|
- return cloudApi.call<{ success: boolean }>('updateTurtleSoupGameStatus', { gameId, status });
|
|
|
|
|
|
+ return cloudApi.call<{ success: boolean }>('updateTurtleSoupProgress', { gameId, progress });
|
|
}
|
|
}
|
|
};
|
|
};
|