Merge branch 'test' into feat-vip

This commit is contained in:
2026-07-03 17:04:09 +08:00
42 changed files with 2351 additions and 90 deletions
+73 -14
View File
@@ -30,11 +30,64 @@ const playersSorted = ref([]);
const playersScores = ref([]);
const halfTimeTip = ref(false);
const halfRest = ref(false);
const HALF_REST_SECONDS = 20;
const halfRestRemain = ref(HALF_REST_SECONDS);
let halfRestTimer = null;
/** 控制设备离线提示弹窗的显示状态 */
const showOfflineModal = ref(false);
/** 记录每位玩家当前半场连续 X 环数,key 为 playerId,用于触发 tententen 音效 */
/** 记录每位玩家当前半场连续 10 环及以上次数,key 为 playerId,用于触发 tententen 音效 */
const xRingStreaks = ref({});
function clearHalfRestCountdown() {
if (halfRestTimer) {
clearInterval(halfRestTimer);
halfRestTimer = null;
}
}
function getHalfRestSeconds(battleInfo) {
const remainCandidates = [
battleInfo?.halfRestRemain,
battleInfo?.halfRestRemainSeconds,
battleInfo?.restRemain,
battleInfo?.restRemainSeconds,
];
for (const item of remainCandidates) {
const remain = Number(item);
if (Number.isFinite(remain) && remain > 0 && remain <= HALF_REST_SECONDS) {
return Math.ceil(remain);
}
}
const endTime = Number(battleInfo?.halfRestEndTime ?? battleInfo?.restEndTime);
if (!Number.isFinite(endTime) || endTime <= 0) return HALF_REST_SECONDS;
const timestamp = endTime < 1e12 ? endTime * 1000 : endTime;
const diffSeconds = (timestamp - Date.now()) / 1000;
if (diffSeconds > 0 && diffSeconds <= HALF_REST_SECONDS) {
return Math.ceil(diffSeconds);
}
return HALF_REST_SECONDS;
}
function startHalfRestCountdown(seconds = HALF_REST_SECONDS) {
clearHalfRestCountdown();
halfRestRemain.value = Math.max(0, Math.ceil(Number(seconds) || HALF_REST_SECONDS));
if (halfRestRemain.value <= 0) return;
halfRestTimer = setInterval(() => {
if (halfRestRemain.value <= 1) {
halfRestRemain.value = 0;
clearHalfRestCountdown();
return;
}
halfRestRemain.value -= 1;
}, 1000);
}
const currentPlayer = computed(() =>
players.value.find((player) => String(player?.id) === String(user.value.id))
);
@@ -96,8 +149,7 @@ function recoverData(battleInfo, { force = false } = {}) {
halfTimeTip.value = true;
halfRest.value = true;
tips.value = "准备下半场";
// 剩余休息时间
// const remain = (Date.now() - battleInfo.timeoutTime) / 1000;
startHalfRestCountdown(getHalfRestSeconds(battleInfo));
setTimeout(() => {
uni.$emit("update-remain", 0);
}, 200);
@@ -128,23 +180,27 @@ onLoad(async (options) => {
});
/**
* 检测指定玩家连续 X 环是否达到 3 箭,达到则在环数播报入队后追加 tententen 音效
* 检测指定玩家连续 10 环及以上是否达到 3 箭,达到则在环数播报入队后追加 tententen 音效
* @param {number|string} playerId - 本次射手的 ID(大乱斗中 ShootResult 保留 playerId
* @param {boolean} isXRing - 本次射击是否为 X 环
* @param {boolean} isTenPlusRingShot - 本次射击是否为 10 环及以上
*/
function checkAndPlayTententen(playerId, isXRing) {
function isTenPlusRing(shot) {
return !!(shot?.ringX || Number(shot?.ring) >= 10);
}
function checkAndPlayTententen(playerId, isTenPlusRingShot) {
if (!playerId) return;
const id = parseInt(playerId);
if (isXRing) {
if (isTenPlusRingShot) {
xRingStreaks.value[id] = (xRingStreaks.value[id] || 0) + 1;
// 同一玩家连续 3 箭均为 X 环,追加到环数音效队列尾部播放
// 同一玩家连续 3 箭均为 10 环及以上,追加到环数音效队列尾部播放
if (xRingStreaks.value[id] >= 3) {
xRingStreaks.value[id] = 0;
// nextTick 确保 HeaderProgress 的环数播报已入队后再追加 tententen,避免播放顺序颠倒
nextTick(() => audioManager.play("tententen", false));
}
} else {
// 非 X 环则重置该玩家的连续计数
// 低于 10 环或未上靶则重置该玩家的连续计数
xRingStreaks.value[id] = 0;
}
}
@@ -152,6 +208,7 @@ function checkAndPlayTententen(playerId, isXRing) {
async function onReceiveMessage(msg) {
if (Array.isArray(msg)) return;
if (msg.type === MESSAGETYPESV2.BattleStart) {
clearHalfRestCountdown();
halfTimeTip.value = false;
halfRest.value = false;
recoverData(msg);
@@ -166,22 +223,23 @@ async function onReceiveMessage(msg) {
// 对比更新后数据找出箭数增加的玩家(即本次射手),并读取其最新箭的 ring 数据
const newRound = playersScores.value[playersScores.value.length - 1] || {};
let shooterId = null;
let isXRing = false;
let isTenPlusRingShot = false;
for (const pid of Object.keys(newRound)) {
const newLen = (newRound[pid] || []).length;
if (newLen > (prevCounts[pid] || 0)) {
shooterId = parseInt(pid);
const shot = newRound[pid][newLen - 1];
isXRing = !!(shot?.ringX && shot?.ring);
isTenPlusRingShot = isTenPlusRing(shot);
break;
}
}
// 检测同一玩家三箭全 X 环,触发 tententen 音效
checkAndPlayTententen(shooterId, isXRing);
// 检测同一玩家连续三箭 10 环及以上,触发 tententen 音效
checkAndPlayTententen(shooterId, isTenPlusRingShot);
} else if (msg.type === MESSAGETYPESV2.HalfRest) {
halfTimeTip.value = true;
halfRest.value = true;
tips.value = "准备下半场";
startHalfRestCountdown();
} else if (msg.type === MESSAGETYPESV2.BattleEnd) {
setTimeout(() => {
// 全部跳转到新结算页
@@ -202,6 +260,7 @@ onBeforeUnmount(() => {
uni.setKeepScreenOn({
keepScreenOn: false,
});
clearHalfRestCountdown();
uni.$off("socket-inbox", onReceiveMessage);
audioManager.stopAll();
});
@@ -268,7 +327,7 @@ onShow(async () => {
>
<view class="half-time-tip">
<text>上半场结束休息一下吧:</text>
<text>20秒后开始下半场</text>
<text>{{ halfRestRemain }}秒后开始下半场</text>
</view>
</ScreenHint>
<!-- 设备离线提示弹窗 -->