update:优化个人训练

This commit is contained in:
2026-07-27 16:38:53 +08:00
parent c5618fb60b
commit e6f11d3684
6 changed files with 221 additions and 48 deletions
+66 -2
View File
@@ -18,6 +18,7 @@ import {
startPractiseAPI,
endPractiseAPI,
getPractiseAPI,
getTrainingDifficultyListAPI,
} from "@/apis";
import {
connectMatchWebSocket,
@@ -52,6 +53,7 @@ const defaultTargetType = 1;
const total = ref(defaultTotal);
const practiseResult = ref({});
const practiceEndSnapshot = ref({});
const hasNextDifficulty = ref(false);
const practiseId = ref("");
const showGuide = ref(false);
const tips = ref("");
@@ -64,7 +66,6 @@ const visiblePrecisionTarget = ref({
randomRingArea: 0,
});
const trainingDifficultyStorageKey = "training-selection";
const trainingDifficultyRefreshEvent = "training-difficulty-refresh";
const useHighlightTest = ref(false);
const highlightTestState = ref({
blocks: 8,
@@ -87,6 +88,8 @@ let stopPracticeTask = null;
let practiceSyncTimer = null;
let waitingPracticeSync = false;
let shotPresentationGeneration = 0;
let nextDifficultyRequest = null;
let nextDifficultyRequestGeneration = 0;
const audioWaiters = new Set();
const shotEffectWaiters = new Map();
const PRACTICE_SYNC_TIMEOUT_MS = 5000;
@@ -152,6 +155,63 @@ const currentDifficultyLevel = computed(
getPositiveInteger(trainingParams.value.difficulty)
);
const resetNextDifficultyState = () => {
nextDifficultyRequestGeneration += 1;
nextDifficultyRequest = null;
hasNextDifficulty.value = false;
};
const loadNextDifficultyState = (result = {}) => {
const requestGeneration = ++nextDifficultyRequestGeneration;
const currentLevel =
getPositiveInteger(result.difficultyLevel) ||
getPositiveInteger(result.difficulty_level) ||
currentDifficultyLevel.value;
const currentTrainingType = result.trainingType || trainingType.value;
hasNextDifficulty.value = false;
if (!currentTrainingType || !currentLevel) {
nextDifficultyRequest = Promise.resolve(false);
return nextDifficultyRequest;
}
nextDifficultyRequest = getTrainingDifficultyListAPI(currentTrainingType)
.then((difficultyResult) => {
const levels = Array.isArray(difficultyResult?.list)
? difficultyResult.list
.filter(
(item) => !item?.type || item.type === currentTrainingType
)
.map((item) => getPositiveInteger(item?.difficulty))
.filter(Boolean)
: [];
const maxLevel = Math.max(0, ...levels);
const highestCompletedLevel = getPositiveInteger(
difficultyResult?.user_levels?.[currentTrainingType]
);
const latestUnlockedLevel = Math.min(
highestCompletedLevel + 1,
maxLevel
);
const canAdvance =
currentLevel < maxLevel && latestUnlockedLevel > currentLevel;
if (requestGeneration === nextDifficultyRequestGeneration) {
hasNextDifficulty.value = canAdvance;
}
return canAdvance;
})
.catch((error) => {
console.log("training next difficulty load failed", error);
if (requestGeneration === nextDifficultyRequestGeneration) {
hasNextDifficulty.value = false;
}
return false;
});
return nextDifficultyRequest;
};
// time_limit 缺失或非正数都表示整局不限时。
const timeLimit = computed(() => getPositiveInteger(practiceInfo.value.timeLimit));
const hasTimeLimit = computed(() => timeLimit.value > 0);
@@ -1007,11 +1067,13 @@ const onOver = async () => {
try {
const apiResult = (await getPractiseAPI(practiseId.value)) || {};
await (nextDifficultyRequest || loadNextDifficultyState(apiResult));
if (!enterPracticeResult(mergePracticeResult(apiResult))) {
pageStage.value = pageStages.DISTANCE;
}
} catch (error) {
if (Object.keys(practiceEndSnapshot.value).length > 0) {
await (nextDifficultyRequest || loadNextDifficultyState(practiceEndSnapshot.value));
enterPracticeResult(mergePracticeResult());
return;
}
@@ -1067,6 +1129,7 @@ async function onReceiveMessage(msg) {
}
} else if (msg.type === MESSAGETYPESV2.BattleEnd) {
practiceEndSnapshot.value = createPracticeEndSnapshot(msg);
void loadNextDifficultyState(practiceEndSnapshot.value);
if (
trainingType.value === "base" &&
Number(msg.status) === 3 &&
@@ -1093,7 +1156,6 @@ function onComplete() {
invalidateShotPresentations();
clearPracticeRuntimeContext();
closePracticeConnection("training-practice-complete");
uni.$emit(trainingDifficultyRefreshEvent);
uni.navigateBack();
}
@@ -1102,6 +1164,7 @@ async function onRetry() {
setPracticeAppHideResumable(false);
clearHighlightTestTimer();
useHighlightTest.value = false;
resetNextDifficultyState();
practiseId.value = "";
serverAddr.value = "";
practiseResult.value = {};
@@ -1332,6 +1395,7 @@ onBeforeUnmount(() => {
:onRetry="onRetry"
:trainingType="trainingType"
:difficultyLevel="currentDifficultyLevel"
:hasNextDifficulty="hasNextDifficulty"
:result="practiseResult"
/>
<canvas class="share-canvas" id="shareCanvas" type="2d"></canvas>