14 Commits
Author SHA1 Message Date
zhangyi 4245a3f947 update:按钮特效优化 2026-07-31 11:16:34 +08:00
zhangyi d6f914ca7e update:新版优化练习结束语音 2026-07-31 10:56:41 +08:00
zhangyi 959244c03a update:更新新版个人训练结束播报 2026-07-31 10:32:45 +08:00
zhangyi 3a51142bd3 Merge branch 'feat-audio2' into test 2026-07-31 10:28:40 +08:00
zhangyi 07dc8a250c update:个人训练结束修改语音 2026-07-31 10:21:30 +08:00
zhangyi 970a9874b4 Merge branch 'test' 2026-07-16 16:41:16 +08:00
zhangyi b8c5f3dd91 Merge branch 'test' 2026-07-15 15:23:57 +08:00
zhangyi 6d1a910051 Merge branch 'test' 2026-07-15 09:55:37 +08:00
zhangyi 095884d7fc Merge branch 'fix-vip' 2026-07-06 11:16:52 +08:00
zhangyi a7897af861 Merge branch 'fix-vip' 2026-07-06 09:38:15 +08:00
zhangyi fd7c4b4bbf update:优化图片 2026-07-03 17:50:55 +08:00
zhangyi efb186d242 Merge branch 'test' 2026-07-03 17:49:40 +08:00
zhangyi 4ce2e6a7c4 Merge branch 'fix-bug' 2026-06-15 09:31:27 +08:00
zhangyi 52c5b9504a update:更新靶纸 2026-06-11 18:13:46 +08:00
10 changed files with 44 additions and 11 deletions
+3
View File
@@ -89,6 +89,8 @@ export const audioFils = {
"https://static.shelingxingqiu.com/attachment/2025-11-13/de7kzzllq0futwynso.mp3", "https://static.shelingxingqiu.com/attachment/2025-11-13/de7kzzllq0futwynso.mp3",
练习开始: 练习开始:
"https://static.shelingxingqiu.com/attachment/2025-11-14/de88w0lmmt43nnfmoi.mp3", "https://static.shelingxingqiu.com/attachment/2025-11-14/de88w0lmmt43nnfmoi.mp3",
练习结束:
"https://static.shelingxingqiu.com/shootmini/static/audio/%E7%BB%83%E4%B9%A0%E7%BB%93%E6%9D%9F.mp3",
射箭声音: 射箭声音:
"https://static.shelingxingqiu.com/shootaudio/v4/v4/%E7%AE%AD%E9%A3%9E%E8%A1%8C.mp3", "https://static.shelingxingqiu.com/shootaudio/v4/v4/%E7%AE%AD%E9%A3%9E%E8%A1%8C.mp3",
命中: 命中:
@@ -102,6 +104,7 @@ const AUDIO_WARM_PRIORITY_KEYS = [
"点击按钮", "点击按钮",
"比赛开始", "比赛开始",
"练习开始", "练习开始",
"练习结束",
"请开始射击", "请开始射击",
"轮到你了", "轮到你了",
"比赛结束", "比赛结束",
+5 -1
View File
@@ -46,6 +46,10 @@ const props = defineProps({
type: Function, type: Function,
default: () => {}, default: () => {},
}, },
endAudioKey: {
type: String,
default: "比赛结束",
},
}); });
const barColor = ref("#fed847"); const barColor = ref("#fed847");
@@ -144,7 +148,7 @@ async function onReceiveMessage(msg) {
halfTime.value = false; halfTime.value = false;
audioManager.play(audioKey); audioManager.play(audioKey);
} else if (msg.type === MESSAGETYPESV2.BattleEnd) { } else if (msg.type === MESSAGETYPESV2.BattleEnd) {
audioManager.play("比赛结束", false); audioManager.play(props.endAudioKey, false);
} else if (msg.type === MESSAGETYPESV2.ShootResult) { } else if (msg.type === MESSAGETYPESV2.ShootResult) {
let arrow = {}; let arrow = {};
if (msg.details && Array.isArray(msg.details)) { if (msg.details && Array.isArray(msg.details)) {
+19 -2
View File
@@ -1,12 +1,17 @@
<script setup> <script setup>
import { ref, watch } from "vue"; import { ref, watch } from "vue";
import SButton from "@/components/SButton.vue"; import SButton from "@/components/SButton.vue";
import audioManager from "@/audioManager";
const props = defineProps({ const props = defineProps({
show: { show: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
clickSound: {
type: Boolean,
default: false,
},
onClose: { onClose: {
type: Function, type: Function,
default: () => {}, default: () => {},
@@ -39,7 +44,19 @@ watch(
{} {}
); );
const playClickSound = () => {
if (props.clickSound) {
audioManager.play("点击按钮");
}
};
const handleSelectTarget = (target) => {
playClickSound();
selectedTarget.value = target;
};
const handleConfirm = () => { const handleConfirm = () => {
playClickSound();
props.onConfirm(selectedTarget.value); props.onConfirm(selectedTarget.value);
props.onClose(); props.onClose();
}; };
@@ -70,14 +87,14 @@ const handleConfirm = () => {
<view class="target-options"> <view class="target-options">
<view <view
:class="{ 'target-btn': true, 'target-choosen': selectedTarget === 1 }" :class="{ 'target-btn': true, 'target-choosen': selectedTarget === 1 }"
@click="() => (selectedTarget = 1)" @click="handleSelectTarget(1)"
> >
<text>20厘米全环靶</text> <text>20厘米全环靶</text>
</view> </view>
<view style="width: 30rpx"></view> <view style="width: 30rpx"></view>
<view <view
:class="{ 'target-btn': true, 'target-choosen': selectedTarget === 2 }" :class="{ 'target-btn': true, 'target-choosen': selectedTarget === 2 }"
@click="() => (selectedTarget = 2)" @click="handleSelectTarget(2)"
> >
<text>40厘米全环靶</text> <text>40厘米全环靶</text>
</view> </view>
+3 -1
View File
@@ -373,7 +373,7 @@ function getAckAudioKeys(message, businessMessage) {
if (businessMessage?.type === MESSAGETYPESV2.HalfRest) return ["中场休息"]; if (businessMessage?.type === MESSAGETYPESV2.HalfRest) return ["中场休息"];
return ["比赛结束"]; return ["比赛结束"];
case ServerMessageType.SERVER_MSG_PRACTICE_END: case ServerMessageType.SERVER_MSG_PRACTICE_END:
return ["比赛结束"]; return [currentContext?.practiceEndAudioKey || "比赛结束"];
case ServerMessageType.SERVER_MSG_CHECK: case ServerMessageType.SERVER_MSG_CHECK:
return getTestDistanceAudioKeys(businessMessage?.shootData); return getTestDistanceAudioKeys(businessMessage?.shootData);
case ServerMessageType.SERVER_MSG_NOT_ENOUGH_DISTANCE: case ServerMessageType.SERVER_MSG_NOT_ENOUGH_DISTANCE:
@@ -850,6 +850,7 @@ export function connectMatchWebSocket(options = {}) {
mode, mode,
requestPracticeInfoOnOpen = false, requestPracticeInfoOnOpen = false,
appHideResumable = false, appHideResumable = false,
practiceEndAudioKey = "",
force = false, force = false,
reconnecting = false, reconnecting = false,
reconnectReason = "", reconnectReason = "",
@@ -922,6 +923,7 @@ export function connectMatchWebSocket(options = {}) {
Number.isFinite(normalizedMode) ? normalizedMode > 3 : undefined, Number.isFinite(normalizedMode) ? normalizedMode > 3 : undefined,
requestPracticeInfoOnOpen: requestPracticeInfoOnOpen === true, requestPracticeInfoOnOpen: requestPracticeInfoOnOpen === true,
appHideResumable: appHideResumable === true, appHideResumable: appHideResumable === true,
practiceEndAudioKey: String(practiceEndAudioKey || "").trim(),
meleeHalfRest: isSameContext meleeHalfRest: isSameContext
? currentContext?.meleeHalfRest === true ? currentContext?.meleeHalfRest === true
: false, : false,
+1
View File
@@ -450,6 +450,7 @@ onBeforeUnmount(() => {
}`" }`"
:start="start" :start="start"
:onStop="onOver" :onStop="onOver"
end-audio-key="练习结束"
/> />
<view class="user-row"> <view class="user-row">
<Avatar :src="user.avatar" :size="35" /> <Avatar :src="user.avatar" :size="35" />
+1
View File
@@ -459,6 +459,7 @@ onBeforeUnmount(() => {
:start="start" :start="start"
:total="3600" :total="3600"
:onStop="onOver" :onStop="onOver"
end-audio-key="练习结束"
/> />
<view class="user-row"> <view class="user-row">
<Avatar :src="user.avatar" :size="35" /> <Avatar :src="user.avatar" :size="35" />
@@ -205,7 +205,7 @@ async function onReceiveMessage(msg) {
halfTime.value = false; halfTime.value = false;
audioManager.play("比赛开始"); audioManager.play("比赛开始");
} else if (msg.type === MESSAGETYPESV2.BattleEnd) { } else if (msg.type === MESSAGETYPESV2.BattleEnd) {
audioManager.play("比赛结束", false); audioManager.play("练习结束", false);
} else if (msg.type === MESSAGETYPESV2.ShootResult) { } else if (msg.type === MESSAGETYPESV2.ShootResult) {
// 精准训练由页面统一等待语音和飞箭结束,其他训练保持原播放链路。 // 精准训练由页面统一等待语音和飞箭结束,其他训练保持原播放链路。
if (props.externalShootResultAudio) return; if (props.externalShootResultAudio) return;
+4 -1
View File
@@ -5,6 +5,7 @@ import Container from "@/components/Container.vue";
import TrainingDifficultyBadge from "./components/TrainingDifficultyBadge.vue"; import TrainingDifficultyBadge from "./components/TrainingDifficultyBadge.vue";
import TrainingDifficultyPreviewCard from "./components/TrainingDifficultyPreviewCard.vue"; import TrainingDifficultyPreviewCard from "./components/TrainingDifficultyPreviewCard.vue";
import TrainingDifficultyStartButton from "./components/TrainingDifficultyStartButton.vue"; import TrainingDifficultyStartButton from "./components/TrainingDifficultyStartButton.vue";
import audioManager from "@/audioManager";
import { import {
createPractiseV2API, createPractiseV2API,
endPractiseAPI, endPractiseAPI,
@@ -676,6 +677,8 @@ const handleSelectDifficulty = (node) => {
return; return;
} }
audioManager.play("点击按钮");
if (node.id === selectedDifficultyId.value) { if (node.id === selectedDifficultyId.value) {
return; return;
} }
@@ -810,7 +813,7 @@ onShow(() => {
<view class="difficulty-page__start"> <view class="difficulty-page__start">
<TrainingDifficultyStartButton <TrainingDifficultyStartButton
:text="selectedDifficulty.startText" :text="selectedDifficulty.startText"
@click="handleStart" @click="$clickSound(handleStart)"
/> />
</view> </view>
</view> </view>
+4 -3
View File
@@ -469,7 +469,7 @@ onShow(async () => {
</view> </view>
<view class="radar-section"> <view class="radar-section">
<view class="record-bubble" @click="openTrainingRecord"> <view class="record-bubble" @click="$clickSound(openTrainingRecord)">
<image <image
class="record-bubble-bg" class="record-bubble-bg"
src="https://static.shelingxingqiu.com/shootmini/static/training-home/img_28.png" src="https://static.shelingxingqiu.com/shootmini/static/training-home/img_28.png"
@@ -530,7 +530,7 @@ onShow(async () => {
</view> </view>
</view> </view>
<view class="featured-card" @click="openRoutineTraining"> <view class="featured-card" @click="$clickSound(openRoutineTraining)">
<image <image
class="featured-card-bg" class="featured-card-bg"
src="https://static.shelingxingqiu.com/shootmini/static/training-home/img_22.png" src="https://static.shelingxingqiu.com/shootmini/static/training-home/img_22.png"
@@ -547,7 +547,7 @@ onShow(async () => {
v-for="item in visibleTrainingItems" v-for="item in visibleTrainingItems"
:key="item.id" :key="item.id"
class="mode-card" class="mode-card"
@click="openTrainingItem(item)" @click="$clickSound(() => openTrainingItem(item))"
> >
<view v-if="item.id === recommendedTrainingId" class="mode-tag"> <view v-if="item.id === recommendedTrainingId" class="mode-tag">
推荐 推荐
@@ -572,6 +572,7 @@ onShow(async () => {
</view> </view>
<TargetPicker <TargetPicker
:show="showRoutineTargetPicker" :show="showRoutineTargetPicker"
:clickSound="true"
:onClose="() => (showRoutineTargetPicker = false)" :onClose="() => (showRoutineTargetPicker = false)"
:onConfirm="handleRoutineTargetConfirm" :onConfirm="handleRoutineTargetConfirm"
/> />
+2 -1
View File
@@ -765,6 +765,7 @@ const connectPracticeServer = ({
userId: user.value.id, userId: user.value.id,
requestPracticeInfoOnOpen: true, requestPracticeInfoOnOpen: true,
appHideResumable: appHideResumable.value, appHideResumable: appHideResumable.value,
practiceEndAudioKey: "练习结束",
}); });
connectionClosed.value = false; connectionClosed.value = false;
return true; return true;
@@ -1192,7 +1193,7 @@ function onAudioEnded(key) {
Array.from(audioWaiters).forEach((waiter) => { Array.from(audioWaiters).forEach((waiter) => {
if (waiter.expectedKey === key) waiter.done(); if (waiter.expectedKey === key) waiter.done();
}); });
if (String(key || "").includes("比赛结束")) { if (["比赛结束", "练习结束"].includes(String(key || ""))) {
void onOver(); void onOver();
} }
} }