const app = getApp() Page({ data: { matchCode: '', match: { players: [] }, myPlayer: null, currentGame: null, myScoreInput: '', opponentScoreInput: '', isReferee: false, editingGame: null, editScoreForm: { player1Score: '', player2Score: '' } }, onLoad(options) { this.setData({ matchCode: options.code }) this.fetchMatchDetail() }, onPullDownRefresh() { this.fetchMatchDetail().then(() => { wx.stopPullDownRefresh() }) }, bindMyScoreInput(e) { this.setData({ myScoreInput: e.detail.value }) }, bindOpponentScoreInput(e) { this.setData({ opponentScoreInput: e.detail.value }) }, async handleSubmitScore() { const { myScoreInput, opponentScoreInput, currentGame } = this.data if (!myScoreInput || !opponentScoreInput) { wx.showToast({ title: '请输入比分', icon: 'none' }) return } if (!currentGame) return wx.showLoading({ title: '提交中...' }) try { if (!this.data.match || !this.data.match.id) { throw new Error('比赛信息缺失') } await app.request('/api/match/ranking/submit-score', { match_id: this.data.match.id, my_score: parseInt(myScoreInput), opponent_score: parseInt(opponentScoreInput) }, 'POST') wx.showToast({ title: '已提交,等待确认' }) this.fetchCurrentGame() } catch (e) { console.error('提交比分失败:', e) wx.showToast({ title: '提交失败,请重试', icon: 'none' }) } finally { wx.hideLoading() } }, async handleConfirmScore() { if (!this.data.currentGame) return wx.showModal({ title: '确认比分', content: '确认比分无误并结束本局?', success: async (res) => { if (res.confirm) { wx.showLoading({ title: '确认中...' }) try { await app.request('/api/match/ranking/confirm-score', { game_id: this.data.currentGame.id, confirm: true }, 'POST') wx.showToast({ title: '已确认' }) // 刷新页面以获取最新状态(包括新对局) this.fetchMatchDetail() } catch (e) { console.error('确认比分失败:', e) } finally { wx.hideLoading() } } } }) }, async handleDisputeScore() { if (!this.data.currentGame) return wx.showModal({ title: '标记争议', content: '标记为有争议将重置本局比分,是否继续?', success: async (res) => { if (res.confirm) { wx.showLoading({ title: '提交中...' }) try { await app.request('/api/match/ranking/confirm-score', { game_id: this.data.currentGame.id, confirm: false }, 'POST') wx.showToast({ title: '已标记争议' }) this.fetchCurrentGame() } catch (e) { console.error('提交失败:', e) } finally { wx.hideLoading() } } } }) }, async fetchMatchDetail() { try { // 同时获取比赛详情和当前对局,确保数据完整刷新 const [detailRes, gameRes] = await Promise.all([ app.request(`/api/match/ranking/${this.data.matchCode}`), app.request(`/api/match/ranking/${this.data.matchCode}/my-game`).catch(() => ({ data: { currentGame: null } })) ]) // 调试:打印完整的接口返回数据 console.log('[fetchMatchDetail] 接口返回数据:', { matchCode: detailRes.data.matchCode, rounds: detailRes.data.rounds, roundsLength: detailRes.data.rounds?.length || 0, isReferee: detailRes.data.isReferee, playersCount: detailRes.data.players?.length || 0 }) // 详细打印对局数据(接口已直接返回选手名称) if (detailRes.data.rounds && detailRes.data.rounds.length > 0) { detailRes.data.rounds.forEach((round, roundIndex) => { console.log(`[fetchMatchDetail] 轮次 ${roundIndex + 1}:`, { roundName: round.roundName, roundId: round.id, gamesCount: round.games?.length || 0, games: round.games?.map(g => ({ id: g.id, player1Id: g.player1Id, player2Id: g.player2Id, player1Name: g.player1Name, player2Name: g.player2Name, player1Score: g.player1Score, player2Score: g.player2Score })) || [] }) // 检查每个对局的选手名称 if (round.games && round.games.length > 0) { round.games.forEach((game, gameIndex) => { console.log(`[fetchMatchDetail] 对局 ${gameIndex + 1}:`, { id: game.id, player1Id: game.player1Id, player2Id: game.player2Id, player1Name: game.player1Name, player2Name: game.player2Name, hasPlayer1Name: !!game.player1Name, hasPlayer2Name: !!game.player2Name }) }) } }) } else { console.warn('[fetchMatchDetail] 警告: rounds 为空或不存在', detailRes.data) } // 确保数据正确设置,深拷贝避免引用问题 const matchData = JSON.parse(JSON.stringify({ ...detailRes.data, rounds: (detailRes.data.rounds || []).map(round => ({ ...round, games: (round.games || []).map(game => ({ ...game, // 确保选手名称字段存在 player1Name: game.player1Name || `选手${game.player1Id}`, player2Name: game.player2Name || `选手${game.player2Id}` })) })) })) console.log('[fetchMatchDetail] 设置到页面的数据:', { matchCode: matchData.matchCode, roundsLength: matchData.rounds.length, firstRoundGames: matchData.rounds[0]?.games?.length || 0, firstGame: matchData.rounds[0]?.games?.[0] || null, firstGamePlayerNames: matchData.rounds[0]?.games?.[0] ? { player1Name: matchData.rounds[0].games[0].player1Name, player2Name: matchData.rounds[0].games[0].player2Name } : null }) this.setData({ match: matchData, isReferee: detailRes.data.isReferee || false }, () => { // setData 完成后的回调 console.log('[fetchMatchDetail] setData 完成,页面数据:', { matchRoundsLength: this.data.match?.rounds?.length || 0, firstRoundGamesLength: this.data.match?.rounds?.[0]?.games?.length || 0, firstGamePlayerNames: this.data.match?.rounds?.[0]?.games?.[0] ? { player1Name: this.data.match.rounds[0].games[0].player1Name, player2Name: this.data.match.rounds[0].games[0].player2Name, player1Id: this.data.match.rounds[0].games[0].player1Id, player2Id: this.data.match.rounds[0].games[0].player2Id } : null }) }) // 如果是裁判,不需要获取当前对局 if (detailRes.data.isReferee) { console.log('[fetchMatchDetail] 裁判身份,跳过获取当前对局') return } // 找到我的参赛信息 const ladderUser = app.globalData.ladderUser if (ladderUser) { // 使用 == 比较,避免类型不一致问题 const myPlayer = detailRes.data.players.find(p => p.ladderUserId == ladderUser.id) this.setData({ myPlayer }) // 更新当前对局信息 const newGame = gameRes.data.currentGame || null const prevGameId = this.data.currentGame && this.data.currentGame.id const newGameId = newGame && newGame.id const gameChanged = prevGameId !== newGameId if (gameChanged) { this.setData({ currentGame: newGame, myScoreInput: '', opponentScoreInput: '' }) } else { this.setData({ currentGame: newGame }) } } } catch (e) { console.error('获取排位赛详情失败:', e) } }, async fetchCurrentGame() { try { const res = await app.request(`/api/match/ranking/${this.data.matchCode}/my-game`) const newGame = res.data.currentGame || null // 如果切换到了新的对局(或上一局结束变为 null),重置本地输入框 const prevGameId = this.data.currentGame && this.data.currentGame.id const newGameId = newGame && newGame.id const gameChanged = prevGameId !== newGameId if (gameChanged) { this.setData({ currentGame: newGame, myScoreInput: '', opponentScoreInput: '' }) } else { this.setData({ currentGame: newGame }) } } catch (e) { console.error('获取当前对局失败:', e) } }, // 裁判功能:编辑比分 handleRefereeEditScore(e) { const game = e.currentTarget.dataset.game if (!game) return // 确保 game 对象包含必要的字段,包括选手名称 const gameData = { id: game.id, player1Id: game.player1Id, player2Id: game.player2Id, player1Name: game.player1Name || `选手${game.player1Id}`, player2Name: game.player2Name || `选手${game.player2Id}`, player1Score: game.player1Score, player2Score: game.player2Score, confirmStatus: game.confirmStatus } this.setData({ editingGame: gameData, editScoreForm: { player1Score: game.player1Score !== null && game.player1Score !== undefined ? String(game.player1Score) : '', player2Score: game.player2Score !== null && game.player2Score !== undefined ? String(game.player2Score) : '' } }) }, bindPlayer1ScoreInput(e) { this.setData({ 'editScoreForm.player1Score': e.detail.value }) }, bindPlayer2ScoreInput(e) { this.setData({ 'editScoreForm.player2Score': e.detail.value }) }, async handleRefereeSaveScore() { const { editingGame, editScoreForm } = this.data if (!editingGame || !editScoreForm.player1Score || !editScoreForm.player2Score) { wx.showToast({ title: '请输入完整比分', icon: 'none' }) return } wx.showLoading({ title: '保存中...' }) try { await app.request(`/api/match/referee/update-score`, { match_id: this.data.match.id, game_id: editingGame.id, player1_score: parseInt(editScoreForm.player1Score), player2_score: parseInt(editScoreForm.player2Score) }, 'POST') wx.showToast({ title: '保存成功', icon: 'success' }) this.setData({ editingGame: null }) this.fetchMatchDetail() } catch (e) { console.error('保存比分失败:', e) wx.showToast({ title: e.message || '保存失败', icon: 'none' }) } finally { wx.hideLoading() } }, // 裁判功能:确认比分 async handleRefereeConfirmScore(e) { const game = e.currentTarget.dataset.game wx.showModal({ title: '确认比分', content: `确认该对局结果?确认后将计算战力值变动`, success: async (res) => { if (res.confirm) { wx.showLoading({ title: '确认中...' }) try { // 使用后台API确认比分(需要管理员权限,但裁判应该可以通过小程序API确认) // 或者使用小程序端的确认接口,但需要检查权限 await app.request(`/api/match/ranking/confirm-score`, { game_id: game.id, confirm: true }, 'POST') wx.showToast({ title: '确认成功', icon: 'success' }) this.fetchMatchDetail() } catch (e) { console.error('确认比分失败:', e) wx.showToast({ title: e.message || '确认失败', icon: 'none' }) } finally { wx.hideLoading() } } } }) }, // 关闭编辑弹窗 handleCloseEditModal() { this.setData({ editingGame: null }) }, // 阻止事件冒泡(用于弹窗内容区域) stopPropagation() { // 空函数,仅用于阻止事件冒泡 }, // 获取选手名称(用于裁判界面) getPlayerName(ladderUserId) { if (!ladderUserId) { return '未知选手' } if (!this.data.match || !this.data.match.players || !Array.isArray(this.data.match.players)) { return `选手${ladderUserId}` } // 使用 == 比较,避免类型不一致问题(支持数字和字符串比较) const player = this.data.match.players.find(p => { const pId = p.ladderUserId const targetId = ladderUserId return String(pId) === String(targetId) || Number(pId) === Number(targetId) }) if (player && player.realName) { return player.realName } // 如果找不到,返回默认名称 return `选手${ladderUserId}` }, // 裁判功能:开始淘汰赛 handleRefereeStartElimination() { wx.showModal({ title: '开始淘汰赛', content: '确定要开始淘汰赛吗?', success: async (res) => { if (res.confirm) { wx.showActionSheet({ itemList: ['2强(决赛)', '4强', '8强'], success: async (actionRes) => { const sizes = [2, 4, 8] const size = sizes[actionRes.tapIndex] wx.showLoading({ title: '开始中...' }) try { await app.request(`/api/match/referee/start-elimination`, { match_id: this.data.match.id, elimination_size: size }, 'POST') wx.showToast({ title: '淘汰赛已开始', icon: 'success' }) this.fetchMatchDetail() } catch (e) { console.error('开始淘汰赛失败:', e) wx.showToast({ title: e.message || '开始失败', icon: 'none' }) } finally { wx.hideLoading() } } }) } } }) } })