566 lines
13 KiB
JavaScript
566 lines
13 KiB
JavaScript
// pages/game/play/play.js
|
|
import request from '../../../utils/request'
|
|
|
|
Page({
|
|
data: {
|
|
sessionId: null,
|
|
session: null,
|
|
players: [],
|
|
detailPlayers: [],
|
|
scoreboard: [],
|
|
recentRecords: [],
|
|
historyRecords: [],
|
|
currentRound: 1,
|
|
|
|
// 快速记账
|
|
selectedScore: 0,
|
|
customScore: '',
|
|
canSubmitQuick: false,
|
|
|
|
// 详细记账
|
|
showDetailMode: false,
|
|
totalBalance: 0,
|
|
|
|
// 历史记录
|
|
showHistory: false,
|
|
|
|
// 刷新定时器
|
|
refreshTimer: null
|
|
},
|
|
|
|
onLoad(options) {
|
|
if (!options.id) {
|
|
wx.showToast({
|
|
title: '参数错误',
|
|
icon: 'none'
|
|
})
|
|
setTimeout(() => {
|
|
wx.navigateBack()
|
|
}, 1500)
|
|
return
|
|
}
|
|
|
|
this.setData({ sessionId: options.id })
|
|
|
|
// 加载数据
|
|
this.loadSessionData()
|
|
this.loadRecentRecords()
|
|
|
|
// 设置自动刷新
|
|
this.startAutoRefresh()
|
|
},
|
|
|
|
onUnload() {
|
|
if (this.data.refreshTimer) {
|
|
clearInterval(this.data.refreshTimer)
|
|
}
|
|
},
|
|
|
|
// 启动自动刷新
|
|
startAutoRefresh() {
|
|
const timer = setInterval(() => {
|
|
this.loadSessionData(true)
|
|
this.loadRecentRecords(true)
|
|
}, 10000) // 每10秒刷新一次
|
|
|
|
this.setData({ refreshTimer: timer })
|
|
},
|
|
|
|
// 加载牌局数据
|
|
async loadSessionData(silent = false) {
|
|
if (!silent) {
|
|
wx.showLoading({ title: '加载中...' })
|
|
}
|
|
|
|
try {
|
|
// 获取牌局详情
|
|
const sessionData = await request.get(`/rooms/${this.data.sessionId}`)
|
|
|
|
// 获取当前积分和局数
|
|
const chips = await request.get(`/records/session/${this.data.sessionId}/chips`)
|
|
|
|
// 准备玩家数据(用于快速记账)
|
|
const players = sessionData.players.map(p => ({
|
|
id: p.player_id,
|
|
nickname: p.nickname,
|
|
avatar_url: p.avatar_url,
|
|
selected: false, // 是否选为赢家
|
|
losing: false // 是否选为输家
|
|
}))
|
|
|
|
// 准备详细记账玩家数据
|
|
const detailPlayers = sessionData.players.map(p => ({
|
|
id: p.player_id,
|
|
nickname: p.nickname,
|
|
avatar_url: p.avatar_url,
|
|
current_chips: chips.chips[p.player_id] || 0,
|
|
chips_change: 0
|
|
}))
|
|
|
|
// 准备积分榜数据
|
|
const scoreboard = sessionData.players.map(p => ({
|
|
id: p.player_id,
|
|
nickname: p.nickname,
|
|
avatar_url: p.avatar_url,
|
|
total_chips: chips.chips[p.player_id] || 0
|
|
})).sort((a, b) => b.total_chips - a.total_chips)
|
|
|
|
this.setData({
|
|
session: sessionData.session,
|
|
players,
|
|
detailPlayers,
|
|
scoreboard,
|
|
currentRound: chips.total_rounds + 1
|
|
})
|
|
|
|
if (!silent) {
|
|
wx.hideLoading()
|
|
}
|
|
|
|
} catch (error) {
|
|
if (!silent) {
|
|
wx.hideLoading()
|
|
wx.showToast({
|
|
title: error.message || '加载失败',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
}
|
|
},
|
|
|
|
// 加载最近记录
|
|
async loadRecentRecords(silent = false) {
|
|
try {
|
|
const recordsData = await request.get(`/records/session/${this.data.sessionId}`, {
|
|
page: 1,
|
|
pageSize: 5
|
|
})
|
|
|
|
// 格式化记录
|
|
const recentRecords = (recordsData.list || []).map(record => {
|
|
const time = new Date(record.created_at * 1000)
|
|
const now = Date.now()
|
|
const diff = now - record.created_at * 1000
|
|
|
|
return {
|
|
id: record.id,
|
|
round_number: record.round_number,
|
|
scores: record.playerScores || [],
|
|
timeText: this.formatRecordTime(time),
|
|
can_undo: diff < 300000 // 5分钟内可撤销
|
|
}
|
|
})
|
|
|
|
this.setData({ recentRecords })
|
|
|
|
} catch (error) {
|
|
if (!silent) {
|
|
console.error('加载记录失败:', error)
|
|
}
|
|
}
|
|
},
|
|
|
|
// 格式化时间
|
|
formatRecordTime(time) {
|
|
const now = new Date()
|
|
const diff = now - time
|
|
|
|
if (diff < 60000) {
|
|
return '刚刚'
|
|
} else if (diff < 3600000) {
|
|
return `${Math.floor(diff / 60000)}分钟前`
|
|
} else {
|
|
return `${time.getHours()}:${String(time.getMinutes()).padStart(2, '0')}`
|
|
}
|
|
},
|
|
|
|
// 切换赢家
|
|
toggleWinner(e) {
|
|
const playerId = e.currentTarget.dataset.id
|
|
const players = this.data.players.map(p => {
|
|
if (p.id === playerId) {
|
|
p.selected = !p.selected
|
|
// 赢家不能同时是输家
|
|
if (p.selected) p.losing = false
|
|
}
|
|
return p
|
|
})
|
|
|
|
this.setData({ players })
|
|
this.checkCanSubmitQuick()
|
|
},
|
|
|
|
// 切换输家
|
|
toggleLoser(e) {
|
|
const playerId = e.currentTarget.dataset.id
|
|
const players = this.data.players.map(p => {
|
|
if (p.id === playerId) {
|
|
p.losing = !p.losing
|
|
// 输家不能同时是赢家
|
|
if (p.losing) p.selected = false
|
|
}
|
|
return p
|
|
})
|
|
|
|
this.setData({ players })
|
|
this.checkCanSubmitQuick()
|
|
},
|
|
|
|
// 设置分数
|
|
setScore(e) {
|
|
const score = parseInt(e.currentTarget.dataset.score)
|
|
this.setData({
|
|
selectedScore: score,
|
|
customScore: ''
|
|
})
|
|
this.checkCanSubmitQuick()
|
|
},
|
|
|
|
// 输入自定义分数
|
|
onScoreInput(e) {
|
|
const score = parseInt(e.detail.value) || 0
|
|
this.setData({
|
|
customScore: e.detail.value,
|
|
selectedScore: score
|
|
})
|
|
this.checkCanSubmitQuick()
|
|
},
|
|
|
|
// 检查是否可以提交快速记账
|
|
checkCanSubmitQuick() {
|
|
const { players, selectedScore } = this.data
|
|
const winners = players.filter(p => p.selected)
|
|
const losers = players.filter(p => p.losing)
|
|
|
|
const canSubmit = winners.length > 0 && losers.length > 0 && selectedScore > 0
|
|
this.setData({ canSubmitQuick: canSubmit })
|
|
},
|
|
|
|
// 提交快速记账
|
|
async submitQuickEntry() {
|
|
const { players, selectedScore, currentRound } = this.data
|
|
const winners = players.filter(p => p.selected)
|
|
const losers = players.filter(p => p.losing)
|
|
|
|
if (winners.length === 0 || losers.length === 0 || selectedScore <= 0) {
|
|
wx.showToast({
|
|
title: '请完整填写信息',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
|
|
// 计算分数变化
|
|
const winnerShare = Math.floor(selectedScore * losers.length / winners.length)
|
|
const loserShare = selectedScore
|
|
|
|
const scores = {}
|
|
winners.forEach(w => {
|
|
scores[w.id] = winnerShare
|
|
})
|
|
losers.forEach(l => {
|
|
scores[l.id] = -loserShare
|
|
})
|
|
|
|
// 未参与的玩家分数为0
|
|
players.forEach(p => {
|
|
if (!scores[p.id]) {
|
|
scores[p.id] = 0
|
|
}
|
|
})
|
|
|
|
wx.showLoading({ title: '提交中...' })
|
|
|
|
try {
|
|
await request.post('/records/create', {
|
|
session_id: this.data.sessionId,
|
|
round_number: currentRound,
|
|
scores
|
|
})
|
|
|
|
wx.hideLoading()
|
|
wx.showToast({
|
|
title: '记账成功',
|
|
icon: 'success'
|
|
})
|
|
|
|
// 重置选择
|
|
const resetPlayers = players.map(p => ({
|
|
...p,
|
|
selected: false,
|
|
losing: false
|
|
}))
|
|
|
|
this.setData({
|
|
players: resetPlayers,
|
|
selectedScore: 0,
|
|
customScore: '',
|
|
canSubmitQuick: false,
|
|
currentRound: currentRound + 1
|
|
})
|
|
|
|
// 刷新数据
|
|
this.loadSessionData()
|
|
this.loadRecentRecords()
|
|
|
|
} catch (error) {
|
|
wx.hideLoading()
|
|
wx.showToast({
|
|
title: error.message || '提交失败',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
},
|
|
|
|
// 切换详细记账模式
|
|
toggleDetailMode() {
|
|
this.setData({
|
|
showDetailMode: !this.data.showDetailMode
|
|
})
|
|
},
|
|
|
|
// 详细分数输入
|
|
onDetailScoreInput(e) {
|
|
const playerId = e.currentTarget.dataset.id
|
|
const value = parseInt(e.detail.value) || 0
|
|
|
|
const detailPlayers = this.data.detailPlayers.map(p => {
|
|
if (p.id === playerId) {
|
|
p.chips_change = value
|
|
}
|
|
return p
|
|
})
|
|
|
|
// 计算总平衡
|
|
const totalBalance = detailPlayers.reduce((sum, p) => sum + p.chips_change, 0)
|
|
|
|
this.setData({
|
|
detailPlayers,
|
|
totalBalance
|
|
})
|
|
},
|
|
|
|
// 提交详细记账
|
|
async submitDetailEntry() {
|
|
const { detailPlayers, totalBalance, currentRound } = this.data
|
|
|
|
if (totalBalance !== 0) {
|
|
wx.showToast({
|
|
title: '分数需要平衡',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
|
|
// 检查是否有变化
|
|
const hasChange = detailPlayers.some(p => p.chips_change !== 0)
|
|
if (!hasChange) {
|
|
wx.showToast({
|
|
title: '请输入分数变化',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
|
|
// 构建分数对象
|
|
const scores = {}
|
|
detailPlayers.forEach(p => {
|
|
scores[p.id] = p.chips_change
|
|
})
|
|
|
|
wx.showLoading({ title: '提交中...' })
|
|
|
|
try {
|
|
await request.post('/records/create', {
|
|
session_id: this.data.sessionId,
|
|
round_number: currentRound,
|
|
scores
|
|
})
|
|
|
|
wx.hideLoading()
|
|
wx.showToast({
|
|
title: '记账成功',
|
|
icon: 'success'
|
|
})
|
|
|
|
// 重置详细记账
|
|
const resetPlayers = detailPlayers.map(p => ({
|
|
...p,
|
|
chips_change: 0
|
|
}))
|
|
|
|
this.setData({
|
|
detailPlayers: resetPlayers,
|
|
totalBalance: 0,
|
|
showDetailMode: false,
|
|
currentRound: currentRound + 1
|
|
})
|
|
|
|
// 刷新数据
|
|
this.loadSessionData()
|
|
this.loadRecentRecords()
|
|
|
|
} catch (error) {
|
|
wx.hideLoading()
|
|
wx.showToast({
|
|
title: error.message || '提交失败',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
},
|
|
|
|
// 撤销记录
|
|
async undoRecord(e) {
|
|
const recordId = e.currentTarget.dataset.id
|
|
|
|
wx.showModal({
|
|
title: '撤销记录',
|
|
content: '确定要撤销这条记录吗?',
|
|
success: async (res) => {
|
|
if (res.confirm) {
|
|
wx.showLoading({ title: '撤销中...' })
|
|
|
|
try {
|
|
await request.delete(`/records/${recordId}`)
|
|
|
|
wx.hideLoading()
|
|
wx.showToast({
|
|
title: '已撤销',
|
|
icon: 'success'
|
|
})
|
|
|
|
// 刷新数据
|
|
this.loadSessionData()
|
|
this.loadRecentRecords()
|
|
|
|
} catch (error) {
|
|
wx.hideLoading()
|
|
wx.showToast({
|
|
title: error.message || '撤销失败',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
// 查看历史记录
|
|
async viewHistory() {
|
|
wx.showLoading({ title: '加载中...' })
|
|
|
|
try {
|
|
const recordsData = await request.get(`/records/session/${this.data.sessionId}`, {
|
|
page: 1,
|
|
pageSize: 50
|
|
})
|
|
|
|
const historyRecords = (recordsData.list || []).map(record => {
|
|
const time = new Date(record.created_at * 1000)
|
|
return {
|
|
...record,
|
|
timeText: `${time.getMonth() + 1}/${time.getDate()} ${time.getHours()}:${String(time.getMinutes()).padStart(2, '0')}`
|
|
}
|
|
})
|
|
|
|
this.setData({
|
|
historyRecords,
|
|
showHistory: true
|
|
})
|
|
|
|
wx.hideLoading()
|
|
|
|
} catch (error) {
|
|
wx.hideLoading()
|
|
wx.showToast({
|
|
title: '加载失败',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
},
|
|
|
|
// 关闭历史记录
|
|
closeHistory() {
|
|
this.setData({
|
|
showHistory: false
|
|
})
|
|
},
|
|
|
|
// 暂停游戏
|
|
pauseGame() {
|
|
wx.showModal({
|
|
title: '暂停游戏',
|
|
content: '确定要暂停游戏吗?',
|
|
success: async (res) => {
|
|
if (res.confirm) {
|
|
try {
|
|
await request.post(`/rooms/${this.data.sessionId}/pause`)
|
|
|
|
wx.showToast({
|
|
title: '已暂停',
|
|
icon: 'success'
|
|
})
|
|
|
|
setTimeout(() => {
|
|
wx.navigateBack()
|
|
}, 1500)
|
|
|
|
} catch (error) {
|
|
wx.showToast({
|
|
title: error.message || '操作失败',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
// 结束游戏
|
|
endGame() {
|
|
wx.showModal({
|
|
title: '结束牌局',
|
|
content: '确定要结束牌局吗?结束后将无法继续记账',
|
|
confirmColor: '#ff4444',
|
|
success: async (res) => {
|
|
if (res.confirm) {
|
|
wx.showLoading({ title: '处理中...' })
|
|
|
|
try {
|
|
await request.post(`/rooms/${this.data.sessionId}/end`)
|
|
|
|
wx.hideLoading()
|
|
wx.showToast({
|
|
title: '牌局已结束',
|
|
icon: 'success'
|
|
})
|
|
|
|
// 跳转到统计页
|
|
setTimeout(() => {
|
|
wx.redirectTo({
|
|
url: `/pages/stats/session/session?id=${this.data.sessionId}`
|
|
})
|
|
}, 1500)
|
|
|
|
} catch (error) {
|
|
wx.hideLoading()
|
|
wx.showToast({
|
|
title: error.message || '操作失败',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
// 下拉刷新
|
|
onPullDownRefresh() {
|
|
Promise.all([
|
|
this.loadSessionData(),
|
|
this.loadRecentRecords()
|
|
]).then(() => {
|
|
wx.stopPullDownRefresh()
|
|
})
|
|
}
|
|
}) |