update:优化稳定训练
This commit is contained in:
@@ -14,6 +14,10 @@ const props = defineProps({
|
|||||||
type: Number,
|
type: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
|
introPending: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const WIDTH = 750;
|
const WIDTH = 750;
|
||||||
@@ -33,30 +37,28 @@ const ENTRY_ANIMATION_DURATION = 1000;
|
|||||||
const UPDATE_DURATION = 240;
|
const UPDATE_DURATION = 240;
|
||||||
const SWEEP_DELAY = 100;
|
const SWEEP_DELAY = 100;
|
||||||
const SWEEP_DURATION = 1000;
|
const SWEEP_DURATION = 1000;
|
||||||
const ASSET_ROOT = "https://static.shelingxingqiu.com/shootmini/static/training-difficulty-design/stability-energy";
|
const ASSET_ROOT =
|
||||||
const ASSET_VERSION = "20260922";
|
"/pages/training/static/stability-energy";
|
||||||
const getAssetSource = (filename) =>
|
const getAssetSource = (filename) => `${ASSET_ROOT}/${filename}`;
|
||||||
`${ASSET_ROOT}/${filename}?v=${ASSET_VERSION}`;
|
|
||||||
|
|
||||||
const instance = getCurrentInstance();
|
const instance = getCurrentInstance();
|
||||||
const canvasId = `stability-energy-${Math.random().toString(36).slice(2, 10)}`;
|
const canvasId = `stability-energy-${Math.random().toString(36).slice(2, 10)}`;
|
||||||
const canvasReady = ref(false);
|
const canvasReady = ref(false);
|
||||||
|
const fallbackVisible = ref(true);
|
||||||
const normalizedPercent = computed(() =>
|
const normalizedPercent = computed(() =>
|
||||||
Math.max(0, Math.min(100, Number(props.percent) || 0))
|
Math.max(0, Math.min(100, Number(props.percent) || 0))
|
||||||
);
|
);
|
||||||
const shouldPlayEntryAnimation = ref(normalizedPercent.value <= 0);
|
|
||||||
const fallbackImageSource = computed(
|
|
||||||
() =>
|
|
||||||
getAssetSource(
|
|
||||||
shouldPlayEntryAnimation.value ? "progress-full.png" : "progress-empty.png"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
let engine = null;
|
let engine = null;
|
||||||
let disposed = false;
|
let disposed = false;
|
||||||
let animationHandle = null;
|
let animationHandle = null;
|
||||||
let renderedPercent = normalizedPercent.value;
|
let renderedPercent = props.introPending ? 100 : normalizedPercent.value;
|
||||||
let entryAnimationPlaying = false;
|
let entryAnimationPlaying = false;
|
||||||
|
let entryAnimationRequested = false;
|
||||||
|
|
||||||
|
const showCanvas = () => {
|
||||||
|
canvasReady.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
const requestFrame = (callback) => {
|
const requestFrame = (callback) => {
|
||||||
if (typeof requestAnimationFrame === "function") {
|
if (typeof requestAnimationFrame === "function") {
|
||||||
@@ -81,6 +83,27 @@ const cancelFrame = () => {
|
|||||||
animationHandle = null;
|
animationHandle = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const waitForPaint = () =>
|
||||||
|
new Promise((resolve) => {
|
||||||
|
const schedule = (callback) => {
|
||||||
|
if (typeof requestAnimationFrame === "function") {
|
||||||
|
requestAnimationFrame(callback);
|
||||||
|
} else {
|
||||||
|
setTimeout(callback, 16);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
schedule(() => schedule(resolve));
|
||||||
|
});
|
||||||
|
|
||||||
|
const presentCanvas = async () => {
|
||||||
|
showCanvas();
|
||||||
|
await nextTick();
|
||||||
|
await waitForPaint();
|
||||||
|
if (disposed) return false;
|
||||||
|
fallbackVisible.value = false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
const smoothStep = (value) => {
|
const smoothStep = (value) => {
|
||||||
const amount = Math.max(0, Math.min(1, value));
|
const amount = Math.max(0, Math.min(1, value));
|
||||||
return amount * amount * (3 - 2 * amount);
|
return amount * amount * (3 - 2 * amount);
|
||||||
@@ -185,14 +208,11 @@ const loadCanvasImage = (canvas, source) =>
|
|||||||
image.src = source;
|
image.src = source;
|
||||||
});
|
});
|
||||||
|
|
||||||
const createEnergyEngine = async (canvas) => {
|
const createEnergyEngine = async (canvas, preloadedFullImage = null) => {
|
||||||
const context = canvas.getContext("2d");
|
const context = canvas.getContext("2d");
|
||||||
if (!context) throw new Error("Canvas unavailable");
|
if (!context) throw new Error("Canvas unavailable");
|
||||||
enableImageSmoothing(context);
|
enableImageSmoothing(context);
|
||||||
|
|
||||||
canvas.width = WIDTH;
|
|
||||||
canvas.height = HEIGHT;
|
|
||||||
|
|
||||||
const maskLayer = createOffscreenCanvas(canvas, MASK_WIDTH, MASK_HEIGHT);
|
const maskLayer = createOffscreenCanvas(canvas, MASK_WIDTH, MASK_HEIGHT);
|
||||||
const emptyLayer = createOffscreenCanvas(canvas);
|
const emptyLayer = createOffscreenCanvas(canvas);
|
||||||
const fullLayer = createOffscreenCanvas(canvas);
|
const fullLayer = createOffscreenCanvas(canvas);
|
||||||
@@ -208,6 +228,7 @@ const createEnergyEngine = async (canvas) => {
|
|||||||
|
|
||||||
const images = await Promise.all([
|
const images = await Promise.all([
|
||||||
loadCanvasImage(canvas, getAssetSource("progress-empty.png")),
|
loadCanvasImage(canvas, getAssetSource("progress-empty.png")),
|
||||||
|
preloadedFullImage ||
|
||||||
loadCanvasImage(canvas, getAssetSource("progress-full.png")),
|
loadCanvasImage(canvas, getAssetSource("progress-full.png")),
|
||||||
loadCanvasImage(canvas, getAssetSource("progress-glow.png")),
|
loadCanvasImage(canvas, getAssetSource("progress-glow.png")),
|
||||||
]);
|
]);
|
||||||
@@ -514,10 +535,11 @@ const drawPercent = (targetPercent, animate = true) => {
|
|||||||
const runEntryAnimation = () => {
|
const runEntryAnimation = () => {
|
||||||
if (!engine || disposed) return;
|
if (!engine || disposed) return;
|
||||||
cancelFrame();
|
cancelFrame();
|
||||||
|
entryAnimationRequested = false;
|
||||||
entryAnimationPlaying = true;
|
entryAnimationPlaying = true;
|
||||||
renderedPercent = 100;
|
renderedPercent = 100;
|
||||||
engine.draw(100);
|
engine.draw(100);
|
||||||
canvasReady.value = true;
|
showCanvas();
|
||||||
|
|
||||||
let startedAt = null;
|
let startedAt = null;
|
||||||
const step = (timestamp) => {
|
const step = (timestamp) => {
|
||||||
@@ -537,7 +559,6 @@ const runEntryAnimation = () => {
|
|||||||
|
|
||||||
animationHandle = null;
|
animationHandle = null;
|
||||||
entryAnimationPlaying = false;
|
entryAnimationPlaying = false;
|
||||||
shouldPlayEntryAnimation.value = false;
|
|
||||||
renderedPercent = 0;
|
renderedPercent = 0;
|
||||||
engine.draw(0);
|
engine.draw(0);
|
||||||
|
|
||||||
@@ -565,36 +586,82 @@ const initialize = async () => {
|
|||||||
|
|
||||||
if (disposed) return;
|
if (disposed) return;
|
||||||
if (!info?.node?.getContext) {
|
if (!info?.node?.getContext) {
|
||||||
shouldPlayEntryAnimation.value = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
engine = await createEnergyEngine(info.node);
|
const canvas = info.node;
|
||||||
|
canvas.width = WIDTH;
|
||||||
|
canvas.height = HEIGHT;
|
||||||
|
const context = canvas.getContext("2d");
|
||||||
|
if (!context) throw new Error("Canvas unavailable");
|
||||||
|
enableImageSmoothing(context);
|
||||||
|
|
||||||
|
let preloadedFullImage = null;
|
||||||
|
if (props.introPending) {
|
||||||
|
preloadedFullImage = await loadCanvasImage(
|
||||||
|
canvas,
|
||||||
|
getAssetSource("progress-full.png")
|
||||||
|
);
|
||||||
if (disposed) return;
|
if (disposed) return;
|
||||||
if (shouldPlayEntryAnimation.value) {
|
context.clearRect(0, 0, WIDTH, HEIGHT);
|
||||||
|
context.drawImage(
|
||||||
|
preloadedFullImage,
|
||||||
|
0,
|
||||||
|
FULL_TRACK_OFFSET_Y,
|
||||||
|
WIDTH,
|
||||||
|
HEIGHT
|
||||||
|
);
|
||||||
|
renderedPercent = 100;
|
||||||
|
if (!(await presentCanvas())) return;
|
||||||
|
// 先让满能量首帧完成合成,再开始较重的遮罩和轨道计算。
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||||
|
if (disposed) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
engine = await createEnergyEngine(canvas, preloadedFullImage);
|
||||||
|
if (disposed) return;
|
||||||
|
if (props.introPending || entryAnimationRequested) {
|
||||||
|
renderedPercent = 100;
|
||||||
|
engine.draw(100);
|
||||||
|
showCanvas();
|
||||||
|
if (!props.introPending && entryAnimationRequested) {
|
||||||
runEntryAnimation();
|
runEntryAnimation();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
renderedPercent = normalizedPercent.value;
|
renderedPercent = normalizedPercent.value;
|
||||||
engine.draw(renderedPercent);
|
engine.draw(renderedPercent);
|
||||||
canvasReady.value = true;
|
await presentCanvas();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Canvas 能力不可用时保留单张兜底图,不影响训练业务。
|
|
||||||
shouldPlayEntryAnimation.value = false;
|
|
||||||
console.log("stability energy canvas unavailable", error);
|
console.log("stability energy canvas unavailable", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(normalizedPercent, (value) => {
|
watch(normalizedPercent, (value) => {
|
||||||
if (!engine) {
|
if (!engine || props.introPending || entryAnimationPlaying) return;
|
||||||
// Canvas 初始化前已经恢复出真实能量时,视为重连并跳过入场归零动画。
|
|
||||||
if (value > 0) shouldPlayEntryAnimation.value = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (entryAnimationPlaying) return;
|
|
||||||
drawPercent(value);
|
drawPercent(value);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.introPending,
|
||||||
|
(pending, wasPending) => {
|
||||||
|
if (pending) {
|
||||||
|
entryAnimationRequested = false;
|
||||||
|
if (!engine) return;
|
||||||
|
cancelFrame();
|
||||||
|
entryAnimationPlaying = false;
|
||||||
|
renderedPercent = 100;
|
||||||
|
engine.draw(100);
|
||||||
|
showCanvas();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!wasPending) return;
|
||||||
|
|
||||||
|
entryAnimationRequested = true;
|
||||||
|
if (engine) runEntryAnimation();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
onMounted(initialize);
|
onMounted(initialize);
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
@@ -607,20 +674,18 @@ onBeforeUnmount(() => {
|
|||||||
<template>
|
<template>
|
||||||
<view class="stability-energy-track" aria-label="稳定训练能量进度">
|
<view class="stability-energy-track" aria-label="稳定训练能量进度">
|
||||||
<image
|
<image
|
||||||
v-if="!canvasReady"
|
v-if="fallbackVisible"
|
||||||
:class="[
|
class="stability-energy-track__image"
|
||||||
'stability-energy-track__image',
|
:src="getAssetSource('progress-full.png')"
|
||||||
shouldPlayEntryAnimation
|
mode="scaleToFill"
|
||||||
? 'stability-energy-track__image--full'
|
|
||||||
: '',
|
|
||||||
]"
|
|
||||||
:src="fallbackImageSource"
|
|
||||||
mode="aspectFit"
|
|
||||||
/>
|
/>
|
||||||
<canvas
|
<canvas
|
||||||
:id="canvasId"
|
:id="canvasId"
|
||||||
:canvas-id="canvasId"
|
:canvas-id="canvasId"
|
||||||
class="stability-energy-track__canvas"
|
:class="[
|
||||||
|
'stability-energy-track__canvas',
|
||||||
|
canvasReady ? 'stability-energy-track__canvas--ready' : '',
|
||||||
|
]"
|
||||||
type="2d"
|
type="2d"
|
||||||
:width="WIDTH"
|
:width="WIDTH"
|
||||||
:height="HEIGHT"
|
:height="HEIGHT"
|
||||||
@@ -636,6 +701,7 @@ onBeforeUnmount(() => {
|
|||||||
height: 228rpx;
|
height: 228rpx;
|
||||||
margin: -164rpx 0 -80rpx;
|
margin: -164rpx 0 -80rpx;
|
||||||
margin-left: -10rpx;
|
margin-left: -10rpx;
|
||||||
|
overflow: hidden;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -648,7 +714,17 @@ onBeforeUnmount(() => {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stability-energy-track__image--full {
|
.stability-energy-track__image {
|
||||||
transform: translateY(-2.8rpx);
|
z-index: 0;
|
||||||
|
transform: translateY(-3rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stability-energy-track__canvas {
|
||||||
|
z-index: 1;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stability-energy-track__canvas--ready {
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ const { user } = storeToRefs(store);
|
|||||||
const sound = ref(true);
|
const sound = ref(true);
|
||||||
const start = ref(false);
|
const start = ref(false);
|
||||||
const practiceStarting = ref(false);
|
const practiceStarting = ref(false);
|
||||||
|
const stabilityEnergyIntroPending = ref(false);
|
||||||
const pageStages = Object.freeze({
|
const pageStages = Object.freeze({
|
||||||
DISTANCE: "distance",
|
DISTANCE: "distance",
|
||||||
SHOOTING: "shooting",
|
SHOOTING: "shooting",
|
||||||
@@ -134,11 +135,14 @@ let shotPresentationGeneration = 0;
|
|||||||
let nextDifficultyRequest = null;
|
let nextDifficultyRequest = null;
|
||||||
let nextDifficultyRequestGeneration = 0;
|
let nextDifficultyRequestGeneration = 0;
|
||||||
const audioWaiters = new Set();
|
const audioWaiters = new Set();
|
||||||
|
let stabilityEnergyIntroGeneration = 0;
|
||||||
|
let stabilityEnergyIntroTimer = null;
|
||||||
const shotEffectWaiters = new Map();
|
const shotEffectWaiters = new Map();
|
||||||
const PRACTICE_SYNC_TIMEOUT_MS = 5000;
|
const PRACTICE_SYNC_TIMEOUT_MS = 5000;
|
||||||
const SHOT_EFFECT_WAIT_TIMEOUT_MS = 1200;
|
const SHOT_EFFECT_WAIT_TIMEOUT_MS = 1200;
|
||||||
const AUDIO_TIMEOUT_BASE = 3500;
|
const AUDIO_TIMEOUT_BASE = 3500;
|
||||||
const AUDIO_TIMEOUT_PER_KEY = 2600;
|
const AUDIO_TIMEOUT_PER_KEY = 2600;
|
||||||
|
const STABILITY_ENERGY_ENTRY_DELAY_MS = 1000;
|
||||||
const AUDIO_TIMEOUT_MAX = 12000;
|
const AUDIO_TIMEOUT_MAX = 12000;
|
||||||
const RUNTIME_DIAGNOSTIC_INTERVAL_MS = 60000;
|
const RUNTIME_DIAGNOSTIC_INTERVAL_MS = 60000;
|
||||||
let lastRuntimeDiagnosticAt = 0;
|
let lastRuntimeDiagnosticAt = 0;
|
||||||
@@ -863,6 +867,12 @@ const playAudioKeysAndWait = (keys) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const clearStabilityEnergyIntroTimer = () => {
|
||||||
|
if (!stabilityEnergyIntroTimer) return;
|
||||||
|
clearTimeout(stabilityEnergyIntroTimer);
|
||||||
|
stabilityEnergyIntroTimer = null;
|
||||||
|
};
|
||||||
|
|
||||||
const shouldWaitForShotEffect = (shot) => {
|
const shouldWaitForShotEffect = (shot) => {
|
||||||
const x = Number(shot?.x);
|
const x = Number(shot?.x);
|
||||||
const y = Number(shot?.y);
|
const y = Number(shot?.y);
|
||||||
@@ -1405,6 +1415,9 @@ onLoad((options = {}) => {
|
|||||||
toRouteNumber(trainingContext.scoreSlot)
|
toRouteNumber(trainingContext.scoreSlot)
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
// 稳定训练在测距阶段预挂载 Canvas,并提前绘制 100% 满能量首帧。
|
||||||
|
stabilityEnergyIntroPending.value =
|
||||||
|
trainingParams.value.type === "stability";
|
||||||
practiseId.value = trainingContext.practiceId || "";
|
practiseId.value = trainingContext.practiceId || "";
|
||||||
serverAddr.value = trainingContext.serverAddr || "";
|
serverAddr.value = trainingContext.serverAddr || "";
|
||||||
|
|
||||||
@@ -1450,15 +1463,30 @@ const onReady = async () => {
|
|||||||
scores.value = [];
|
scores.value = [];
|
||||||
shotEffectToken.value = 0;
|
shotEffectToken.value = 0;
|
||||||
initializeRhythmFirstRoundCountdown();
|
initializeRhythmFirstRoundCountdown();
|
||||||
|
const shouldPlayStabilityEnergyIntro =
|
||||||
|
trainingType.value === "stability";
|
||||||
|
clearStabilityEnergyIntroTimer();
|
||||||
|
const stabilityIntroGeneration = ++stabilityEnergyIntroGeneration;
|
||||||
|
stabilityEnergyIntroPending.value = shouldPlayStabilityEnergyIntro;
|
||||||
|
const startAudioKey = getTrainingStartAudioKey(
|
||||||
|
trainingType.value,
|
||||||
|
"练习开始"
|
||||||
|
);
|
||||||
start.value = true;
|
start.value = true;
|
||||||
pageStage.value = pageStages.SHOOTING;
|
pageStage.value = pageStages.SHOOTING;
|
||||||
setPracticeAppHideResumable(true);
|
setPracticeAppHideResumable(true);
|
||||||
// 先由本地锚点保证首轮立即显示,再用最新服务端快照无感校准。
|
// 先由本地锚点保证首轮立即显示,再用最新服务端快照无感校准。
|
||||||
requestPracticeInfoSync();
|
requestPracticeInfoSync();
|
||||||
// 开始接口成功即进入正式训练,直接播放对应提示,避免依赖 BattleStart 消息。
|
// 开始语音只进入原播放队列,不参与能量条的入场计时。
|
||||||
audioManager.play(
|
audioManager.play(startAudioKey);
|
||||||
getTrainingStartAudioKey(trainingType.value, "练习开始")
|
if (shouldPlayStabilityEnergyIntro) {
|
||||||
);
|
stabilityEnergyIntroTimer = setTimeout(() => {
|
||||||
|
stabilityEnergyIntroTimer = null;
|
||||||
|
if (stabilityIntroGeneration !== stabilityEnergyIntroGeneration) return;
|
||||||
|
if (!isShootingStage.value || !isStabilityTraining.value) return;
|
||||||
|
stabilityEnergyIntroPending.value = false;
|
||||||
|
}, STABILITY_ENERGY_ENTRY_DELAY_MS);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
start.value = false;
|
start.value = false;
|
||||||
pageStage.value = pageStages.DISTANCE;
|
pageStage.value = pageStages.DISTANCE;
|
||||||
@@ -1649,6 +1677,9 @@ function onComplete() {
|
|||||||
|
|
||||||
async function onRetry() {
|
async function onRetry() {
|
||||||
pageStage.value = pageStages.LOADING;
|
pageStage.value = pageStages.LOADING;
|
||||||
|
clearStabilityEnergyIntroTimer();
|
||||||
|
stabilityEnergyIntroGeneration += 1;
|
||||||
|
stabilityEnergyIntroPending.value = isStabilityTraining.value;
|
||||||
setPracticeAppHideResumable(false);
|
setPracticeAppHideResumable(false);
|
||||||
clearHighlightTestTimer();
|
clearHighlightTestTimer();
|
||||||
useHighlightTest.value = false;
|
useHighlightTest.value = false;
|
||||||
@@ -1761,6 +1792,9 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
clearStabilityEnergyIntroTimer();
|
||||||
|
stabilityEnergyIntroGeneration += 1;
|
||||||
|
stabilityEnergyIntroPending.value = false;
|
||||||
setPracticeAppHideResumable(false);
|
setPracticeAppHideResumable(false);
|
||||||
invalidateShotPresentations();
|
invalidateShotPresentations();
|
||||||
clearPracticeRuntimeContext();
|
clearPracticeRuntimeContext();
|
||||||
@@ -1856,6 +1890,7 @@ onBeforeUnmount(() => {
|
|||||||
<StabilityEnergyTrack
|
<StabilityEnergyTrack
|
||||||
v-if="isStabilityTraining"
|
v-if="isStabilityTraining"
|
||||||
:percent="stabilityEnergyPercent"
|
:percent="stabilityEnergyPercent"
|
||||||
|
:introPending="stabilityEnergyIntroPending"
|
||||||
/>
|
/>
|
||||||
<!-- <view v-if="env !== 'release'" class="highlight-test-actions">
|
<!-- <view v-if="env !== 'release'" class="highlight-test-actions">
|
||||||
<button
|
<button
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
+3
-1
@@ -79,6 +79,7 @@ function createWebSocket(token, onMessage) {
|
|||||||
|
|
||||||
const { data, event } = JSON.parse(res.data);
|
const { data, event } = JSON.parse(res.data);
|
||||||
if (event === "pong") return;
|
if (event === "pong") return;
|
||||||
|
if (!data || typeof data !== "object") return;
|
||||||
if (data.type) {
|
if (data.type) {
|
||||||
if (ENABLE_REALTIME_MESSAGE_LOG) {
|
if (ENABLE_REALTIME_MESSAGE_LOG) {
|
||||||
console.log("收到 WebSocket 消息", getMessageTypeName(data.type));
|
console.log("收到 WebSocket 消息", getMessageTypeName(data.type));
|
||||||
@@ -86,7 +87,8 @@ function createWebSocket(token, onMessage) {
|
|||||||
if (onMessage) onMessage({ ...(data.data || {}), type: data.type });
|
if (onMessage) onMessage({ ...(data.data || {}), type: data.type });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (onMessage && data.updates) onMessage(data.updates);
|
if (!Array.isArray(data.updates)) return;
|
||||||
|
if (onMessage) onMessage(data.updates);
|
||||||
const msg = data.updates[0];
|
const msg = data.updates[0];
|
||||||
if (msg) {
|
if (msg) {
|
||||||
if (ENABLE_REALTIME_MESSAGE_LOG) {
|
if (ENABLE_REALTIME_MESSAGE_LOG) {
|
||||||
|
|||||||
Reference in New Issue
Block a user