From b7fdf97156522fb05070193c0d92fd672ca49e8f Mon Sep 17 00:00:00 2001 From: chenlimao Date: Tue, 12 May 2026 10:36:27 +0800 Subject: [PATCH] =?UTF-8?q?fix=EF=BC=9A=E6=8E=92=E4=BD=8D=E8=B5=9B?= =?UTF-8?q?=E5=8C=B9=E9=85=8D=E9=A1=B5=E9=9D=A2=E9=80=BB=E8=BE=91=E4=BC=98?= =?UTF-8?q?=E5=8C=96=EF=BC=9A=E5=A2=9E=E5=8A=A0=E8=B6=85=E6=97=B6=E5=88=A4?= =?UTF-8?q?=E6=96=AD&websocket=E4=B8=A2=E5=A4=B1=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/match-page.vue | 82 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 4 deletions(-) diff --git a/src/pages/match-page.vue b/src/pages/match-page.vue index c1c1102..05358f2 100644 --- a/src/pages/match-page.vue +++ b/src/pages/match-page.vue @@ -3,22 +3,90 @@ import { ref, onMounted, onBeforeUnmount } from "vue"; import { onLoad, onShow, onHide } from "@dcloudio/uni-app"; import Container from "@/components/Container.vue"; import Matching from "@/components/Matching.vue"; -import { matchGameAPI } from "@/apis"; +import { matchGameAPI, getBattleAPI } from "@/apis"; import { MESSAGETYPESV2 } from "@/constants"; const gameType = ref(0); const teamSize = ref(0); const onComplete = ref(null); +/** 匹配超时计时器,用于检测 WS 消息丢失或真正超时 */ +const matchTimeoutTimer = ref(null); + +/** 匹配超时阈值(ms),后端设置 15s 匹配,前端预留 5s 冗余 */ +const MATCH_TIMEOUT_MS = 20 * 1000; + +/** 清除超时计时器 */ +const clearMatchTimeout = () => { + if (matchTimeoutTimer.value) { + clearTimeout(matchTimeoutTimer.value); + matchTimeoutTimer.value = null; + } +}; + +/** + * 超时处理:查询后端是否已分配对局 + * - 有对局 → WS 消息丢失场景,自动跳入 + * - 无对局 → 真正超时,提示用户并返回大厅 + */ +const handleMatchTimeout = async () => { + try { + const battle = await getBattleAPI(); + if (battle && battle.matchId) { + uni.showToast({ title: "匹配成功,正在进入...", icon: "none" }); + if (battle.mode <= 3) { + uni.redirectTo({ url: `/pages/team-battle?battleId=${battle.matchId}` }); + } else { + uni.redirectTo({ url: `/pages/melee-battle?battleId=${battle.matchId}` }); + } + } else { + uni.showToast({ title: "匹配超时,请重试", icon: "none" }); + try { + if (gameType.value && teamSize.value) { + await matchGameAPI(false, gameType.value, teamSize.value); + } + } catch (_) { /* 取消失败忽略 */ } + uni.navigateBack(); + } + } catch (e) { + uni.showToast({ title: "匹配超时,请重试", icon: "none" }); + uni.navigateBack(); + } +}; + async function stopMatch() { uni.$showHint(3); } +/** + * 取消匹配,带容错处理: + * - 取消成功 → 返回大厅 + * - 取消失败(后端已分配对局但 WS 未到达)→ 查询并跳入当前对局 + */ async function cancelMatch() { - if (gameType.value && teamSize.value) { - await matchGameAPI(false, gameType.value, teamSize.value); + clearMatchTimeout(); + try { + if (gameType.value && teamSize.value) { + await matchGameAPI(false, gameType.value, teamSize.value); + } + uni.navigateBack(); + } catch (e) { + // 取消匹配接口失败,尝试查询是否已被分配对局 + try { + const battle = await getBattleAPI(); + if (battle && battle.matchId) { + if (battle.mode <= 3) { + uni.redirectTo({ url: `/pages/team-battle?battleId=${battle.matchId}` }); + } else { + uni.redirectTo({ url: `/pages/melee-battle?battleId=${battle.matchId}` }); + } + } else { + uni.navigateBack(); + } + } catch (_) { + uni.navigateBack(); + } } - uni.navigateBack() } async function onReceiveMessage(msg) { @@ -26,6 +94,8 @@ async function onReceiveMessage(msg) { onComplete.value = () => {} } if (msg.type === MESSAGETYPESV2.AboutToStart) { + // 收到开始消息,清除超时计时器 + clearMatchTimeout(); // 使用后端下发的 mode 字段判断跳转目标,与好友约战(battle-room.vue)保持一致 // mode <= 3 为团队对抗,mode > 3 为大乱斗,覆盖全部 gameType(1~5),不再遗漏 if (msg.mode <= 3) { @@ -56,6 +126,7 @@ onMounted(() => { }); onBeforeUnmount(() => { + clearMatchTimeout(); uni.setKeepScreenOn({ keepScreenOn: false, }); @@ -66,6 +137,9 @@ onBeforeUnmount(() => { onShow(async () => { if (gameType.value && teamSize.value) { matchGameAPI(true, gameType.value, teamSize.value); + // 启动超时计时器,防止 WS 消息丢失或长时间无对手导致用户卡死 + clearMatchTimeout(); + matchTimeoutTimer.value = setTimeout(handleMatchTimeout, MATCH_TIMEOUT_MS); } });