room.ts 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. // services/room.ts
  2. import Taro from '@tarojs/taro'
  3. import {
  4. type Room,
  5. type RoomUserInfo,
  6. RoomRole,
  7. RoomStatus,
  8. RoomVisibility
  9. } from '@/types/room'
  10. import { type UserInfo } from '@/types/user'
  11. // Mock房间数据(测试用)
  12. const mockRooms: Record<string, Room> = {
  13. 'room_001': {
  14. roomId: 'room_001',
  15. name: '海龟汤房间',
  16. gameId: '1',
  17. gameTitle: '海龟汤',
  18. maxPlayers: 10,
  19. visibility: RoomVisibility.PUBLIC,
  20. hosterId: 'host_123',
  21. createTime: Date.now() - 3600000,
  22. status: RoomStatus.WAITING,
  23. users: [
  24. {
  25. openid: 'host_123',
  26. nickname: '主持人',
  27. avatar: '',
  28. roomRole: RoomRole.HOSTER,
  29. joinTime: Date.now() - 3600000,
  30. isReady: true
  31. }
  32. ]
  33. },
  34. 'room_002': {
  35. roomId: 'room_002',
  36. name: '狼人杀小队',
  37. gameId: '2',
  38. gameTitle: '狼人杀',
  39. maxPlayers: 8,
  40. visibility: RoomVisibility.PRIVATE,
  41. password: '1234',
  42. hosterId: 'host_456',
  43. createTime: Date.now() - 86400000,
  44. status: RoomStatus.WAITING,
  45. users: [
  46. {
  47. openid: 'host_456',
  48. nickname: '狼王',
  49. avatar: '',
  50. roomRole: RoomRole.HOSTER,
  51. joinTime: Date.now() - 86400000,
  52. isReady: true
  53. }
  54. ]
  55. }
  56. };
  57. // 房间API - 适配新数据结构
  58. export const roomService = {
  59. // 获取最近房间
  60. async getRecentRooms(): Promise<Room[]> {
  61. try {
  62. // 从缓存获取
  63. const cachedRooms = Taro.getStorageSync('recentRooms')
  64. if (cachedRooms) {
  65. return JSON.parse(cachedRooms)
  66. }
  67. // 返回默认mock数据
  68. return [
  69. {
  70. roomId: 'room_001',
  71. name: '海龟汤房间',
  72. gameTitle: '海龟汤',
  73. gameId: '1',
  74. maxPlayers: 10,
  75. visibility: RoomVisibility.PUBLIC,
  76. hosterId: 'host_123',
  77. createTime: Date.now() - 3600000,
  78. status: RoomStatus.WAITING,
  79. users: []
  80. },
  81. {
  82. roomId: 'room_002',
  83. name: '狼人杀小队',
  84. gameTitle: '狼人杀',
  85. gameId: '2',
  86. maxPlayers: 8,
  87. visibility: RoomVisibility.PRIVATE,
  88. password: '1234',
  89. hosterId: 'host_456',
  90. createTime: Date.now() - 86400000,
  91. status: RoomStatus.WAITING,
  92. users: []
  93. }
  94. ]
  95. } catch (error) {
  96. console.error('获取最近房间失败:', error)
  97. return []
  98. }
  99. },
  100. // 检查房间是否存在
  101. async checkRoomExist(gameId: string, roomId: string): Promise<{exists: boolean, needPassword: boolean}> {
  102. try {
  103. // 先查询本地存储
  104. const recentRooms = Taro.getStorageSync('recentRooms')
  105. if (recentRooms) {
  106. const rooms = JSON.parse(recentRooms)
  107. const room = rooms.find((r: Room) => r.roomId === `${gameId}-${roomId}`)
  108. if (room) {
  109. return { exists: true, needPassword: room.visibility === RoomVisibility.PRIVATE }
  110. }
  111. }
  112. // 如果本地没有,检查mock数据
  113. const mockRoom = mockRooms[`${gameId}-${roomId}`]
  114. if (mockRoom) {
  115. return {
  116. exists: true,
  117. needPassword: mockRoom.visibility === RoomVisibility.PRIVATE
  118. }
  119. }
  120. return { exists: false, needPassword: false }
  121. } catch (error) {
  122. console.error('检查房间失败:', error)
  123. return { exists: false, needPassword: false }
  124. }
  125. },
  126. // 验证房间密码
  127. async verifyRoomPassword(gameId: string, roomId: string, password: string): Promise<{valid: boolean}> {
  128. try {
  129. // 简化实现:仅检查mock数据中的密码
  130. const mockRoom = mockRooms[`${gameId}-${roomId}`]
  131. if (mockRoom && mockRoom.visibility === RoomVisibility.PRIVATE) {
  132. return { valid: mockRoom.password === password }
  133. }
  134. return { valid: true }
  135. } catch (error) {
  136. console.error('验证房间密码失败:', error)
  137. return { valid: false }
  138. }
  139. },
  140. // 创建新房间 - 适配新数据结构
  141. async createRoom(roomData: Room, userInfo: UserInfo): Promise<{success: boolean, message?: string}> {
  142. try {
  143. if (!userInfo.openid) {
  144. return { success: false, message: '用户未登录' }
  145. }
  146. // 本地存储一份房间信息
  147. const recentRooms = Taro.getStorageSync('recentRooms') || '[]'
  148. const rooms = JSON.parse(recentRooms)
  149. rooms.unshift(roomData)
  150. // 只保留最近10个房间
  151. if (rooms.length > 10) {
  152. rooms.pop()
  153. }
  154. Taro.setStorageSync('recentRooms', JSON.stringify(rooms))
  155. // 简化实现:仅存储在本地缓存
  156. const allRooms = Taro.getStorageSync('allRooms') || '{}'
  157. const roomsObj = JSON.parse(allRooms)
  158. const roomKey = `${roomData.gameId}-${roomData.roomId}`
  159. roomsObj[roomKey] = roomData
  160. Taro.setStorageSync('allRooms', JSON.stringify(roomsObj))
  161. return { success: true }
  162. } catch (error) {
  163. console.error('创建房间失败:', error)
  164. return { success: false, message: '创建房间失败' }
  165. }
  166. },
  167. // 加入房间 - 适配新数据结构
  168. async joinRoom(gameId: string, roomId: string, userData: RoomUserInfo): Promise<{success: boolean, roomData?: Room, message?: string}> {
  169. try {
  170. // 查找房间 - 先从本地缓存查询
  171. let room: Room | null = null
  172. // 检查本地缓存中是否有该房间
  173. const allRooms = Taro.getStorageSync('allRooms') || '{}'
  174. const roomsObj = JSON.parse(allRooms)
  175. const roomKey = `${gameId}-${roomId}`
  176. if (roomsObj[roomKey]) {
  177. room = roomsObj[roomKey]
  178. } else if (mockRooms[roomKey]) {
  179. // 使用mock数据
  180. room = mockRooms[roomKey]
  181. }
  182. if (!room) {
  183. return { success: false, message: '房间不存在' }
  184. }
  185. // 检查房间是否已满
  186. if (room.users && room.users.length >= room.maxPlayers) {
  187. return { success: false, message: '房间已满' }
  188. }
  189. // 检查用户是否已在房间中
  190. const existingUser = room.users.find(u => u.openid === userData.openid)
  191. if (!existingUser) {
  192. // 添加用户到房间
  193. room.users.push(userData)
  194. // 更新本地缓存
  195. roomsObj[roomKey] = room
  196. Taro.setStorageSync('allRooms', JSON.stringify(roomsObj))
  197. }
  198. // 保存到最近加入的房间
  199. const roomInfo: Room = {
  200. roomId: room.roomId,
  201. name: room.name,
  202. gameId: room.gameId,
  203. gameTitle: room.gameTitle,
  204. maxPlayers: room.maxPlayers,
  205. visibility: room.visibility,
  206. hosterId: room.hosterId,
  207. createTime: room.createTime,
  208. startTime: room.startTime,
  209. endTime: room.endTime,
  210. status: room.status,
  211. users: room.users
  212. }
  213. // 更新最近房间列表
  214. this.saveToRecentRooms(roomInfo)
  215. return { success: true, roomData: room }
  216. } catch (error) {
  217. console.error('加入房间失败:', error)
  218. return { success: false, message: '加入房间失败' }
  219. }
  220. },
  221. // 保存到最近加入的房间
  222. async saveToRecentRooms(roomInfo: Room): Promise<void> {
  223. try {
  224. const recentRooms = Taro.getStorageSync('recentRooms') || '[]'
  225. const rooms = JSON.parse(recentRooms)
  226. // 检查是否已存在
  227. const existingIndex = rooms.findIndex((r: Room) => r.roomId === roomInfo.roomId)
  228. if (existingIndex !== -1) {
  229. // 移除已存在的
  230. rooms.splice(existingIndex, 1)
  231. }
  232. // 添加到最前面
  233. rooms.unshift(roomInfo)
  234. // 只保留最近10个房间
  235. if (rooms.length > 10) {
  236. rooms.pop()
  237. }
  238. Taro.setStorageSync('recentRooms', JSON.stringify(rooms))
  239. } catch (error) {
  240. console.error('保存最近房间失败:', error)
  241. }
  242. },
  243. // 退出房间
  244. async leaveRoom(gameId: string, roomId: string, userId: string): Promise<{success: boolean, message?: string}> {
  245. try {
  246. // 从本地缓存找到房间
  247. const allRooms = Taro.getStorageSync('allRooms') || '{}'
  248. const roomsObj = JSON.parse(allRooms)
  249. const roomKey = `${gameId}-${roomId}`
  250. if (roomsObj[roomKey]) {
  251. const room = roomsObj[roomKey]
  252. // 过滤掉当前用户
  253. room.users = room.users.filter(u => u.openid !== userId)
  254. // 更新本地缓存
  255. roomsObj[roomKey] = room
  256. Taro.setStorageSync('allRooms', JSON.stringify(roomsObj))
  257. }
  258. return { success: true }
  259. } catch (error) {
  260. console.error('退出房间失败:', error)
  261. return { success: false, message: '退出房间失败' }
  262. }
  263. },
  264. // 获取房间信息
  265. async getRoomInfo(gameId: string, roomId: string): Promise<Room | null> {
  266. try {
  267. // 检查本地缓存中是否有该房间
  268. const allRooms = Taro.getStorageSync('allRooms') || '{}'
  269. const roomsObj = JSON.parse(allRooms)
  270. const roomKey = `${gameId}-${roomId}`
  271. if (roomsObj[roomKey]) {
  272. return roomsObj[roomKey]
  273. }
  274. // 如果本地没有,使用mock数据
  275. if (mockRooms[roomKey]) {
  276. return mockRooms[roomKey]
  277. }
  278. return null
  279. } catch (error) {
  280. console.error('获取房间信息失败:', error)
  281. return null
  282. }
  283. },
  284. // 获取进行中的房间
  285. async getActiveRooms(userId: string): Promise<Room[]> {
  286. try {
  287. // 从缓存或模拟数据获取所有房间
  288. const allRooms = Taro.getStorageSync('allRooms') || '{}'
  289. const roomsObj = JSON.parse(allRooms)
  290. // 添加类型断言,确保 Object.values 返回的是 Room[] 类型
  291. const activeRooms = Object.values(roomsObj) as Room[];
  292. // 过滤出用户参与的且状态为"waiting"或"playing"的房间
  293. const userActiveRooms = activeRooms.filter(room => {
  294. return room.status !== RoomStatus.ENDED &&
  295. room.users &&
  296. room.users.some(u => u.openid === userId)
  297. })
  298. // 添加mock数据用于测试
  299. if (userActiveRooms.length === 0) {
  300. return [
  301. {
  302. roomId: 'room_001',
  303. name: '欢乐海龟汤',
  304. gameId: '1',
  305. gameTitle: '海龟汤',
  306. hosterId: 'host_123',
  307. status: RoomStatus.PLAYING,
  308. users: [
  309. {
  310. openid: userId,
  311. nickname: '玩家',
  312. avatar: '',
  313. roomRole: RoomRole.PLAYER,
  314. joinTime: Date.now(),
  315. isReady: true
  316. }
  317. ],
  318. createTime: Date.now() - 3600000,
  319. maxPlayers: 10,
  320. visibility: RoomVisibility.PUBLIC
  321. },
  322. {
  323. roomId: 'room_002',
  324. name: '趣味谜题',
  325. gameId: '1',
  326. gameTitle: '海龟汤',
  327. hosterId: userId,
  328. status: RoomStatus.WAITING,
  329. users: [
  330. {
  331. openid: userId,
  332. nickname: '玩家',
  333. avatar: '',
  334. roomRole: RoomRole.HOSTER,
  335. joinTime: Date.now(),
  336. isReady: true
  337. }
  338. ],
  339. createTime: Date.now() - 7200000,
  340. maxPlayers: 8,
  341. visibility: RoomVisibility.PUBLIC
  342. }
  343. ]
  344. }
  345. return userActiveRooms
  346. } catch (error) {
  347. console.error('获取进行中房间失败:', error)
  348. return []
  349. }
  350. },
  351. // 更新房间中的用户信息
  352. async updateUserInRoom(gameId: string, roomId: string, userId: string, userData: Partial<RoomUserInfo>): Promise<{success: boolean, message?: string}> {
  353. try {
  354. // 从本地缓存找到房间
  355. const allRooms = Taro.getStorageSync('allRooms') || '{}'
  356. const roomsObj = JSON.parse(allRooms)
  357. const roomKey = `${gameId}-${roomId}`
  358. if (roomsObj[roomKey]) {
  359. const room = roomsObj[roomKey]
  360. // 找到对应用户
  361. const userIndex = room.users.findIndex(u => u.openid === userId)
  362. if (userIndex !== -1) {
  363. // 更新用户信息
  364. room.users[userIndex] = {
  365. ...room.users[userIndex],
  366. ...userData
  367. }
  368. // 更新本地缓存
  369. roomsObj[roomKey] = room
  370. Taro.setStorageSync('allRooms', JSON.stringify(roomsObj))
  371. return { success: true }
  372. } else {
  373. return { success: false, message: '用户不在房间中' }
  374. }
  375. } else if (mockRooms[roomId]) {
  376. // 更新mock数据
  377. const room = mockRooms[roomId]
  378. const userIndex = room.users.findIndex(u => u.openid === userId)
  379. if (userIndex !== -1) {
  380. room.users[userIndex] = {
  381. ...room.users[userIndex],
  382. ...userData
  383. }
  384. return { success: true }
  385. } else {
  386. return { success: false, message: '用户不在房间中' }
  387. }
  388. }
  389. return { success: false, message: '房间不存在' }
  390. } catch (error) {
  391. console.error('更新用户信息失败:', error)
  392. return { success: false, message: '更新用户信息失败' }
  393. }
  394. },
  395. // 更新房间状态
  396. async updateRoomStatus(gameId: string, roomId: string, status: RoomStatus): Promise<{success: boolean, message?: string}> {
  397. try {
  398. // 从本地缓存找到房间
  399. const allRooms = Taro.getStorageSync('allRooms') || '{}'
  400. const roomsObj = JSON.parse(allRooms)
  401. const roomKey = `${gameId}-${roomId}`
  402. if (roomsObj[roomKey]) {
  403. const room = roomsObj[roomKey]
  404. // 更新状态
  405. room.status = status
  406. // 更新本地缓存
  407. roomsObj[roomKey] = room
  408. Taro.setStorageSync('allRooms', JSON.stringify(roomsObj))
  409. // 同时更新最近房间列表中的状态
  410. const recentRooms = Taro.getStorageSync('recentRooms') || '[]'
  411. const rooms = JSON.parse(recentRooms)
  412. const roomIndex = rooms.findIndex((r: Room) => r.roomId === roomId)
  413. if (roomIndex !== -1) {
  414. rooms[roomIndex].status = status
  415. Taro.setStorageSync('recentRooms', JSON.stringify(rooms))
  416. }
  417. return { success: true }
  418. } else if (mockRooms[roomId]) {
  419. // 更新mock数据
  420. mockRooms[roomId].status = status
  421. return { success: true }
  422. }
  423. return { success: false, message: '房间不存在' }
  424. } catch (error) {
  425. console.error('更新房间状态失败:', error)
  426. return { success: false, message: '更新房间状态失败' }
  427. }
  428. }
  429. }