Merge branch 'feat-yuyin' into test
This commit is contained in:
+1
-2
@@ -23,10 +23,9 @@ export const getPrecisionShotAudioKeys = (shootData, directionText = "") => {
|
|||||||
return ["未上靶", directionAudioKey].filter(Boolean);
|
return ["未上靶", directionAudioKey].filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ringAudioKey = shootData.ringX === true ? "X环" : `${ring}环`;
|
|
||||||
// protobuf 的 false 可能不编码;只要不是明确命中,本箭就反馈未命中。
|
// protobuf 的 false 可能不编码;只要不是明确命中,本箭就反馈未命中。
|
||||||
const hitAudioKey = shootData.ok === true ? "Bingo命中目标" : "未命中";
|
const hitAudioKey = shootData.ok === true ? "Bingo命中目标" : "未命中";
|
||||||
return [ringAudioKey, directionAudioKey, hitAudioKey].filter(Boolean);
|
return [directionAudioKey, hitAudioKey].filter(Boolean);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const audioFils = {
|
export const audioFils = {
|
||||||
|
|||||||
@@ -6,11 +6,16 @@ import Avatar from "@/components/Avatar.vue";
|
|||||||
import audioManager from "@/audioManager";
|
import audioManager from "@/audioManager";
|
||||||
import { simulShootAPI } from "@/apis";
|
import { simulShootAPI } from "@/apis";
|
||||||
import { MESSAGETYPESV2 } from "@/constants";
|
import { MESSAGETYPESV2 } from "@/constants";
|
||||||
import { getDistanceCheckAudioKey, getDistanceCheckText } from "@/util";
|
import {
|
||||||
|
getDistanceCheckAudioKey,
|
||||||
|
getDistanceCheckText,
|
||||||
|
getShootValidation,
|
||||||
|
} from "@/util";
|
||||||
import useStore from "@/store";
|
import useStore from "@/store";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const { user, device } = storeToRefs(store);
|
const { user, device } = storeToRefs(store);
|
||||||
|
const emit = defineEmits(["passed"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
guide: {
|
guide: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -24,6 +29,10 @@ const props = defineProps({
|
|||||||
type: Number,
|
type: Number,
|
||||||
default: 15,
|
default: 15,
|
||||||
},
|
},
|
||||||
|
autoStart: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const arrow = ref({});
|
const arrow = ref({});
|
||||||
const distance = ref(0);
|
const distance = ref(0);
|
||||||
@@ -31,6 +40,29 @@ const statusText = ref("");
|
|||||||
const showsimul = ref(false);
|
const showsimul = ref(false);
|
||||||
const count = ref(props.count);
|
const count = ref(props.count);
|
||||||
const timer = ref(null);
|
const timer = ref(null);
|
||||||
|
const autoStartPending = ref(false);
|
||||||
|
const autoStartTriggered = ref(false);
|
||||||
|
let autoStartTimer = null;
|
||||||
|
const DISTANCE_PASSED_AUDIO_KEY = "站距合格,靶纸正确";
|
||||||
|
const AUTO_START_TIMEOUT_MS = 6000;
|
||||||
|
|
||||||
|
const clearAutoStartTimer = () => {
|
||||||
|
if (!autoStartTimer) return;
|
||||||
|
clearTimeout(autoStartTimer);
|
||||||
|
autoStartTimer = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const triggerAutoStart = () => {
|
||||||
|
if (!autoStartPending.value || autoStartTriggered.value) return;
|
||||||
|
clearAutoStartTimer();
|
||||||
|
autoStartPending.value = false;
|
||||||
|
autoStartTriggered.value = true;
|
||||||
|
emit("passed");
|
||||||
|
};
|
||||||
|
|
||||||
|
const onAudioEnded = (key) => {
|
||||||
|
if (key === DISTANCE_PASSED_AUDIO_KEY) triggerAutoStart();
|
||||||
|
};
|
||||||
|
|
||||||
const updateTimer = (value) => {
|
const updateTimer = (value) => {
|
||||||
count.value = Math.round(value);
|
count.value = Math.round(value);
|
||||||
@@ -44,21 +76,31 @@ onMounted(() => {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
uni.$on("update-timer", updateTimer);
|
uni.$on("update-timer", updateTimer);
|
||||||
|
uni.$on("audioEnded", onAudioEnded);
|
||||||
});
|
});
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
if (timer.value) clearInterval(timer.value);
|
if (timer.value) clearInterval(timer.value);
|
||||||
|
clearAutoStartTimer();
|
||||||
uni.$off("update-timer", updateTimer);
|
uni.$off("update-timer", updateTimer);
|
||||||
|
uni.$off("audioEnded", onAudioEnded);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function onReceiveMessage(msg) {
|
async function onReceiveMessage(msg) {
|
||||||
if (Array.isArray(msg)) return;
|
if (Array.isArray(msg)) return;
|
||||||
if (msg.type === MESSAGETYPESV2.TestDistance) {
|
if (msg.type === MESSAGETYPESV2.TestDistance) {
|
||||||
|
if (autoStartPending.value || autoStartTriggered.value) return;
|
||||||
const rawDistance = Number(msg.shootData?.distance ?? msg.shootData?.dst);
|
const rawDistance = Number(msg.shootData?.distance ?? msg.shootData?.dst);
|
||||||
distance.value = Number.isFinite(rawDistance)
|
distance.value = Number.isFinite(rawDistance)
|
||||||
? Number((rawDistance / 100).toFixed(2))
|
? Number((rawDistance / 100).toFixed(2))
|
||||||
: 0;
|
: 0;
|
||||||
statusText.value = getDistanceCheckText(msg.shootData);
|
statusText.value = getDistanceCheckText(msg.shootData);
|
||||||
audioManager.play(getDistanceCheckAudioKey(msg.shootData));
|
const audioKey = getDistanceCheckAudioKey(msg.shootData);
|
||||||
|
const validation = getShootValidation(msg.shootData);
|
||||||
|
if (props.autoStart && validation.distanceOk && validation.targetOk) {
|
||||||
|
autoStartPending.value = true;
|
||||||
|
autoStartTimer = setTimeout(triggerAutoStart, AUTO_START_TIMEOUT_MS);
|
||||||
|
}
|
||||||
|
audioManager.play(audioKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ const store = useStore();
|
|||||||
const { user, device } = storeToRefs(store);
|
const { user, device } = storeToRefs(store);
|
||||||
|
|
||||||
const start = ref(false);
|
const start = ref(false);
|
||||||
|
const practiceStarting = ref(false);
|
||||||
const scores = ref([]);
|
const scores = ref([]);
|
||||||
const isSvip = ref(false);
|
const isSvip = ref(false);
|
||||||
const total = 12;
|
const total = 12;
|
||||||
@@ -156,12 +157,18 @@ const beginPractise = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onReady = async () => {
|
const onReady = async () => {
|
||||||
|
if (practiceStarting.value || start.value) return;
|
||||||
|
practiceStarting.value = true;
|
||||||
|
try {
|
||||||
const result = await beginPractise();
|
const result = await beginPractise();
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
scores.value = [];
|
scores.value = [];
|
||||||
isSvip.value = false;
|
isSvip.value = false;
|
||||||
start.value = true;
|
start.value = true;
|
||||||
audioManager.play("练习开始");
|
audioManager.play("练习开始");
|
||||||
|
} finally {
|
||||||
|
practiceStarting.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onOver = async (message) => {
|
const onOver = async (message) => {
|
||||||
@@ -438,7 +445,11 @@ onBeforeUnmount(() => {
|
|||||||
:onBack="exitPractise"
|
:onBack="exitPractise"
|
||||||
>
|
>
|
||||||
<view>
|
<view>
|
||||||
<TestDistance v-if="!start && !practiseResult.id" />
|
<TestDistance
|
||||||
|
v-if="!start && !practiseResult.id"
|
||||||
|
:autoStart="true"
|
||||||
|
@passed="onReady"
|
||||||
|
/>
|
||||||
<block v-else>
|
<block v-else>
|
||||||
<ShootProgress
|
<ShootProgress
|
||||||
:tips="`${
|
:tips="`${
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ const store = useStore();
|
|||||||
const { user, device } = storeToRefs(store);
|
const { user, device } = storeToRefs(store);
|
||||||
|
|
||||||
const start = ref(false);
|
const start = ref(false);
|
||||||
|
const practiceStarting = ref(false);
|
||||||
const scores = ref([]);
|
const scores = ref([]);
|
||||||
const isSvip = ref(false);
|
const isSvip = ref(false);
|
||||||
const total = 36;
|
const total = 36;
|
||||||
@@ -155,12 +156,18 @@ const beginPractise = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onReady = async () => {
|
const onReady = async () => {
|
||||||
|
if (practiceStarting.value || start.value) return;
|
||||||
|
practiceStarting.value = true;
|
||||||
|
try {
|
||||||
const result = await beginPractise();
|
const result = await beginPractise();
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
scores.value = [];
|
scores.value = [];
|
||||||
isSvip.value = false;
|
isSvip.value = false;
|
||||||
start.value = true;
|
start.value = true;
|
||||||
audioManager.play("练习开始");
|
audioManager.play("练习开始");
|
||||||
|
} finally {
|
||||||
|
practiceStarting.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onOver = async (message) => {
|
const onOver = async (message) => {
|
||||||
@@ -452,7 +459,11 @@ onBeforeUnmount(() => {
|
|||||||
:onBack="exitPractise"
|
:onBack="exitPractise"
|
||||||
>
|
>
|
||||||
<view>
|
<view>
|
||||||
<TestDistance v-if="!start && !practiseResult.id" />
|
<TestDistance
|
||||||
|
v-if="!start && !practiseResult.id"
|
||||||
|
:autoStart="true"
|
||||||
|
@passed="onReady"
|
||||||
|
/>
|
||||||
<block v-else>
|
<block v-else>
|
||||||
<ShootProgress
|
<ShootProgress
|
||||||
:tips="`请连续射${total}支箭`"
|
:tips="`请连续射${total}支箭`"
|
||||||
|
|||||||
@@ -6,11 +6,16 @@ import Avatar from "@/components/Avatar.vue";
|
|||||||
import audioManager from "@/audioManager";
|
import audioManager from "@/audioManager";
|
||||||
import { simulShootAPI } from "@/apis";
|
import { simulShootAPI } from "@/apis";
|
||||||
import { MESSAGETYPESV2 } from "@/constants";
|
import { MESSAGETYPESV2 } from "@/constants";
|
||||||
import { getDistanceCheckAudioKey, getDistanceCheckText } from "@/util";
|
import {
|
||||||
|
getDistanceCheckAudioKey,
|
||||||
|
getDistanceCheckText,
|
||||||
|
getShootValidation,
|
||||||
|
} from "@/util";
|
||||||
import useStore from "@/store";
|
import useStore from "@/store";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const { user, device } = storeToRefs(store);
|
const { user, device } = storeToRefs(store);
|
||||||
|
const emit = defineEmits(["passed"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
guide: {
|
guide: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -28,6 +33,10 @@ const props = defineProps({
|
|||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
default: "",
|
default: "",
|
||||||
},
|
},
|
||||||
|
autoStart: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const arrow = ref({});
|
const arrow = ref({});
|
||||||
const distance = ref(0);
|
const distance = ref(0);
|
||||||
@@ -35,6 +44,29 @@ const statusText = ref("");
|
|||||||
const showsimul = ref(false);
|
const showsimul = ref(false);
|
||||||
const count = ref(props.count);
|
const count = ref(props.count);
|
||||||
const timer = ref(null);
|
const timer = ref(null);
|
||||||
|
const autoStartPending = ref(false);
|
||||||
|
const autoStartTriggered = ref(false);
|
||||||
|
let autoStartTimer = null;
|
||||||
|
const DISTANCE_PASSED_AUDIO_KEY = "站距合格,靶纸正确";
|
||||||
|
const AUTO_START_TIMEOUT_MS = 6000;
|
||||||
|
|
||||||
|
const clearAutoStartTimer = () => {
|
||||||
|
if (!autoStartTimer) return;
|
||||||
|
clearTimeout(autoStartTimer);
|
||||||
|
autoStartTimer = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const triggerAutoStart = () => {
|
||||||
|
if (!autoStartPending.value || autoStartTriggered.value) return;
|
||||||
|
clearAutoStartTimer();
|
||||||
|
autoStartPending.value = false;
|
||||||
|
autoStartTriggered.value = true;
|
||||||
|
emit("passed");
|
||||||
|
};
|
||||||
|
|
||||||
|
const onAudioEnded = (key) => {
|
||||||
|
if (key === DISTANCE_PASSED_AUDIO_KEY) triggerAutoStart();
|
||||||
|
};
|
||||||
|
|
||||||
const updateTimer = (value) => {
|
const updateTimer = (value) => {
|
||||||
count.value = Math.round(value);
|
count.value = Math.round(value);
|
||||||
@@ -48,21 +80,31 @@ onMounted(() => {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
uni.$on("update-timer", updateTimer);
|
uni.$on("update-timer", updateTimer);
|
||||||
|
uni.$on("audioEnded", onAudioEnded);
|
||||||
});
|
});
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
if (timer.value) clearInterval(timer.value);
|
if (timer.value) clearInterval(timer.value);
|
||||||
|
clearAutoStartTimer();
|
||||||
uni.$off("update-timer", updateTimer);
|
uni.$off("update-timer", updateTimer);
|
||||||
|
uni.$off("audioEnded", onAudioEnded);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function onReceiveMessage(msg) {
|
async function onReceiveMessage(msg) {
|
||||||
if (Array.isArray(msg)) return;
|
if (Array.isArray(msg)) return;
|
||||||
if (msg.type === MESSAGETYPESV2.TestDistance) {
|
if (msg.type === MESSAGETYPESV2.TestDistance) {
|
||||||
|
if (autoStartPending.value || autoStartTriggered.value) return;
|
||||||
const rawDistance = Number(msg.shootData?.distance ?? msg.shootData?.dst);
|
const rawDistance = Number(msg.shootData?.distance ?? msg.shootData?.dst);
|
||||||
distance.value = Number.isFinite(rawDistance)
|
distance.value = Number.isFinite(rawDistance)
|
||||||
? Number((rawDistance / 100).toFixed(2))
|
? Number((rawDistance / 100).toFixed(2))
|
||||||
: 0;
|
: 0;
|
||||||
statusText.value = getDistanceCheckText(msg.shootData);
|
statusText.value = getDistanceCheckText(msg.shootData);
|
||||||
audioManager.play(getDistanceCheckAudioKey(msg.shootData));
|
const audioKey = getDistanceCheckAudioKey(msg.shootData);
|
||||||
|
const validation = getShootValidation(msg.shootData);
|
||||||
|
if (props.autoStart && validation.distanceOk && validation.targetOk) {
|
||||||
|
autoStartPending.value = true;
|
||||||
|
autoStartTimer = setTimeout(triggerAutoStart, AUTO_START_TIMEOUT_MS);
|
||||||
|
}
|
||||||
|
audioManager.play(audioKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,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 pageStages = Object.freeze({
|
const pageStages = Object.freeze({
|
||||||
DISTANCE: "distance",
|
DISTANCE: "distance",
|
||||||
SHOOTING: "shooting",
|
SHOOTING: "shooting",
|
||||||
@@ -1031,6 +1032,7 @@ onLoad((options = {}) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const onReady = async () => {
|
const onReady = async () => {
|
||||||
|
if (practiceStarting.value) return;
|
||||||
if (
|
if (
|
||||||
!practiseId.value ||
|
!practiseId.value ||
|
||||||
practiceEnded.value ||
|
practiceEnded.value ||
|
||||||
@@ -1044,6 +1046,7 @@ const onReady = async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
practiceStarting.value = true;
|
||||||
pageStage.value = pageStages.LOADING;
|
pageStage.value = pageStages.LOADING;
|
||||||
clearHighlightTestTimer();
|
clearHighlightTestTimer();
|
||||||
useHighlightTest.value = false;
|
useHighlightTest.value = false;
|
||||||
@@ -1066,6 +1069,8 @@ const onReady = async () => {
|
|||||||
pageStage.value = pageStages.DISTANCE;
|
pageStage.value = pageStages.DISTANCE;
|
||||||
setPracticeAppHideResumable(true);
|
setPracticeAppHideResumable(true);
|
||||||
throw error;
|
throw error;
|
||||||
|
} finally {
|
||||||
|
practiceStarting.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1332,6 +1337,8 @@ onBeforeUnmount(() => {
|
|||||||
<TestDistance
|
<TestDistance
|
||||||
v-if="isDistanceStage"
|
v-if="isDistanceStage"
|
||||||
:targetType="practiceInfo.targetType"
|
:targetType="practiceInfo.targetType"
|
||||||
|
:autoStart="true"
|
||||||
|
@passed="onReady"
|
||||||
/>
|
/>
|
||||||
<view v-else-if="isShootingStage" class="shooting-layout">
|
<view v-else-if="isShootingStage" class="shooting-layout">
|
||||||
<view class="shooting-fixed">
|
<view class="shooting-fixed">
|
||||||
|
|||||||
Reference in New Issue
Block a user