update:优化

This commit is contained in:
2026-05-25 14:28:42 +08:00
parent fe8b38bc6f
commit 1e568db861

View File

@@ -41,6 +41,7 @@ const AUDIO_TIMEOUT_PER_KEY = 2600;
const AUDIO_TIMEOUT_MAX = 12000;
const BATTLE_CANCEL_RETURN_DELAY = 2000;
const ROUND_AUDIO_NAMES = ["一", "二", "三", "四", "五"];
const X_RING_STREAKS_KEY = "team-battle-x-ring-streaks";
const PROGRESS_ZERO_EVENT = "team-battle-progress-zero";
const COUNTDOWN_READY_EVENT = "team-battle-countdown-ready";
@@ -107,6 +108,21 @@ watch(online, (newVal, oldVal) => {
});
// 统一把秒级或毫秒级时间戳转成毫秒,方便和本机时间比较。
function loadXRingStreaks() {
const cached = uni.getStorageSync(X_RING_STREAKS_KEY);
xRingStreaks.value =
cached && typeof cached === "object" && !Array.isArray(cached) ? cached : {};
}
function saveXRingStreaks() {
uni.setStorageSync(X_RING_STREAKS_KEY, xRingStreaks.value);
}
function clearXRingStreaks() {
xRingStreaks.value = {};
uni.removeStorageSync(X_RING_STREAKS_KEY);
}
function normalizeTimestamp(value) {
const numberValue = Number(value || 0);
if (!numberValue) return 0;
@@ -213,11 +229,19 @@ function waitForRoundTipClosed(isFinal) {
});
}
function handleRoundTipAutoClose() {
function closeRoundTip() {
showRoundTip.value = false;
clearRoundTipWaiters();
}
function cancelRoundTipDisplay() {
closeRoundTip();
}
function handleRoundTipAutoClose() {
closeRoundTip();
}
function markProgressDeadline(countdown, delayMs = 0) {
if (!countdown?.value || !countdown?.durationMs) {
progressDeadlineAt = 0;
@@ -283,7 +307,7 @@ function invalidateBattleQueue({ stopAudio = false, stopProgress = false } = {})
clearAudioWaiters();
progressDeadlineAt = 0;
clearProgressZeroWaiters();
clearRoundTipWaiters();
cancelRoundTipDisplay();
if (stopAudio) audioManager.stopAll();
if (stopProgress) uni.$emit("update-remain", { stop: true });
}
@@ -442,6 +466,44 @@ function updateGoldenRound(battleInfo) {
goldenRound.value = Math.max(1, finishedGoldCount + (battleInfo.current?.playerId ? 1 : 0));
}
// Restore an info snapshot whose eventType points at the NewRound phase.
function getRestorePrevRound(battleInfo) {
const currentRoundValue = Number(battleInfo?.current?.round || 0);
if (currentRoundValue > 1) return currentRoundValue - 1;
const rounds = Array.isArray(battleInfo?.rounds) ? battleInfo.rounds : [];
return Math.max(1, rounds.length || 1);
}
function applyRestoreNewRoundSnapshot(battleInfo) {
const prevRound = getRestorePrevRound(battleInfo);
start.value = true;
showRoundTip.value = false;
scores.value = [];
blueScores.value = [];
currentRound.value = prevRound;
if (battleInfo.current?.goldRound) {
store.updateShotInfo(0, 0);
currentBluePoint.value = battleInfo.teams?.[1]?.score ?? 0;
currentRedPoint.value = battleInfo.teams?.[2]?.score ?? 0;
} else {
const latestRound = battleInfo.rounds?.[prevRound - 1];
if (battleInfo?.shootNumber) {
store.updateShotInfo(0, battleInfo.shootNumber);
}
if (latestRound) {
currentBluePoint.value = latestRound.scores?.[1]?.score ?? 0;
currentRedPoint.value = latestRound.scores?.[2]?.score ?? 0;
} else {
currentBluePoint.value = 0;
currentRedPoint.value = 0;
}
}
return prevRound;
}
// 回填比赛基础信息:队伍、比分、轮次、金箭状态等公共字段都在这里统一处理。
function applyBattleBase(battleInfo) {
if (!battleInfo) return;
@@ -650,7 +712,7 @@ function applyReadyState(battleInfo) {
updateTips("");
progressDeadlineAt = 0;
clearProgressZeroWaiters();
clearRoundTipWaiters();
cancelRoundTipDisplay();
const createTime = normalizeTimestamp(battleInfo?.createTime || Date.now());
const readyElapsed = (Date.now() - createTime) / 1000;
@@ -662,7 +724,7 @@ function applyReadyState(battleInfo) {
}
// 快照恢复入口:只把页面拉到服务端最新状态,不重放已经发生过的语音。
function applyBattleSnapshot(battleInfo, { restore = false } = {}) {
function applyBattleSnapshot(battleInfo, { restore = false, restoreEventType = 0 } = {}) {
// 快照恢复只负责“把页面拉回最新状态”,不重放历史语音。
applyBattleBase(battleInfo);
if (battleInfo.status === 0) {
@@ -672,6 +734,12 @@ function applyBattleSnapshot(battleInfo, { restore = false } = {}) {
start.value = true;
showRoundTip.value = false;
if (restore && restoreEventType === MESSAGETYPESV2.NewRound) {
applyRestoreNewRoundSnapshot(battleInfo);
return;
}
updateShotInfo(battleInfo);
updateCurrentRoundScores(battleInfo);
@@ -699,6 +767,7 @@ function applyBattleSnapshot(battleInfo, { restore = false } = {}) {
// 开局任务:切换到正式比赛态,并播报“比赛开始”。
async function runBattleStartTask(task, runId) {
// 开赛任务只负责切换正式态并播“比赛开始”,后续进入队列顺序。
clearXRingStreaks();
applyBattleBase(task.message);
start.value = true;
pendingRoundAudio = true;
@@ -711,12 +780,20 @@ async function runBattleStartTask(task, runId) {
async function runToSomeoneShootTask(task, runId) {
// 新射手任务:先等上一轮倒计时归零,再更新展示、播轮次/射手语音、启动倒计时。
const battleInfo = task.message;
const shouldEnterImmediately = showRoundTip.value;
if (shouldEnterImmediately) {
cancelRoundTipDisplay();
progressDeadlineAt = 0;
clearProgressZeroWaiters();
} else {
await waitForProgressZero();
}
if (!isQueueAlive(runId)) return;
applyBattleBase(battleInfo);
start.value = true;
showRoundTip.value = false;
hideRestoreLoading();
cancelRoundTipDisplay();
updateShotInfo(battleInfo);
const current = battleInfo.current || {};
@@ -769,12 +846,17 @@ function updateXRingStreak(shooterId, isXRing) {
const id = String(shooterId);
if (!isXRing) {
xRingStreaks.value[id] = 0;
saveXRingStreaks();
return false;
}
xRingStreaks.value[id] = (xRingStreaks.value[id] || 0) + 1;
if (xRingStreaks.value[id] < 3) return false;
if (xRingStreaks.value[id] < 3) {
saveXRingStreaks();
return false;
}
xRingStreaks.value[id] = 0;
saveXRingStreaks();
return true;
}
@@ -818,7 +900,7 @@ async function runShootResultTask(task) {
async function runNewRoundTask(task, runId) {
// 新回合提示要故意延后一点,避免和上一箭结果展示抢先后顺序。
const battleInfo = task.message;
const prevRound = currentRound.value;
const prevRound = task.restorePrevRound || currentRound.value;
await new Promise((resolve) => setTimeout(resolve, ROUND_TIP_DELAY));
if (!isQueueAlive(runId)) return;
@@ -854,9 +936,6 @@ async function runNewRoundTask(task, runId) {
currentRedPoint.value = 0;
}
pendingRoundAudio = true;
await waitForRoundTipClosed(!!battleInfo.current?.goldRound);
if (!isQueueAlive(runId)) return;
showRoundTip.value = false;
}
// 终局任务:播放结束语音后,根据状态跳结果页或返回上一页。
@@ -864,6 +943,7 @@ async function runBattleEndTask(task, runId) {
const battleInfo = task.message;
applyBattleBase(battleInfo);
battleEnded = true;
clearXRingStreaks();
matchStatus.value = battleInfo.status;
if (battleInfo.status === 4) {
showRoundTip.value = true;
@@ -924,15 +1004,44 @@ async function restoreLatestBattle() {
latestAppliedServerTime.value = Math.max(latestAppliedServerTime.value, snapshotTime);
}
const restoreEventType = Number(result?.eventType || 0);
if (result.status === 2) {
clearXRingStreaks();
hideRestoreLoading();
uni.redirectTo({
url: `/pages/friend-battle-result?battleId=${result.matchId}`,
});
return;
}
if (result.status === 4) {
clearXRingStreaks();
}
applyBattleSnapshot(result, { restore: true });
if (restoreEventType === MESSAGETYPESV2.NewRound) {
const prevRound = getRestorePrevRound(result);
const restoreMessage = { ...result, type: MESSAGETYPESV2.NewRound };
const restoreKey = getMessageKey(restoreMessage);
applyBattleSnapshot(result, { restore: true, restoreEventType });
if (!handledMessageKeys.has(restoreKey) && !queuedMessageKeys.has(restoreKey)) {
queuedMessageKeys.add(restoreKey);
battleQueue.value.unshift({
message: result,
type: MESSAGETYPESV2.NewRound,
key: restoreKey,
serverTime: snapshotTime,
receivedAt: Date.now(),
order: ++queueOrder,
restorePrevRound: prevRound,
});
}
runBattleQueue();
return;
}
applyBattleSnapshot(result, { restore: true, restoreEventType });
runBattleQueue();
}
@@ -984,7 +1093,7 @@ onLoad((options) => {
shootTimeTotal.value = DEFAULT_SHOOT_TIME;
showOfflineModal.value = false;
hideRestoreLoading();
xRingStreaks.value = {};
loadXRingStreaks();
queueGeneration += 1;
battleQueue.value = [];
queueRunning.value = false;
@@ -998,7 +1107,7 @@ onLoad((options) => {
queuedMessageKeys.clear();
progressDeadlineAt = 0;
clearProgressZeroWaiters();
clearRoundTipWaiters();
cancelRoundTipDisplay();
store.updateShotInfo(0, 0);
store.updateTips("");
latestShotFlash.value = null;