game.ts 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. // services/game.ts
  2. import { Result, createSuccess, createError } from '@/types/result'
  3. import { cloudApi } from '@/api'
  4. import { type Game } from '@/types/game'
  5. import { USE_MOCK } from '@/services'
  6. // Mock游戏数据
  7. const mockGames: Game[] = [
  8. {
  9. id: '1',
  10. title: '海龟汤',
  11. image: 'https://images.unsplash.com/photo-1582845512747-e42001c95638?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&h=100&q=80',
  12. players: '3-10',
  13. duration: '30-60',
  14. rating: 4.8,
  15. isNew: true,
  16. isHot: true,
  17. description: '海龟汤是一种猜谜游戏,游戏开始时,主持人会讲述一个故事的结果,参与者需要通过提问来猜测故事的真相。',
  18. rules: '1. 主持人讲述一个故事的结果\n2. 参与者通过提问来猜测故事的真相\n3. 主持人只能回答"是"、"否"或"不重要"',
  19. category: '推理',
  20. playCount: 1000,
  21. completionRate: 0.8,
  22. tips: [
  23. '提问时要注意逻辑思维',
  24. '尝试从多个角度思考问题',
  25. '注意主持人的回答,特别是"不重要"的部分'
  26. ],
  27. examples: [
  28. {
  29. question: '一个人走进酒吧,点了一杯水,喝完就离开了。为什么?',
  30. answer: '这个人有打嗝的困扰,想通过喝水来缓解。'
  31. }
  32. ]
  33. },
  34. {
  35. id: '2',
  36. title: '剧本杀',
  37. image: 'https://images.unsplash.com/photo-1529156069898-49953e39b3ac?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&h=100&q=80',
  38. players: '4-8',
  39. duration: '120-180',
  40. rating: 4.5,
  41. isNew: false,
  42. isHot: true,
  43. description: '剧本杀是一种角色扮演游戏,每个玩家扮演一个角色,通过阅读剧本和相互交流来解决一个谜题。',
  44. rules: '1. 每个玩家扮演一个角色\n2. 阅读剧本并获取个人信息\n3. 通过交流和推理解决谜题',
  45. category: '角色扮演',
  46. playCount: 1500,
  47. completionRate: 0.7,
  48. tips: [
  49. '认真阅读你的角色背景',
  50. '注意收集和分析信息',
  51. '积极参与角色扮演和讨论'
  52. ],
  53. examples: [
  54. {
  55. question: '谁是凶手?',
  56. answer: '根据线索和证据,管家是凶手。'
  57. }
  58. ]
  59. },
  60. {
  61. id: '3',
  62. title: '狼人杀',
  63. image: 'https://images.unsplash.com/photo-1529156069898-49953e39b3ac?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&h=100&q=80',
  64. players: '6-12',
  65. duration: '30-45',
  66. rating: 4.7,
  67. isNew: false,
  68. isHot: true,
  69. description: '狼人杀是一种桌游,玩家分为狼人和村民两个阵营,狼人试图消灭村民,村民则要找出并消灭狼人。',
  70. rules: '1. 玩家分为狼人和村民两个阵营\n2. 夜晚狼人选择一名玩家"杀死"\n3. 白天所有人讨论并投票处决一名玩家',
  71. category: '桌游',
  72. playCount: 2000,
  73. completionRate: 0.6,
  74. tips: [
  75. '仔细观察其他玩家的言行',
  76. '理性分析每晚的死亡情况',
  77. '善用自己的角色技能'
  78. ],
  79. examples: [
  80. {
  81. question: '如何判断谁是狼人?',
  82. answer: '通过分析发言逻辑、投票行为和表情变化,找出可疑的玩家。'
  83. }
  84. ]
  85. }
  86. ]
  87. // 游戏通用服务
  88. export const gameService = {
  89. // 获取游戏列表
  90. async getGames(options?: { category?: string }): Promise<Result<Game[]>> {
  91. // 如果在开发环境或非小程序环境,使用Mock数据
  92. if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
  93. return new Promise(resolve => {
  94. setTimeout(() => {
  95. let filteredGames = [...mockGames];
  96. // 如果指定了分类,进行过滤
  97. if (options?.category) {
  98. filteredGames = filteredGames.filter(
  99. game => game.category === options.category
  100. );
  101. }
  102. resolve(createSuccess(filteredGames));
  103. }, 500); // 模拟网络延迟
  104. });
  105. }
  106. // 使用cloudApi调用云函数
  107. return cloudApi.call<Game[]>('getGames', options)
  108. .then(result => {
  109. // 如果没有返回数据,使用mock数据
  110. if (result.success && (!result.data || result.data.length === 0)) {
  111. return createSuccess(mockGames);
  112. }
  113. return result;
  114. })
  115. .catch(error => {
  116. console.error('获取游戏列表失败:', error);
  117. return createError(error.message || '获取游戏列表失败');
  118. });
  119. },
  120. // 获取游戏详情
  121. async getGameDetail(id: string): Promise<Result<Game>> {
  122. // 如果在开发环境或非小程序环境,使用Mock数据
  123. if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
  124. return new Promise(resolve => {
  125. setTimeout(() => {
  126. const game = mockGames.find(g => g.id === id);
  127. if (game) {
  128. resolve(createSuccess(game));
  129. } else {
  130. resolve(createError('未找到指定游戏'));
  131. }
  132. }, 300); // 模拟网络延迟
  133. });
  134. }
  135. // 使用cloudApi调用云函数
  136. return cloudApi.call<Game>('getGameDetail', { id })
  137. .then(result => {
  138. // 如果没有返回数据,尝试从mock找
  139. if (result.success && !result.data) {
  140. const mockGame = mockGames.find(g => g.id === id);
  141. if (mockGame) {
  142. return createSuccess(mockGame);
  143. }
  144. return createError('未找到指定游戏');
  145. }
  146. return result;
  147. })
  148. .catch(error => {
  149. console.error('获取游戏详情失败:', error);
  150. return createError(error.message || '获取游戏详情失败');
  151. });
  152. },
  153. // 获取热门游戏
  154. async getHotGames(limit: number = 5): Promise<Result<Game[]>> {
  155. const result = await this.getGames();
  156. if (!result.success) {
  157. return result;
  158. }
  159. const hotGames = result.data
  160. ?.filter(game => game.isHot)
  161. .sort((a, b) => b.rating - a.rating)
  162. .slice(0, limit);
  163. return createSuccess(hotGames || []);
  164. },
  165. // 获取新游戏
  166. async getNewGames(limit: number = 5): Promise<Result<Game[]>> {
  167. const result = await this.getGames();
  168. if (!result.success) {
  169. return result;
  170. }
  171. const newGames = result.data
  172. ?.filter(game => game.isNew)
  173. .slice(0, limit);
  174. return createSuccess(newGames || []);
  175. },
  176. // 搜索游戏
  177. async searchGames(keyword: string): Promise<Result<Game[]>> {
  178. // 如果在开发环境或非小程序环境,使用Mock数据
  179. if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
  180. return new Promise(resolve => {
  181. setTimeout(() => {
  182. if (!keyword.trim()) {
  183. resolve(createSuccess(mockGames));
  184. return;
  185. }
  186. const searchKey = keyword.toLowerCase();
  187. const results = mockGames.filter(game =>
  188. game.title.toLowerCase().includes(searchKey) ||
  189. game.description.toLowerCase().includes(searchKey) ||
  190. game.category.toLowerCase().includes(searchKey)
  191. );
  192. resolve(createSuccess(results));
  193. }, 300);
  194. });
  195. }
  196. // 使用cloudApi调用云函数
  197. return cloudApi.call<Game[]>('searchGames', { keyword })
  198. .then(result => {
  199. // 如果云函数搜索失败,降级到前端搜索mock数据
  200. if (!result.success || !result.data || result.data.length === 0) {
  201. const searchKey = keyword.toLowerCase();
  202. const results = mockGames.filter(game =>
  203. game.title.toLowerCase().includes(searchKey) ||
  204. game.description.toLowerCase().includes(searchKey) ||
  205. game.category.toLowerCase().includes(searchKey)
  206. );
  207. return createSuccess(results);
  208. }
  209. return result;
  210. })
  211. .catch(error => {
  212. console.error('搜索游戏失败:', error);
  213. return createError(error.message || '搜索游戏失败');
  214. });
  215. },
  216. // 获取游戏分类
  217. async getCategories(): Promise<Result<string[]>> {
  218. // 如果在开发环境或非小程序环境,使用Mock数据
  219. if (USE_MOCK || process.env.TARO_ENV !== 'weapp') {
  220. return new Promise(resolve => {
  221. setTimeout(() => {
  222. // 从mock数据中提取唯一分类
  223. const categories = [...new Set(mockGames.map(game => game.category))];
  224. resolve(createSuccess(categories));
  225. }, 200);
  226. });
  227. }
  228. // 使用cloudApi调用云函数
  229. return cloudApi.call<string[]>('getGameCategories')
  230. .then(result => {
  231. // 如果没有返回数据,从mock数据提取
  232. if (result.success && (!result.data || result.data.length === 0)) {
  233. const categories = [...new Set(mockGames.map(game => game.category))];
  234. return createSuccess(categories);
  235. }
  236. return result;
  237. })
  238. .catch(error => {
  239. console.error('获取游戏分类失败:', error);
  240. return createError(error.message || '获取游戏分类失败');
  241. });
  242. }
  243. }