1038 lines
26 KiB
JavaScript
1038 lines
26 KiB
JavaScript
// pages/game/detail/detail.js
|
||
import request from '../../../utils/request'
|
||
import { formatTime } from '../../../utils/format'
|
||
|
||
// 格式化积分显示(超过1000显示k)
|
||
function formatScore(score) {
|
||
const num = parseFloat(score) || 0
|
||
if (Math.abs(num) >= 1000) {
|
||
return (num / 1000).toFixed(1) + 'k'
|
||
}
|
||
return num.toString()
|
||
}
|
||
|
||
Page({
|
||
data: {
|
||
sessionId: null,
|
||
session: null,
|
||
players: [],
|
||
records: [],
|
||
logs: [],
|
||
logsScrollTop: 0,
|
||
hasMoreLogs: false,
|
||
logsPage: 1,
|
||
userInfo: null,
|
||
isHost: false,
|
||
isInSession: false,
|
||
totalRounds: 0,
|
||
showShareModal: false,
|
||
showPlayerModal: false,
|
||
showExpenseModal: false,
|
||
showSettingsModal: false,
|
||
selectedPlayer: null,
|
||
scoreInput: '',
|
||
otherPlayers: [],
|
||
expenseInputs: {},
|
||
tableFee: 0,
|
||
quickInputs: [50, 100, 200, 500],
|
||
ttsEnabled: true, // 语音播报开关,默认开启
|
||
refreshTimer: null,
|
||
navTitle: '房间详情',
|
||
announcement: '',
|
||
navbarHeight: 0, // 导航栏高度
|
||
qrcodeUrl: '', // 二维码URL
|
||
hasShownRejoinPrompt: false, // 标记是否已显示过重新加入提示
|
||
|
||
statusText: {
|
||
'waiting': '等待中',
|
||
'playing': '游戏中',
|
||
'paused': '已暂停',
|
||
'finished': '已结束'
|
||
},
|
||
|
||
gameTypeText: {
|
||
'mahjong': '麻将',
|
||
'poker': '扑克',
|
||
'other': '其他'
|
||
}
|
||
},
|
||
|
||
onLoad(options) {
|
||
// 计算导航栏高度
|
||
const windowInfo = wx.getWindowInfo()
|
||
const menuButtonInfo = wx.getMenuButtonBoundingClientRect()
|
||
const statusBarHeight = windowInfo.statusBarHeight
|
||
const menuButtonTop = menuButtonInfo.top
|
||
const navbarHeight = menuButtonInfo.bottom + (menuButtonTop - statusBarHeight)
|
||
this.setData({ navbarHeight })
|
||
|
||
if (!options.id) {
|
||
wx.showToast({
|
||
title: '牌局不存在',
|
||
icon: 'none'
|
||
})
|
||
setTimeout(() => {
|
||
wx.navigateBack()
|
||
}, 1500)
|
||
return
|
||
}
|
||
console.log(options.id)
|
||
this.setData({
|
||
sessionId: options.id
|
||
})
|
||
// 获取用户信息
|
||
const app = getApp()
|
||
const userInfo = app.getUserInfo()
|
||
if (!userInfo) {
|
||
wx.showToast({
|
||
title: '请先登录',
|
||
icon: 'none'
|
||
})
|
||
setTimeout(() => {
|
||
wx.navigateBack()
|
||
}, 1500)
|
||
return
|
||
}
|
||
|
||
this.setData({ userInfo })
|
||
|
||
// 加载TTS设置
|
||
const ttsEnabled = wx.getStorageSync('ttsEnabled')
|
||
if (ttsEnabled !== '') {
|
||
this.setData({ ttsEnabled: ttsEnabled })
|
||
}
|
||
|
||
// 加载公告
|
||
this.loadAnnouncements()
|
||
|
||
// 加载牌局详情(包含日志)
|
||
this.loadSessionDetail()
|
||
|
||
// 设置自动刷新
|
||
this.startAutoRefresh()
|
||
|
||
},
|
||
|
||
onShow() {
|
||
if (this.data.sessionId) {
|
||
this.loadSessionDetail()
|
||
// 页面重新显示时,重启自动刷新
|
||
this.startAutoRefresh()
|
||
}
|
||
},
|
||
|
||
onHide() {
|
||
// 页面隐藏时清除定时器,避免后台继续请求
|
||
this.stopAutoRefresh()
|
||
},
|
||
|
||
onUnload() {
|
||
// 页面卸载时清除定时器
|
||
this.stopAutoRefresh()
|
||
},
|
||
|
||
// 停止自动刷新
|
||
stopAutoRefresh() {
|
||
if (this.data.refreshTimer) {
|
||
clearInterval(this.data.refreshTimer)
|
||
this.setData({ refreshTimer: null })
|
||
}
|
||
},
|
||
|
||
// 启动自动刷新
|
||
startAutoRefresh() {
|
||
// 如果已有定时器,先清除
|
||
this.stopAutoRefresh()
|
||
|
||
// 每5秒刷新一次
|
||
const timer = setInterval(() => {
|
||
if (this.data.session) {
|
||
this.loadSessionDetail(true)
|
||
}
|
||
}, 5000)
|
||
|
||
this.setData({ refreshTimer: timer })
|
||
},
|
||
|
||
// 加载公告
|
||
async loadAnnouncements() {
|
||
try {
|
||
const data = await request.get('/announcements')
|
||
if (data && data.length > 0) {
|
||
// 将最新的2条公告用"|"连接
|
||
const announcementText = data.map(item => item.content).join(' | ')
|
||
this.setData({ announcement: announcementText })
|
||
}
|
||
} catch (error) {
|
||
console.error('加载公告失败:', error)
|
||
// 使用默认公告
|
||
this.setData({ announcement: '欢迎来到打牌记账,祝大家游戏愉快!' })
|
||
}
|
||
},
|
||
|
||
// 加载牌局实时数据(统一接口)
|
||
async loadSessionDetail(silent = false) {
|
||
if (!silent) {
|
||
wx.showLoading({ title: '加载中...' })
|
||
}
|
||
|
||
try {
|
||
// 调用统一的实时数据接口
|
||
const realtimeData = await request.get(`/rooms/${this.data.sessionId}/realtime`)
|
||
|
||
const { room, players, records, logs, user_info } = realtimeData
|
||
|
||
// 检测用户是否曾经在房间但已离开(仅在初次加载时,不是自动刷新,并且未显示过提示)
|
||
if (!silent && user_info.has_left && !this.data.hasShownRejoinPrompt) {
|
||
if (!silent) {
|
||
wx.hideLoading()
|
||
}
|
||
|
||
// 标记已显示过提示,避免重复弹窗
|
||
this.setData({ hasShownRejoinPrompt: true })
|
||
|
||
// 停止自动刷新
|
||
this.stopAutoRefresh()
|
||
|
||
wx.showModal({
|
||
title: '检测到您已离开此房间',
|
||
content: '您之前已离开过此房间,是否重新加入?',
|
||
confirmText: '重新加入',
|
||
cancelText: '返回首页',
|
||
success: async (res) => {
|
||
if (res.confirm) {
|
||
// 重新加入房间
|
||
try {
|
||
wx.showLoading({ title: '加入中...' })
|
||
await request.post('/rooms/join', {
|
||
room_code: room.room_code
|
||
})
|
||
wx.hideLoading()
|
||
wx.showToast({
|
||
title: '重新加入成功',
|
||
icon: 'success'
|
||
})
|
||
// 刷新页面并重启自动刷新
|
||
this.loadSessionDetail()
|
||
this.startAutoRefresh()
|
||
} catch (error) {
|
||
wx.hideLoading()
|
||
wx.showToast({
|
||
title: error.message || '加入失败',
|
||
icon: 'none'
|
||
})
|
||
// 返回首页
|
||
setTimeout(() => {
|
||
wx.switchTab({
|
||
url: '/pages/index/index'
|
||
})
|
||
}, 1500)
|
||
}
|
||
} else {
|
||
// 返回首页(tabBar页面使用switchTab)
|
||
wx.switchTab({
|
||
url: '/pages/index/index'
|
||
})
|
||
}
|
||
}
|
||
})
|
||
return
|
||
}
|
||
|
||
// 检测房间状态变化(仅在自动刷新时)
|
||
if (silent && this.data.session) {
|
||
const oldStatus = this.data.session.status
|
||
const newStatus = room.status
|
||
const oldIsInSession = this.data.isInSession
|
||
const newIsInSession = user_info.is_in_session
|
||
|
||
// 1. 检测房间是否已关闭
|
||
if (oldStatus === 'playing' && newStatus === 'finished') {
|
||
// 停止自动刷新
|
||
this.stopAutoRefresh()
|
||
|
||
wx.showModal({
|
||
title: '牌局已结束',
|
||
content: '牌局已经结束,是否查看战绩?',
|
||
confirmText: '查看战绩',
|
||
cancelText: '退出',
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
// 跳转到统计页(tabBar页面使用switchTab)
|
||
wx.switchTab({
|
||
url: '/pages/stats/personal/personal'
|
||
})
|
||
} else {
|
||
// 返回首页(tabBar页面使用switchTab)
|
||
wx.switchTab({
|
||
url: '/pages/index/index'
|
||
})
|
||
}
|
||
}
|
||
})
|
||
return
|
||
}
|
||
|
||
// 2. 检测用户是否离开了房间
|
||
if (oldIsInSession && !newIsInSession) {
|
||
// 停止自动刷新
|
||
this.stopAutoRefresh()
|
||
|
||
wx.showModal({
|
||
title: '已离开房间',
|
||
content: '您已离开此牌局,是否重新加入?',
|
||
confirmText: '重新加入',
|
||
cancelText: '返回首页',
|
||
success: async (res) => {
|
||
if (res.confirm) {
|
||
// 重新加入房间
|
||
try {
|
||
wx.showLoading({ title: '加入中...' })
|
||
await request.post('/rooms/join', {
|
||
room_code: this.data.session.room_code
|
||
})
|
||
wx.hideLoading()
|
||
wx.showToast({
|
||
title: '重新加入成功',
|
||
icon: 'success'
|
||
})
|
||
// 刷新页面并重启自动刷新
|
||
this.loadSessionDetail()
|
||
this.startAutoRefresh()
|
||
} catch (error) {
|
||
wx.hideLoading()
|
||
wx.showToast({
|
||
title: error.message || '加入失败',
|
||
icon: 'none'
|
||
})
|
||
// 返回首页
|
||
setTimeout(() => {
|
||
wx.redirectTo({
|
||
url: '/pages/index/index'
|
||
})
|
||
}, 1500)
|
||
}
|
||
} else {
|
||
// 返回首页(tabBar页面使用switchTab)
|
||
wx.switchTab({
|
||
url: '/pages/index/index'
|
||
})
|
||
}
|
||
}
|
||
})
|
||
return
|
||
}
|
||
}
|
||
|
||
// 格式化创建时间
|
||
const createTime = formatTime(new Date(room.created_at * 1000))
|
||
|
||
// 格式化战绩时间
|
||
const formattedRecords = (records || []).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')}`
|
||
}
|
||
})
|
||
|
||
// 格式化日志时间
|
||
const formattedLogs = (logs || []).map(log => {
|
||
const time = new Date(log.created_at * 1000)
|
||
const month = String(time.getMonth() + 1).padStart(2, '0')
|
||
const day = String(time.getDate()).padStart(2, '0')
|
||
const hours = String(time.getHours()).padStart(2, '0')
|
||
const minutes = String(time.getMinutes()).padStart(2, '0')
|
||
const seconds = String(time.getSeconds()).padStart(2, '0')
|
||
return {
|
||
...log,
|
||
timeText: `${month}-${day} ${hours}:${minutes}:${seconds}`
|
||
}
|
||
})
|
||
|
||
// 查找房主昵称
|
||
const hostPlayer = players.find(p => p.is_host)
|
||
//const hostNickname = hostPlayer ? hostPlayer.nickname : '房主'
|
||
const navTitle = `${room.room_name}`
|
||
|
||
// 获取除自己外的其他玩家
|
||
const otherPlayers = players.filter(p => p.player_id !== this.data.userInfo.id)
|
||
|
||
// 更新快捷输入设置
|
||
const quickInputs = room.quick_settings || [10, 20, 30]
|
||
|
||
// 格式化玩家积分显示
|
||
const formattedPlayers = players.map(p => ({
|
||
...p,
|
||
formatted_score: formatScore(p.total_win_loss)
|
||
}))
|
||
|
||
this.setData({
|
||
session: room,
|
||
players: formattedPlayers,
|
||
records: formattedRecords,
|
||
logs: formattedLogs,
|
||
isInSession: user_info.is_in_session,
|
||
isHost: user_info.is_host,
|
||
createTime,
|
||
totalRounds: room.total_rounds || 0,
|
||
navTitle,
|
||
otherPlayers,
|
||
quickInputs,
|
||
tableFee: room.table_fee || 0
|
||
})
|
||
|
||
if (!silent) {
|
||
wx.hideLoading()
|
||
}
|
||
|
||
} catch (error) {
|
||
// 静默刷新时忽略错误(网络问题等),避免打扰用户
|
||
if (!silent) {
|
||
wx.hideLoading()
|
||
wx.showToast({
|
||
title: error.message || '加载失败',
|
||
icon: 'none'
|
||
})
|
||
} else {
|
||
// 静默刷新失败时,仅在控制台记录错误,不显示给用户
|
||
console.warn('自动刷新失败:', error)
|
||
}
|
||
}
|
||
},
|
||
|
||
// 开始游戏
|
||
async startGame() {
|
||
if (this.data.players.length < 2) {
|
||
wx.showToast({
|
||
title: '至少需要2人才能开始',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
wx.showModal({
|
||
title: '开始游戏',
|
||
content: `确定要开始游戏吗?当前${this.data.players.length}人`,
|
||
success: async (res) => {
|
||
if (res.confirm) {
|
||
wx.showLoading({ title: '启动中...' })
|
||
|
||
try {
|
||
await request.post(`/rooms/${this.data.sessionId}/start`)
|
||
|
||
wx.hideLoading()
|
||
wx.showToast({
|
||
title: '游戏已开始',
|
||
icon: 'success'
|
||
})
|
||
|
||
// 刷新页面
|
||
this.loadSessionDetail()
|
||
|
||
// 跳转到记账页
|
||
setTimeout(() => {
|
||
this.goToPlay()
|
||
}, 1500)
|
||
|
||
} catch (error) {
|
||
wx.hideLoading()
|
||
wx.showToast({
|
||
title: error.message || '启动失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
})
|
||
},
|
||
|
||
// 暂停游戏
|
||
async 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'
|
||
})
|
||
|
||
this.loadSessionDetail()
|
||
|
||
} catch (error) {
|
||
wx.showToast({
|
||
title: error.message || '操作失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
})
|
||
},
|
||
|
||
// 结束牌局
|
||
confirmEndSession() {
|
||
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'
|
||
})
|
||
|
||
this.loadSessionDetail()
|
||
|
||
} catch (error) {
|
||
wx.hideLoading()
|
||
wx.showToast({
|
||
title: error.message || '操作失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
})
|
||
},
|
||
|
||
// 返回上一页(不离开房间)
|
||
confirmLeaveSession() {
|
||
wx.navigateBack()
|
||
},
|
||
|
||
// 加入牌局
|
||
async joinSession() {
|
||
wx.showLoading({ title: '加入中...' })
|
||
|
||
try {
|
||
await request.post('/rooms/join', {
|
||
session_id: this.data.sessionId
|
||
})
|
||
|
||
wx.hideLoading()
|
||
wx.showToast({
|
||
title: '加入成功',
|
||
icon: 'success'
|
||
})
|
||
|
||
// 刷新页面
|
||
this.loadSessionDetail()
|
||
|
||
} catch (error) {
|
||
wx.hideLoading()
|
||
wx.showToast({
|
||
title: error.message || '加入失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
|
||
// 显示分享弹窗
|
||
async shareSession() {
|
||
// 打开分享弹窗时暂停自动刷新
|
||
this.stopAutoRefresh()
|
||
this.setData({
|
||
showShareModal: true,
|
||
qrcodeUrl: '' // 重置二维码
|
||
})
|
||
|
||
// 生成二维码
|
||
await this.generateQRCode()
|
||
},
|
||
|
||
// 生成二维码
|
||
async generateQRCode() {
|
||
if (!this.data.session || !this.data.session.invite_code) {
|
||
console.error('无法生成二维码: session或invite_code不存在', this.data.session)
|
||
wx.showToast({
|
||
title: '房间信息不完整',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
try {
|
||
const app = getApp()
|
||
const scene = `qrcode&code=${this.data.session.invite_code}`
|
||
|
||
console.log('开始生成二维码, scene:', scene, 'invite_code:', this.data.session.invite_code)
|
||
|
||
wx.showLoading({ title: '生成二维码...' })
|
||
|
||
const qrcodeBuffer = await app.getQrcode(scene)
|
||
|
||
console.log('二维码数据返回:', qrcodeBuffer)
|
||
|
||
wx.hideLoading()
|
||
|
||
// 检查返回数据类型
|
||
if (!qrcodeBuffer) {
|
||
throw new Error('二维码数据为空')
|
||
}
|
||
|
||
// 将arraybuffer转换为base64
|
||
const base64 = wx.arrayBufferToBase64(qrcodeBuffer)
|
||
const qrcodeUrl = `data:image/png;base64,${base64}`
|
||
|
||
console.log('base64长度:', base64.length)
|
||
|
||
this.setData({
|
||
qrcodeUrl: qrcodeUrl
|
||
})
|
||
|
||
} catch (error) {
|
||
wx.hideLoading()
|
||
console.error('生成二维码失败:', error)
|
||
wx.showToast({
|
||
title: error.message || '二维码生成失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
|
||
// 关闭分享弹窗
|
||
closeShareModal() {
|
||
this.setData({
|
||
showShareModal: false
|
||
})
|
||
// 关闭分享弹窗后恢复自动刷新
|
||
this.startAutoRefresh()
|
||
},
|
||
|
||
// 复制邀请码
|
||
copyInviteCode() {
|
||
wx.setClipboardData({
|
||
data: this.data.session.invite_code,
|
||
success: () => {
|
||
wx.showToast({
|
||
title: '已复制邀请码',
|
||
icon: 'success'
|
||
})
|
||
}
|
||
})
|
||
},
|
||
|
||
// 进入记账页
|
||
goToPlay() {
|
||
wx.navigateTo({
|
||
url: `/pages/game/settlement/settlement?id=${this.data.sessionId}`
|
||
})
|
||
},
|
||
|
||
// 查看统计
|
||
goToStats() {
|
||
wx.navigateTo({
|
||
url: `/pages/stats/session/session?id=${this.data.sessionId}`
|
||
})
|
||
},
|
||
|
||
// 查看所有战绩
|
||
goToRecords() {
|
||
wx.navigateTo({
|
||
url: `/pages/game/records/records?id=${this.data.sessionId}`
|
||
})
|
||
},
|
||
|
||
// 再来一局
|
||
createNewSession() {
|
||
wx.showModal({
|
||
title: '再来一局',
|
||
content: '是否使用相同设置创建新牌局?',
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
wx.navigateTo({
|
||
url: `/pages/game/create/create?copy=${this.data.sessionId}`
|
||
})
|
||
}
|
||
}
|
||
})
|
||
},
|
||
|
||
// 下拉刷新
|
||
onPullDownRefresh() {
|
||
this.loadSessionDetail().then(() => {
|
||
wx.stopPullDownRefresh()
|
||
})
|
||
},
|
||
|
||
// 点击玩家卡片
|
||
onPlayerTap(e) {
|
||
const player = e.currentTarget.dataset.player
|
||
// 打开玩家弹窗时暂停自动刷新
|
||
this.stopAutoRefresh()
|
||
this.setData({
|
||
selectedPlayer: player,
|
||
showPlayerModal: true,
|
||
scoreInput: ''
|
||
})
|
||
},
|
||
|
||
// 关闭玩家弹窗
|
||
closePlayerModal() {
|
||
this.setData({
|
||
showPlayerModal: false,
|
||
selectedPlayer: null,
|
||
scoreInput: ''
|
||
})
|
||
// 关闭玩家弹窗后恢复自动刷新
|
||
this.startAutoRefresh()
|
||
},
|
||
|
||
// 分数输入
|
||
onScoreInput(e) {
|
||
this.setData({
|
||
scoreInput: e.detail.value
|
||
})
|
||
},
|
||
|
||
// 快捷输入
|
||
quickInput(e) {
|
||
const value = e.currentTarget.dataset.value
|
||
this.setData({
|
||
scoreInput: value
|
||
})
|
||
},
|
||
|
||
// 提交分数
|
||
async submitScore() {
|
||
const score = parseFloat(this.data.scoreInput)
|
||
|
||
// 验证金额格式(正数,最多2位小数)
|
||
if (isNaN(score) || score <= 0) {
|
||
wx.showToast({
|
||
title: '请输入有效金额',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
// 验证最大值99999
|
||
if (score > 99999) {
|
||
wx.showToast({
|
||
title: '金额不能超过99999',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
// 验证最多2位小数
|
||
if (!/^\d+(\.\d{1,2})?$/.test(this.data.scoreInput)) {
|
||
wx.showToast({
|
||
title: '金额最多保留2位小数',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
wx.showLoading({ title: '提交中...' })
|
||
|
||
try {
|
||
// 调用记分转账API(当前用户输给选中的玩家)
|
||
await request.post('/records/transfer', {
|
||
room_id: this.data.sessionId,
|
||
to_player_id: this.data.selectedPlayer.player_id,
|
||
amount: score
|
||
})
|
||
|
||
wx.hideLoading()
|
||
wx.showToast({
|
||
title: '记分成功',
|
||
icon: 'success'
|
||
})
|
||
|
||
// 播放TTS语音
|
||
const ttsText = `${this.data.userInfo.nickname}付给${this.data.selectedPlayer.nickname}${score}元`
|
||
this.playTTS(ttsText)
|
||
|
||
this.closePlayerModal()
|
||
this.loadSessionDetail()
|
||
|
||
} catch (error) {
|
||
wx.hideLoading()
|
||
wx.showToast({
|
||
title: error.message || '提交失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
|
||
|
||
// 显示支出弹窗
|
||
showExpenseModal() {
|
||
// 打开支出弹窗时暂停自动刷新
|
||
this.stopAutoRefresh()
|
||
this.setData({
|
||
showExpenseModal: true,
|
||
expenseInputs: {}
|
||
})
|
||
},
|
||
|
||
// 关闭支出弹窗
|
||
closeExpenseModal() {
|
||
this.setData({
|
||
showExpenseModal: false,
|
||
expenseInputs: {}
|
||
})
|
||
// 关闭支出弹窗后恢复自动刷新
|
||
this.startAutoRefresh()
|
||
},
|
||
|
||
// 支出金额输入
|
||
onExpenseInput(e) {
|
||
const index = e.currentTarget.dataset.index
|
||
const value = e.detail.value
|
||
const expenseInputs = {...this.data.expenseInputs}
|
||
expenseInputs[index] = value
|
||
this.setData({ expenseInputs })
|
||
},
|
||
|
||
// 提交支出
|
||
async submitExpense() {
|
||
const expenses = []
|
||
Object.keys(this.data.expenseInputs).forEach(index => {
|
||
const amount = parseFloat(this.data.expenseInputs[index])
|
||
if (!isNaN(amount) && amount > 0) {
|
||
// 验证最大值99999
|
||
if (amount > 99999) {
|
||
wx.showToast({
|
||
title: '金额不能超过99999',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
// 验证最多2位小数
|
||
if (!/^\d+(\.\d{1,2})?$/.test(this.data.expenseInputs[index])) {
|
||
wx.showToast({
|
||
title: '金额最多保留2位小数',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
expenses.push({
|
||
playerId: this.data.otherPlayers[index].player_id,
|
||
amount: amount
|
||
})
|
||
}
|
||
})
|
||
|
||
if (expenses.length === 0) {
|
||
wx.showToast({
|
||
title: '请至少输入一项支出',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
wx.showLoading({ title: '提交中...' })
|
||
|
||
try {
|
||
// 串行调用记分转账API(避免数据库死锁)
|
||
let successCount = 0
|
||
const successExpenses = []
|
||
for (const expense of expenses) {
|
||
try {
|
||
await request.post('/records/transfer', {
|
||
room_id: this.data.sessionId,
|
||
to_player_id: expense.playerId,
|
||
amount: expense.amount
|
||
})
|
||
successCount++
|
||
successExpenses.push(expense)
|
||
} catch (error) {
|
||
console.error('记分失败:', expense, error)
|
||
// 继续执行其他记分,不中断
|
||
}
|
||
}
|
||
|
||
wx.hideLoading()
|
||
|
||
if (successCount === expenses.length) {
|
||
wx.showToast({
|
||
title: `成功记录${successCount}笔支出`,
|
||
icon: 'success'
|
||
})
|
||
|
||
// 播放批量支出语音
|
||
if (successExpenses.length > 0) {
|
||
const ttsTexts = successExpenses.map(exp => {
|
||
const player = this.data.otherPlayers.find(p => p.player_id === exp.playerId)
|
||
return `${this.data.userInfo.nickname}付给${player.nickname}${exp.amount}元`
|
||
})
|
||
// 播放第一条(可以根据需要调整为播放所有或汇总)
|
||
this.playTTS(ttsTexts.join(','))
|
||
}
|
||
} else if (successCount > 0) {
|
||
wx.showToast({
|
||
title: `成功${successCount}笔,失败${expenses.length - successCount}笔`,
|
||
icon: 'none',
|
||
duration: 3000
|
||
})
|
||
|
||
// 播放成功的语音
|
||
if (successExpenses.length > 0) {
|
||
const ttsTexts = successExpenses.map(exp => {
|
||
const player = this.data.otherPlayers.find(p => p.player_id === exp.playerId)
|
||
return `${this.data.userInfo.nickname}付给${player.nickname}${exp.amount}元`
|
||
})
|
||
this.playTTS(ttsTexts.join(','))
|
||
}
|
||
} else {
|
||
wx.showToast({
|
||
title: '所有记分都失败了',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
|
||
this.closeExpenseModal()
|
||
this.loadSessionDetail()
|
||
|
||
} catch (error) {
|
||
wx.hideLoading()
|
||
wx.showToast({
|
||
title: error.message || '提交失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
|
||
// 显示设置弹窗
|
||
showSettingsModal() {
|
||
// 打开设置弹窗时暂停自动刷新
|
||
this.stopAutoRefresh()
|
||
this.setData({
|
||
showSettingsModal: true
|
||
})
|
||
},
|
||
|
||
// 关闭设置弹窗
|
||
closeSettingsModal() {
|
||
this.setData({
|
||
showSettingsModal: false
|
||
})
|
||
// 关闭设置弹窗后恢复自动刷新
|
||
this.startAutoRefresh()
|
||
},
|
||
|
||
// 桌位费输入
|
||
onTableFeeInput(e) {
|
||
this.setData({
|
||
tableFee: e.detail.value
|
||
})
|
||
},
|
||
|
||
// 语音播报开关切换
|
||
onTtsToggle(e) {
|
||
const ttsEnabled = e.detail.value
|
||
this.setData({ ttsEnabled })
|
||
// 保存到本地存储
|
||
wx.setStorageSync('ttsEnabled', ttsEnabled)
|
||
},
|
||
|
||
// TTS语音播放
|
||
async playTTS(text) {
|
||
// 如果语音播报关闭,直接返回
|
||
if (!this.data.ttsEnabled) {
|
||
return
|
||
}
|
||
|
||
try {
|
||
const result = await request.post('/tts/convert', { text })
|
||
|
||
if (result.audioUrl) {
|
||
// 使用音频URL直接播放
|
||
const innerAudioContext = wx.createInnerAudioContext()
|
||
innerAudioContext.src = `https://ca.miniappapi.com/mp${result.audioUrl}`
|
||
innerAudioContext.play()
|
||
|
||
// 播放完成后销毁音频上下文
|
||
innerAudioContext.onEnded(() => {
|
||
innerAudioContext.destroy()
|
||
})
|
||
|
||
// 播放失败处理
|
||
innerAudioContext.onError((error) => {
|
||
console.error('音频播放失败:', error)
|
||
innerAudioContext.destroy()
|
||
})
|
||
}
|
||
} catch (error) {
|
||
console.error('TTS转换失败:', error)
|
||
}
|
||
},
|
||
|
||
// 快捷输入值修改
|
||
onQuickInputChange(e) {
|
||
const index = e.currentTarget.dataset.index
|
||
const value = e.detail.value
|
||
const quickInputs = [...this.data.quickInputs]
|
||
quickInputs[index] = value
|
||
this.setData({ quickInputs })
|
||
},
|
||
|
||
// 删除快捷输入
|
||
deleteQuickInput(e) {
|
||
const index = e.currentTarget.dataset.index
|
||
const quickInputs = [...this.data.quickInputs]
|
||
quickInputs.splice(index, 1)
|
||
this.setData({ quickInputs })
|
||
},
|
||
|
||
// 添加快捷输入
|
||
addQuickInput() {
|
||
const quickInputs = [...this.data.quickInputs]
|
||
quickInputs.push('')
|
||
this.setData({ quickInputs })
|
||
},
|
||
|
||
// 保存设置
|
||
async saveSettings() {
|
||
wx.showLoading({ title: '保存中...' })
|
||
|
||
try {
|
||
await request.put(`/rooms/${this.data.sessionId}/settings`, {
|
||
table_fee: parseFloat(this.data.tableFee) || 0,
|
||
quick_settings: this.data.quickInputs.map(v => parseFloat(v) || 0)
|
||
})
|
||
|
||
wx.hideLoading()
|
||
wx.showToast({
|
||
title: '保存成功',
|
||
icon: 'success'
|
||
})
|
||
|
||
this.closeSettingsModal()
|
||
this.loadSessionDetail(true)
|
||
|
||
} catch (error) {
|
||
wx.hideLoading()
|
||
wx.showToast({
|
||
title: error.message || '保存失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
|
||
// 分享给朋友
|
||
onShareAppMessage() {
|
||
return {
|
||
title: `邀请你加入牌局:${this.data.session.room_name}`,
|
||
path: `/pages/game/join/join?code=${this.data.session.invite_code}`,
|
||
imageUrl: '/images/share-bg.png'
|
||
}
|
||
}
|
||
}) |