import { defineStore } from "pinia"; const PERSISTED_STORE_KEY = "store"; const defaultUser = { id: "", nickName: "", avatar: "https://static.shelingxingqiu.com/shootmini/static/user-icon.png", trio: 0, // 大于1表示完成了新手引导 lvlName: "", }; const getDefaultUser = () => ({ ...defaultUser }); const getDefaultDevice = () => ({ deviceId: "", deviceName: "", }); const getDefaultDeviceStatus = () => ({ battery: null, charging: false, version: "", online: false, netType: "", onlineDuration: null, receivedAt: 0, }); const getDefaultGame = () => ({ roomID: "", inBattle: false, roomNumber: "", currentShot: 0, totalShot: 0, tips: "", }); const getDefaultDailyCount = () => ({ challenge: { count: 0, limit: -1, }, ranked: { count: 0, limit: -1, }, }); const getLvlName = (rankLvl, rankList = []) => { if (!Array.isArray(rankList) || rankLvl === undefined || rankLvl === null) { return ""; } // 仅返回真正匹配的段位,避免未加载时误取列表最后一项。 const rankInfo = rankList.find( (item) => String(item.rank_id) === String(rankLvl) ); return rankInfo?.name || ""; }; const getLvlNameByScore = (score, rankList = []) => { if (!rankList) return; let lvlName = ""; rankList.some((r, index) => { if (r.upgrade_scores && r.upgrade_scores < score) { lvlName = rankList[index].name; return true; } return false; }); return lvlName; }; const getLvlImage = (rankLvl, rankList = []) => { if (!rankList) return; let lvlImage = ""; rankList.some((r, index) => { if (r.rank_id === rankLvl) { lvlImage = rankList[index].icoin; return true; } return false; }); return lvlImage; }; const getLvlImageByScore = (score, rankList = []) => { if (!rankList) return; let lvlImage = ""; rankList.some((r, index) => { if (r.upgrade_scores && r.upgrade_scores < score) { lvlImage = rankList[index].icoin; return true; } return false; }); return lvlImage; }; // 定义游戏相关的 store export default defineStore("store", { // 状态 state: () => ({ user: getDefaultUser(), device: getDefaultDevice(), config: {}, rankData: { rank: [], ringRank: [], }, online: false, // 设备电量属于运行时状态,null 表示当前没有有效数据。 deviceBattery: null, // WebSocket 实时推送的设备状态,不参与持久化。 deviceStatus: getDefaultDeviceStatus(), game: { roomID: "", inBattle: false, roomNumber: "", // 当前房间号,供 Header 展示房号胶囊 currentShot: 0, // 当前已射箭数(用于 HeaderProgress 恢复状态) totalShot: 0, // 轮次总箭数(用于 HeaderProgress 恢复状态) tips: "", // 当前提示文案(用于 HeaderProgress 恢复状态,替代 uni.$emit 避免时序问题) }, dailyCount: getDefaultDailyCount(), deviceChargingDialogVisible: false, }), // 计算属性 getters: { getUsername: (state) => { return state.user.username; }, }, // 方法 actions: { getLvlNameByScore(score) { return getLvlNameByScore(score, this.config.randInfos); }, getLvlName(rankLvl) { return getLvlName(rankLvl, this.config.randInfos); }, getLvlImage(rankLvl) { return getLvlImage(rankLvl, this.config.randInfos); }, updateRank(data = {}) { this.rankData = { ...(data || {}) }; }, updateOnline(online) { this.setDeviceOnline(online); }, updateDeviceBattery(value) { if (value === null || value === undefined || value === "") { this.deviceBattery = null; return; } const battery = Number(value); this.deviceBattery = Number.isFinite(battery) ? Math.min(100, Math.max(0, battery)) : null; }, updateDeviceStatus(status = {}) { const battery = Number(status.battery ?? status.power); const onlineDuration = Number(status.onlineDuration); const online = status.online === true; const nextStatus = { battery: Number.isFinite(battery) ? Math.min(100, Math.max(0, battery)) : null, charging: status.charging === true, version: String(status.version ?? "").trim(), online, netType: String(status.netType ?? "").trim().toLowerCase(), onlineDuration: Number.isFinite(onlineDuration) && onlineDuration >= 0 ? onlineDuration : null, receivedAt: Date.now(), }; this.deviceStatus = nextStatus; this.online = online; this.deviceBattery = online ? nextStatus.battery : null; }, setDeviceOnline(online) { const nextOnline = online === true; this.online = nextOnline; if (nextOnline) { this.deviceStatus = { ...this.deviceStatus, online: true }; return; } this.deviceBattery = null; this.deviceStatus = getDefaultDeviceStatus(); }, clearDeviceStatus() { this.online = false; this.deviceBattery = null; this.deviceStatus = getDefaultDeviceStatus(); }, async updateUser(user = {}) { this.user = { ...getDefaultUser(), ...user }; this.user.lvlName = getLvlNameByScore(this.user.scores, this.config.randInfos) this.user.lvlImage = getLvlImageByScore( this.user.scores, this.config.randInfos ); }, updateDevice(deviceId, deviceName) { if (String(this.device.deviceId || "") !== String(deviceId || "")) { this.clearDeviceStatus(); } this.device.deviceId = deviceId; this.device.deviceName = deviceName; }, clearDevice() { this.device = getDefaultDevice(); this.clearDeviceStatus(); }, async updateConfig(config) { this.config = config; if (this.user.scores !== undefined) { this.user.lvlName = getLvlName( this.user.rankLvl, this.config.randInfos ); } this.user.lvlImage = getLvlImage( this.user.rankLvl, this.config.randInfos ); }, updateGame(inBattle = false, roomID = "") { this.game.roomID = roomID; this.game.inBattle = inBattle; }, /** 更新当前射箭进度(用于 HeaderProgress 恢复状态,替代 uni.$emit 避免时序问题) */ updateShotInfo(currentShot = 0, totalShot = 0) { this.game.currentShot = currentShot; this.game.totalShot = totalShot; }, /** 更新当前提示文案(用于 HeaderProgress 恢复状态,替代 uni.$emit 避免时序问题) */ updateTips(tips = "") { this.game.tips = tips; }, /** 更新当前房间号,供 Header 组件展示房号胶囊 */ updateRoomNumber(number) { this.game.roomNumber = number; }, updateDailyCount(data = {}) { this.dailyCount = { ...getDefaultDailyCount(), ...(data || {}), }; }, showDeviceChargingDialog() { this.deviceChargingDialogVisible = true; }, hideDeviceChargingDialog() { this.deviceChargingDialogVisible = false; }, clearSessionState() { this.$patch({ user: getDefaultUser(), device: getDefaultDevice(), online: false, deviceBattery: null, deviceStatus: getDefaultDeviceStatus(), game: getDefaultGame(), dailyCount: getDefaultDailyCount(), deviceChargingDialogVisible: false, }); uni.removeStorageSync(PERSISTED_STORE_KEY); setTimeout(() => { uni.removeStorageSync(PERSISTED_STORE_KEY); }, 0); }, }, // 数据持久化(via pinia-plugin-persistedstate) // 仅持久化 user 和 device:身份凭证需在冷启动时恢复(如从分享链接进入) // config、game 等运行时状态不持久化,每次联网后重新拉取 persist: { storage: { getItem: (key) => uni.getStorageSync(key), setItem: (key, value) => uni.setStorageSync(key, value), }, paths: ['user', 'device'], }, });