diff --git a/.gitignore b/.gitignore
index 1923370..c91affc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,7 +12,7 @@ node_modules
.github
openspec
CLAUDE.md
-dosc
+docs
.DS_Store
dist
*.local
diff --git a/src/App.vue b/src/App.vue
index 3a630ac..c852548 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -22,9 +22,7 @@
const {
updateUser,
updateOnline,
- updateDevice,
- updateGame,
- updateRoomNumber
+ clearSessionState
} = store;
watch(
@@ -50,14 +48,9 @@
}
function onSessionKickedOut() {
- uni.removeStorageSync(
- `${uni.getAccountInfoSync().miniProgram.envVersion}_token`
- );
- updateUser();
- updateDevice("", "");
- updateOnline(false);
- updateGame(false, "");
- updateRoomNumber("");
+ const env = uni.getAccountInfoSync().miniProgram.envVersion;
+ uni.removeStorageSync(`${env}_token`);
+ clearSessionState();
uni.showModal({
title: "提示",
content: "账号已在其他设备登录",
diff --git a/src/apis.js b/src/apis.js
index f1c7614..305a040 100644
--- a/src/apis.js
+++ b/src/apis.js
@@ -42,6 +42,7 @@ function request(method, url, data = {}) {
if (code === 0) resolve(data);
else if (message) {
if (message.indexOf("登录身份已失效") !== -1) {
+ console.log('1111111111111111111,token失效')
uni.removeStorageSync(
`${uni.getAccountInfoSync().miniProgram.envVersion}_token`
);
diff --git a/src/audioManager.js b/src/audioManager.js
index 0d5fc18..44fe3a5 100644
--- a/src/audioManager.js
+++ b/src/audioManager.js
@@ -1,4 +1,6 @@
export const audioFils = {
+ tententen: "https://static.shelingxingqiu.com/shootmini/static/audio/tententen.mp3",
+ 点击按钮: "https://static.shelingxingqiu.com/shootmini/static/audio/%E7%82%B9%E5%87%BB%E6%8C%89%E9%92%AE.mp3",
"20CM全环靶": "https://static.shelingxingqiu.com/shootmini/static/audio/20CM%E5%85%A8%E7%8E%AF%E9%9D%B6-%E6%97%A0%E6%95%88.mp3",
"40CM全环靶": "https://static.shelingxingqiu.com/shootmini/static/audio/40CM%E5%85%A8%E7%8E%AF%E9%9D%B6-%E6%97%A0%E6%95%88.mp3",
// 激光已校准:
diff --git a/src/components/AppFooter.vue b/src/components/AppFooter.vue
index 3a44260..05f2ebe 100644
--- a/src/components/AppFooter.vue
+++ b/src/components/AppFooter.vue
@@ -31,7 +31,7 @@ function handleTabClick(index) {
v-for="(tab, index) in tabs"
:key="index"
class="tab-item"
- @click="handleTabClick(index)"
+ @click="$clickSound(() => handleTabClick(index))"
:style="{
width: index === 1 ? '36%' : '20%',
}"
diff --git a/src/components/Container.vue b/src/components/Container.vue
index 109606a..280959c 100644
--- a/src/components/Container.vue
+++ b/src/components/Container.vue
@@ -206,7 +206,7 @@ const goCalibration = async () => {
-
+
diff --git a/src/components/CreateRoom.vue b/src/components/CreateRoom.vue
index 0b32a26..e66dd22 100644
--- a/src/components/CreateRoom.vue
+++ b/src/components/CreateRoom.vue
@@ -112,7 +112,7 @@ const createRoom = debounce(async () => {
40厘米全环靶
- 创建房间
+ 创建房间
diff --git a/src/components/HeaderProgress.vue b/src/components/HeaderProgress.vue
index da96697..464d31d 100644
--- a/src/components/HeaderProgress.vue
+++ b/src/components/HeaderProgress.vue
@@ -19,12 +19,17 @@ const ended = ref(false);
const halfTime = ref(false);
const currentShot = ref(0);
const totalShot = ref(0);
+/** 标记组件是否已完成挂载,防止 immediate watcher 在挂载前用旧 store 值触发意外播音 */
+const isMounted = ref(false);
watch(
() => tips.value,
(newVal) => {
+ // 挂载完成前不播音(避免 immediate store watcher 用旧值触发多余播报)
+ if (!isMounted.value) return;
+ // 空字符串或含"重回"的 tips 均不播音
+ if (!newVal || newVal.includes("重回")) return;
let key = [];
- if (newVal.includes("重回")) return;
if (currentRoundEnded.value) {
// 播放当前轮次语音
key.push(`第${["一", "二", "三", "四", "五"][currentRound.value]}轮`);
@@ -60,8 +65,12 @@ async function onReceiveMessage(message) {
audioManager.play("比赛结束", false);
} else if (type === MESSAGETYPESV2.ShootResult) {
if (melee.value && current.playerId !== user.value.id) return;
- // 从 indexMap 按当前用户 id 取已射箭数,由后端维护准确值,不在前端自增
- if (current.playerId === user.value.id) currentShot.value = current.indexMap?.[user.value.id] ?? currentShot.value;
+ // 从 indexMap 按当前用户 id 取已射箭数,由后端维护准确值,不在前端自增。
+ // 注意:后端在 ShootResult 中会将 playerId 重置为 0(无当前射手),
+ // 因此不能依赖 playerId === user.id 判断,改为直接读取 indexMap[user.id]。
+ // indexMap[user.id] 只在本人射箭后才增加,队友射箭时该值不变,逻辑等价且更准确。
+ const myShot = current.indexMap?.[user.value.id];
+ if (myShot !== undefined) currentShot.value = myShot;
if (message.shootData) {
let key = [];
key.push(
@@ -113,6 +122,7 @@ watch(() => store.game.tips, (newVal) => {
}, { immediate: true });
onMounted(() => {
+ isMounted.value = true;
uni.$on("update-tips", onUpdateTips);
uni.$on("socket-inbox", onReceiveMessage);
uni.$on("play-sound", playSound);
diff --git a/src/components/Matching.vue b/src/components/Matching.vue
index c6c109a..f680c0f 100644
--- a/src/components/Matching.vue
+++ b/src/components/Matching.vue
@@ -123,7 +123,7 @@ onBeforeUnmount(() => {
-
+
diff --git a/src/main.js b/src/main.js
index 0a0dccb..8462e70 100644
--- a/src/main.js
+++ b/src/main.js
@@ -2,12 +2,25 @@ import { createSSRApp } from 'vue'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import App from './App.vue'
+import audioManager from './audioManager'
export function createApp() {
const app = createSSRApp(App)
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
app.use(pinia)
+
+ /**
+ * 全局点击音效工具函数,用于在任意按钮/元素点击时自动播放音效。
+ * 用法:@click="$clickSound(handler)" 或 @click="$clickSound(() => doSomething())"
+ * @param {Function} handler - 原始点击回调函数(可选,点击时直接调用)
+ * @param {string} [soundKey='点击按钮'] - audioManager 中的音效 key
+ */
+ app.config.globalProperties.$clickSound = (handler, soundKey = '点击按钮') => {
+ audioManager.play(soundKey);
+ if (typeof handler === 'function') handler();
+ };
+
return {
app
}
diff --git a/src/pages/battle-room.vue b/src/pages/battle-room.vue
index 1bf2695..bf27084 100644
--- a/src/pages/battle-room.vue
+++ b/src/pages/battle-room.vue
@@ -443,7 +443,7 @@ onBeforeUnmount(() => {
-
+
{{
allReady.value
? "即将进入对局..."
diff --git a/src/pages/friend-battle-result.vue b/src/pages/friend-battle-result.vue
index 7b8e426..70296e2 100644
--- a/src/pages/friend-battle-result.vue
+++ b/src/pages/friend-battle-result.vue
@@ -240,7 +240,7 @@ function closeOverlay() {
/**
* 底部按钮文案:好友约战显示“返回房间”,排位赛等其他模式显示“返回”
*/
-const exitBtnText = computed(() => data.value.way === 1 ? '返回房间' : '返回');
+const exitBtnText = computed(() => data.value.way === 1 ? '再来一局' : '返回');
/**
* 点击底部按钮跳转
diff --git a/src/pages/friend-battle.vue b/src/pages/friend-battle.vue
index 698524a..2cbdda1 100644
--- a/src/pages/friend-battle.vue
+++ b/src/pages/friend-battle.vue
@@ -98,8 +98,10 @@ onLoad(async (options) => {
- 约上朋友开几局,欢乐多,不寂寞
- 一起练升级更快,早日加入全国排位赛!
+
+ 约上朋友开几局,欢乐多,不寂寞
+ 一起练升级更快,早日加入全国排位赛!
+
@@ -139,7 +141,7 @@ onLoad(async (options) => {
- 进入房间
+ enterRoom(roomNumber))">进入房间
@@ -153,7 +155,7 @@ onLoad(async (options) => {
-
+
创建约战房
@@ -171,6 +173,24 @@ onLoad(async (options) => {