yingsa/miniprogram/pages/match/ranking/index.js
ethanfly 8f9eb38666 fix(dependencies): Remove peer flags from package-lock.json and update Vite dependencies
- Removed unnecessary "peer" flags from various dependencies in package-lock.json to streamline package management.
- Updated Vite dependencies and their corresponding metadata for improved performance and compatibility.
- Adjusted import paths in CSS files to reflect the correct directory structure.
- Deleted unused CSS files related to the "col" component to clean up the project.
2026-02-07 02:05:34 +08:00

439 lines
14 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()
}
}
})
}
}
})
}
})