index.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. // 云函数入口文件
  2. const cloud = require('wx-server-sdk')
  3. cloud.init({
  4. env: cloud.DYNAMIC_CURRENT_ENV
  5. })
  6. const db = cloud.database()
  7. const _ = db.command
  8. const roomCollection = db.collection('rooms')
  9. const riddleCollection = db.collection('turtle_soup_riddles')
  10. // 云函数入口函数
  11. exports.main = async (event, context) => {
  12. const wxContext = cloud.getWXContext()
  13. const openid = wxContext.OPENID
  14. if (!openid) {
  15. return {
  16. code: 401,
  17. message: '未能获取到用户OpenID',
  18. }
  19. }
  20. const { action, roomId, riddleId, question, clue, answer } = event
  21. try {
  22. // 获取随机题目
  23. if (action === 'getRandomRiddle') {
  24. // 获取所有题目的总数
  25. const countResult = await riddleCollection.count()
  26. const total = countResult.total
  27. if (total === 0) {
  28. return {
  29. code: 404,
  30. message: '没有可用的题目',
  31. }
  32. }
  33. // 随机选择一个题目
  34. const random = Math.floor(Math.random() * total)
  35. const riddleResult = await riddleCollection.skip(random).limit(1).get()
  36. if (riddleResult.data.length === 0) {
  37. return {
  38. code: 404,
  39. message: '获取题目失败',
  40. }
  41. }
  42. const riddle = riddleResult.data[0]
  43. return {
  44. code: 200,
  45. message: '获取题目成功',
  46. data: {
  47. riddleId: riddle._id,
  48. title: riddle.title,
  49. description: riddle.description,
  50. answer: riddle.answer,
  51. difficulty: riddle.difficulty,
  52. tips: riddle.tips
  53. }
  54. }
  55. }
  56. // 根据ID获取题目
  57. else if (action === 'getRiddleById') {
  58. if (!riddleId) {
  59. return {
  60. code: 400,
  61. message: '缺少必要参数:riddleId',
  62. }
  63. }
  64. const riddleResult = await riddleCollection.doc(riddleId).get()
  65. const riddle = riddleResult.data
  66. return {
  67. code: 200,
  68. message: '获取题目成功',
  69. data: {
  70. riddleId: riddle._id,
  71. title: riddle.title,
  72. description: riddle.description,
  73. answer: riddle.answer,
  74. difficulty: riddle.difficulty,
  75. tips: riddle.tips
  76. }
  77. }
  78. }
  79. // 初始化房间的游戏数据
  80. else if (action === 'initGameData') {
  81. if (!roomId || !riddleId) {
  82. return {
  83. code: 400,
  84. message: '缺少必要参数:roomId或riddleId',
  85. }
  86. }
  87. // 获取房间信息
  88. const roomResult = await roomCollection.doc(roomId).get()
  89. const room = roomResult.data
  90. // 检查是否是房主
  91. if (room.hostId !== openid) {
  92. return {
  93. code: 403,
  94. message: '只有房主可以初始化游戏数据',
  95. }
  96. }
  97. // 获取题目信息
  98. const riddleResult = await riddleCollection.doc(riddleId).get()
  99. const riddle = riddleResult.data
  100. // 初始化游戏数据
  101. const gameData = {
  102. riddleId: riddle._id,
  103. title: riddle.title,
  104. description: riddle.description,
  105. answer: riddle.answer,
  106. questions: [],
  107. clues: [],
  108. solved: false,
  109. startedAt: db.serverDate(),
  110. hostRevealedAnswer: false
  111. }
  112. // 更新房间游戏数据
  113. await roomCollection.doc(roomId).update({
  114. data: {
  115. gameData,
  116. updatedAt: db.serverDate()
  117. }
  118. })
  119. return {
  120. code: 200,
  121. message: '游戏数据初始化成功',
  122. data: {
  123. roomId,
  124. gameData: {
  125. ...gameData,
  126. answer: undefined // 不向客户端返回答案
  127. }
  128. }
  129. }
  130. }
  131. // 提交问题(玩家向主持人提问)
  132. else if (action === 'submitQuestion') {
  133. if (!roomId || !question) {
  134. return {
  135. code: 400,
  136. message: '缺少必要参数:roomId或question',
  137. }
  138. }
  139. // 获取房间信息
  140. const roomResult = await roomCollection.doc(roomId).get()
  141. const room = roomResult.data
  142. // 检查房间状态
  143. if (room.status !== 'playing') {
  144. return {
  145. code: 400,
  146. message: '游戏尚未开始或已结束',
  147. }
  148. }
  149. // 检查是否是玩家(非房主)
  150. if (room.hostId === openid) {
  151. return {
  152. code: 403,
  153. message: '房主不能提交问题',
  154. }
  155. }
  156. // 检查用户是否在房间中
  157. const playerExists = room.players.some(p => p.userId === openid && p.status === 'active')
  158. if (!playerExists) {
  159. return {
  160. code: 403,
  161. message: '您不是该房间的成员',
  162. }
  163. }
  164. // 获取用户信息
  165. const playerInfo = room.players.find(p => p.userId === openid)
  166. // 添加问题到游戏数据
  167. const newQuestion = {
  168. id: Date.now().toString(),
  169. content: question,
  170. askedBy: {
  171. userId: openid,
  172. nickName: playerInfo.nickName,
  173. avatarUrl: playerInfo.avatarUrl
  174. },
  175. askedAt: db.serverDate(),
  176. status: 'pending', // pending, answered, rejected
  177. answer: '',
  178. answeredAt: null
  179. }
  180. const updatedGameData = room.gameData || {}
  181. updatedGameData.questions = [...(updatedGameData.questions || []), newQuestion]
  182. // 更新房间游戏数据
  183. await roomCollection.doc(roomId).update({
  184. data: {
  185. 'gameData.questions': _.push(newQuestion),
  186. updatedAt: db.serverDate()
  187. }
  188. })
  189. return {
  190. code: 200,
  191. message: '问题提交成功',
  192. data: {
  193. roomId,
  194. questionId: newQuestion.id
  195. }
  196. }
  197. }
  198. // 回答问题(主持人回答玩家的问题)
  199. else if (action === 'answerQuestion') {
  200. if (!roomId || !event.questionId || !event.answer || !event.status) {
  201. return {
  202. code: 400,
  203. message: '缺少必要参数:roomId、questionId、answer或status',
  204. }
  205. }
  206. // 获取房间信息
  207. const roomResult = await roomCollection.doc(roomId).get()
  208. const room = roomResult.data
  209. // 检查是否是房主
  210. if (room.hostId !== openid) {
  211. return {
  212. code: 403,
  213. message: '只有房主可以回答问题',
  214. }
  215. }
  216. // 查找问题在数组中的索引
  217. const questions = room.gameData?.questions || []
  218. const questionIndex = questions.findIndex(q => q.id === event.questionId)
  219. if (questionIndex === -1) {
  220. return {
  221. code: 404,
  222. message: '问题不存在',
  223. }
  224. }
  225. // 更新问题状态和回答
  226. await roomCollection.doc(roomId).update({
  227. data: {
  228. [`gameData.questions.${questionIndex}.status`]: event.status,
  229. [`gameData.questions.${questionIndex}.answer`]: event.answer,
  230. [`gameData.questions.${questionIndex}.answeredAt`]: db.serverDate(),
  231. updatedAt: db.serverDate()
  232. }
  233. })
  234. return {
  235. code: 200,
  236. message: '回答问题成功',
  237. data: {
  238. roomId,
  239. questionId: event.questionId,
  240. status: event.status
  241. }
  242. }
  243. }
  244. // 提交线索(主持人提供线索)
  245. else if (action === 'submitClue') {
  246. if (!roomId || !clue) {
  247. return {
  248. code: 400,
  249. message: '缺少必要参数:roomId或clue',
  250. }
  251. }
  252. // 获取房间信息
  253. const roomResult = await roomCollection.doc(roomId).get()
  254. const room = roomResult.data
  255. // 检查是否是房主
  256. if (room.hostId !== openid) {
  257. return {
  258. code: 403,
  259. message: '只有房主可以提交线索',
  260. }
  261. }
  262. // 添加线索到游戏数据
  263. const newClue = {
  264. id: Date.now().toString(),
  265. content: clue,
  266. providedAt: db.serverDate()
  267. }
  268. // 更新房间游戏数据
  269. await roomCollection.doc(roomId).update({
  270. data: {
  271. 'gameData.clues': _.push(newClue),
  272. updatedAt: db.serverDate()
  273. }
  274. })
  275. return {
  276. code: 200,
  277. message: '线索提交成功',
  278. data: {
  279. roomId,
  280. clueId: newClue.id
  281. }
  282. }
  283. }
  284. // 提交答案(玩家尝试解答)
  285. else if (action === 'submitAnswer') {
  286. if (!roomId || !answer) {
  287. return {
  288. code: 400,
  289. message: '缺少必要参数:roomId或answer',
  290. }
  291. }
  292. // 获取房间信息
  293. const roomResult = await roomCollection.doc(roomId).get()
  294. const room = roomResult.data
  295. // 检查房间状态
  296. if (room.status !== 'playing') {
  297. return {
  298. code: 400,
  299. message: '游戏尚未开始或已结束',
  300. }
  301. }
  302. // 检查是否是玩家(非房主)
  303. if (room.hostId === openid) {
  304. return {
  305. code: 403,
  306. message: '房主不能提交答案',
  307. }
  308. }
  309. // 检查用户是否在房间中
  310. const playerExists = room.players.some(p => p.userId === openid && p.status === 'active')
  311. if (!playerExists) {
  312. return {
  313. code: 403,
  314. message: '您不是该房间的成员',
  315. }
  316. }
  317. // 获取用户信息
  318. const playerInfo = room.players.find(p => p.userId === openid)
  319. // 检查答案是否正确
  320. const isCorrect = room.gameData.answer.toLowerCase().includes(answer.toLowerCase())
  321. // 添加答案尝试到游戏数据
  322. const answerAttempt = {
  323. id: Date.now().toString(),
  324. content: answer,
  325. submittedBy: {
  326. userId: openid,
  327. nickName: playerInfo.nickName,
  328. avatarUrl: playerInfo.avatarUrl
  329. },
  330. submittedAt: db.serverDate(),
  331. isCorrect
  332. }
  333. // 更新房间游戏数据
  334. const updateData = {
  335. 'gameData.answerAttempts': _.push(answerAttempt),
  336. updatedAt: db.serverDate()
  337. }
  338. // 如果答案正确,则更新游戏状态
  339. if (isCorrect) {
  340. updateData['gameData.solved'] = true
  341. updateData['gameData.solvedBy'] = {
  342. userId: openid,
  343. nickName: playerInfo.nickName,
  344. avatarUrl: playerInfo.avatarUrl
  345. }
  346. updateData['gameData.solvedAt'] = db.serverDate()
  347. }
  348. await roomCollection.doc(roomId).update({
  349. data: updateData
  350. })
  351. return {
  352. code: 200,
  353. message: isCorrect ? '恭喜你,回答正确!' : '答案不正确,请继续尝试',
  354. data: {
  355. roomId,
  356. isCorrect,
  357. answerId: answerAttempt.id
  358. }
  359. }
  360. }
  361. // 揭晓答案(主持人揭晓答案)
  362. else if (action === 'revealAnswer') {
  363. if (!roomId) {
  364. return {
  365. code: 400,
  366. message: '缺少必要参数:roomId',
  367. }
  368. }
  369. // 获取房间信息
  370. const roomResult = await roomCollection.doc(roomId).get()
  371. const room = roomResult.data
  372. // 检查是否是房主
  373. if (room.hostId !== openid) {
  374. return {
  375. code: 403,
  376. message: '只有房主可以揭晓答案',
  377. }
  378. }
  379. // 更新游戏数据
  380. await roomCollection.doc(roomId).update({
  381. data: {
  382. 'gameData.hostRevealedAnswer': true,
  383. 'gameData.revealedAt': db.serverDate(),
  384. updatedAt: db.serverDate()
  385. }
  386. })
  387. return {
  388. code: 200,
  389. message: '答案已揭晓',
  390. data: {
  391. roomId,
  392. answer: room.gameData.answer
  393. }
  394. }
  395. }
  396. else {
  397. return {
  398. code: 400,
  399. message: '无效的action参数',
  400. }
  401. }
  402. } catch (error) {
  403. console.error('海龟汤游戏操作失败:', error)
  404. return {
  405. code: 500,
  406. message: '操作失败: ' + error.message,
  407. }
  408. }
  409. }