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) => { - 进入房间 + 进入房间 @@ -153,7 +155,7 @@ onLoad(async (options) => { - + 创建约战房 @@ -171,6 +173,24 @@ onLoad(async (options) => {