const config = require("./config"); App({ globalData: { userInfo: null, token: null, currentStore: null, ladderUser: null, wsConnected: false, // 微信登录临时信息 wxLoginInfo: null, // 从配置文件读取 baseUrl: config.baseUrl, wsUrl: config.wsUrl, }, onLaunch() { // 从本地存储读取 token 和上次选择的门店 const token = wx.getStorageSync("token"); if (token) { this.globalData.token = token; this.ensureCurrentStore() .then(() => this.getUserInfo(this.globalData.currentStore?.storeId)) .catch(() => {}); } }, // 微信登录(第一步:获取openid和session_key) wxLogin() { return new Promise((resolve, reject) => { wx.login({ success: (res) => { wx.request({ url: `${this.globalData.baseUrl}/api/user/login`, method: "POST", data: { code: res.code }, success: (loginRes) => { if (loginRes.data.code === 0) { const data = loginRes.data.data; // 保存微信登录信息(用于后续手机号授权) this.globalData.wxLoginInfo = { openid: data.openid, unionid: data.unionid, sessionKey: data.sessionKey, isNewUser: data.isNewUser, hasPhone: data.hasPhone, }; // 如果已有token(老用户),直接使用 if (data.userInfo && data.hasPhone) { // 老用户已绑定手机号,生成token并登录 this.globalData.userInfo = data.userInfo; } resolve(data); } else { reject(loginRes.data); } }, fail: reject, }); }, fail: reject, }); }); }, // 手机号授权登录(第二步:解密手机号完成注册/登录) phoneLogin(encryptedData, iv, gender) { return new Promise((resolve, reject) => { const wxInfo = this.globalData.wxLoginInfo; if (!wxInfo) { reject({ message: "请先进行微信登录" }); return; } const requestData = { openid: wxInfo.openid, unionid: wxInfo.unionid, sessionKey: wxInfo.sessionKey, encryptedData, iv, }; // 如果提供了性别参数,添加到请求中 if (gender === 1 || gender === 2) { requestData.gender = gender; } wx.request({ url: `${this.globalData.baseUrl}/api/user/phone-login`, method: "POST", data: requestData, success: (loginRes) => { if (loginRes.data.code === 0) { this.globalData.token = loginRes.data.data.token; this.globalData.userInfo = loginRes.data.data.userInfo; // 处理天梯用户信息(战力按当前门店,当前门店无天梯则不显示) if ( loginRes.data.data.userInfo.ladderUsers && loginRes.data.data.userInfo.ladderUsers.length > 0 ) { if ( this.globalData.currentStore && this.globalData.currentStore.storeId ) { const currentStoreLadderUser = loginRes.data.data.userInfo.ladderUsers.find( (lu) => lu.storeId === this.globalData.currentStore.storeId, ); // 仅当当前门店有天梯用户时才显示,否则为 null,避免显示其他门店数据 this.globalData.ladderUser = currentStoreLadderUser || null; } else { this.globalData.ladderUser = null; } } else { this.globalData.ladderUser = null; } wx.setStorageSync("token", loginRes.data.data.token); this.connectWebSocket(); resolve(loginRes.data.data); } else { reject(loginRes.data); } }, fail: reject, }); }); }, // 旧的登录方法(兼容) login() { return this.wxLogin(); }, // 获取用户信息(storeId 可选,传入时返回该门店的积分 storePoints) getUserInfo(storeId) { return new Promise((resolve, reject) => { const data = storeId ? { store_id: storeId } : {}; this.request("/api/user/info", data) .then((res) => { this.globalData.userInfo = res.data; // 处理天梯用户信息(战力按当前门店,当前门店无天梯则不显示) if (res.data.ladderUsers && res.data.ladderUsers.length > 0) { if ( this.globalData.currentStore && this.globalData.currentStore.storeId ) { const currentStoreLadderUser = res.data.ladderUsers.find( (lu) => lu.storeId === this.globalData.currentStore.storeId, ); // 仅当当前门店有天梯用户时才显示,否则为 null,避免显示其他门店数据 this.globalData.ladderUser = currentStoreLadderUser || null; } else { this.globalData.ladderUser = null; } } else { this.globalData.ladderUser = null; } this.connectWebSocket(); resolve(res.data); }) .catch(reject); }); }, /** * 优先使用上次选择的门店,没有或失败时再请求最近门店(新用户逻辑) */ ensureCurrentStore() { const lastStore = wx.getStorageSync("last_store"); if (lastStore && lastStore.storeId) { this.globalData.currentStore = { storeId: lastStore.storeId, storeName: lastStore.storeName || "", storeAddress: lastStore.storeAddress || "", }; return this.getLadderUser(lastStore.storeId) .then(() => this.globalData.currentStore) .catch(() => { wx.removeStorageSync("last_store"); return this.getCurrentStore(); }); } return this.getCurrentStore(); }, // 获取当前门店(新用户或未选过门店时:按位置取最近门店) getCurrentStore() { return new Promise((resolve, reject) => { wx.getLocation({ type: "gcj02", success: (loc) => { this.request("/api/user/current-store", { latitude: loc.latitude, longitude: loc.longitude, }) .then((res) => { this.globalData.currentStore = res.data; if (res.data && res.data.ladderUserId) { this.getLadderUser(res.data.storeId); } else if (res.data && res.data.storeId) { if ( this.globalData.userInfo && this.globalData.userInfo.ladderUsers ) { const currentStoreLadderUser = this.globalData.userInfo.ladderUsers.find( (lu) => lu.storeId === res.data.storeId, ); if (currentStoreLadderUser) { this.globalData.ladderUser = currentStoreLadderUser; } else { this.globalData.ladderUser = null; } } } resolve(res.data); }) .catch(reject); }, fail: () => { this.request("/api/user/current-store") .then((res) => { this.globalData.currentStore = res.data; if (res.data && res.data.ladderUserId) { this.getLadderUser(res.data.storeId); } else if (res.data && res.data.storeId) { if ( this.globalData.userInfo && this.globalData.userInfo.ladderUsers ) { const currentStoreLadderUser = this.globalData.userInfo.ladderUsers.find( (lu) => lu.storeId === res.data.storeId, ); if (currentStoreLadderUser) { this.globalData.ladderUser = currentStoreLadderUser; } else { this.globalData.ladderUser = null; } } } resolve(res.data); }) .catch(reject); }, }); }); }, // 获取天梯用户信息(请求失败时 reject,便于上层做降级) getLadderUser(storeId) { return this.request("/api/user/ladder-info", { store_id: storeId }).then( (res) => { if (res.data && res.data.length > 0) { this.globalData.ladderUser = res.data[0]; } else { this.globalData.ladderUser = null; } return res.data; }, ); }, // WebSocket连接 connectWebSocket() { if (this.globalData.wsConnected || !this.globalData.token) return; const wsUrl = this.globalData.wsUrl || "ws://localhost:3000/ws"; this.ws = wx.connectSocket({ url: wsUrl, success: () => { console.log("WebSocket连接中..."); }, }); wx.onSocketOpen(() => { console.log("WebSocket已连接"); this.globalData.wsConnected = true; // 发送认证 wx.sendSocketMessage({ data: JSON.stringify({ type: "auth", token: this.globalData.token, }), }); }); wx.onSocketMessage((res) => { const data = JSON.parse(res.data); this.handleWsMessage(data); }); wx.onSocketClose(() => { console.log("WebSocket已断开"); this.globalData.wsConnected = false; // 尝试重连 setTimeout(() => { this.connectWebSocket(); }, 5000); }); wx.onSocketError((err) => { console.error("WebSocket错误:", err); }); }, // 处理WebSocket消息 handleWsMessage(data) { switch (data.type) { case "challenge_request": // 收到挑战请求 - 使用自定义弹框 const challengeData = data.data; const pages = getCurrentPages(); const currentPage = pages[pages.length - 1]; // 如果当前页面有处理挑战请求的方法,调用它 if ( currentPage && typeof currentPage.handleChallengeRequest === "function" ) { currentPage.handleChallengeRequest(challengeData); } else { // 否则使用系统弹框 wx.showModal({ title: "收到挑战", content: `${challengeData.challenger.realName}(Lv${challengeData.challenger.level}, 战力${challengeData.challenger.powerScore}) 向你发起挑战`, confirmText: "接受", cancelText: "拒绝", success: (res) => { this.request( "/api/match/challenge/respond", { match_id: challengeData.matchId, accept: res.confirm, }, "POST", ) .then(() => { if (res.confirm) { wx.showToast({ title: "已接受挑战", icon: "success" }); // 跳转到挑战赛详情 setTimeout(() => { wx.navigateTo({ url: `/pages/match/challenge-detail/index?id=${challengeData.matchId}`, }); }, 1500); } else { wx.showToast({ title: "已拒绝挑战", icon: "success" }); } }) .catch((err) => { console.error("响应挑战失败:", err); wx.showToast({ title: "操作失败", icon: "none" }); }); }, }); } break; case "challenge_accepted": // 挑战被接受 wx.showToast({ title: "对方已接受挑战", icon: "success" }); // 如果当前在挑战赛详情页面,刷新数据 const pages2 = getCurrentPages(); const currentPage2 = pages2[pages2.length - 1]; if ( currentPage2 && currentPage2.route === "pages/match/challenge-detail/index" ) { if (typeof currentPage2.loadMatchDetail === "function") { currentPage2.loadMatchDetail(); } } break; case "challenge_rejected": // 挑战被拒绝 wx.showToast({ title: "对方已拒绝挑战", icon: "none" }); break; case "score_confirm_request": // 收到比分确认请求 wx.showModal({ title: "确认比分", content: `比分: ${data.data.player1Score} : ${data.data.player2Score}`, confirmText: "确认", cancelText: "有争议", success: (res) => { this.request( "/api/match/challenge/confirm-score", { game_id: data.data.gameId, confirm: res.confirm, }, "POST", ); }, }); break; case "match_paired": // 排位赛匹配通知 try { const payload = data.data || {}; const opponent = payload.opponent || {}; const matchCode = payload.matchCode; wx.showModal({ title: "匹配成功", content: `你的对手是: ${opponent.realName || "对手"}`, showCancel: false, success: (res) => { if (res.confirm) { // 检查当前页面 const pagesMatch = getCurrentPages(); const currentMatchPage = pagesMatch[pagesMatch.length - 1]; if (currentMatchPage && currentMatchPage.route === "pages/match/ranking/index") { // 如果已在比赛详情页,检查是否是同一场比赛 const targetCode = matchCode; if ( !targetCode || !currentMatchPage.data || currentMatchPage.data.matchCode === targetCode ) { // 刷新详情页的所有接口信息 if (typeof currentMatchPage.fetchMatchDetail === "function") { currentMatchPage.fetchMatchDetail(); } else if (typeof currentMatchPage.fetchCurrentGame === "function") { currentMatchPage.fetchCurrentGame(); } } else { // 不同比赛,跳转到新的比赛详情页 wx.redirectTo({ url: `/pages/match/ranking/index?code=${targetCode}` }); } } else { // 如果不在比赛详情页,自动跳转到比赛详情页 if (matchCode) { wx.navigateTo({ url: `/pages/match/ranking/index?code=${matchCode}` }); } } } } }); } catch (e) { console.error("处理 match_paired 消息失败:", e); } break; case "ranking_game_updated": // 排位赛比分/匹配更新:刷新当前排位赛详情页 try { const pages3 = getCurrentPages(); const currentPage3 = pages3[pages3.length - 1]; if (currentPage3) { if (currentPage3.route === "pages/match/ranking/index") { const targetCode = data.data && data.data.matchCode; if ( !targetCode || !currentPage3.data || currentPage3.data.matchCode === targetCode ) { if (typeof currentPage3.fetchMatchDetail === "function") { currentPage3.fetchMatchDetail(); } } } else if (currentPage3.route === "pages/match/challenge/index") { // 比赛首页:比分确认后也刷新“当前比赛”卡片 if (typeof currentPage3.fetchOngoingMatches === "function") { currentPage3.fetchOngoingMatches(); } } } } catch (e) { console.error("处理 ranking_game_updated 消息失败:", e); } break; case "points_order_verified": // 后台核销积分订单后,通知小程序刷新订单列表/详情 try { wx.showToast({ title: "积分订单已核销", icon: "success" }); const pages = getCurrentPages(); const currentPage = pages[pages.length - 1]; const payload = data.data || {}; if ( currentPage && currentPage.route === "pages/points/order/index" ) { // 如果页面实现了下拉刷新逻辑,优先复用 if (typeof currentPage.onPullDownRefresh === "function") { currentPage.onPullDownRefresh(); } else if (typeof currentPage.fetchOrders === "function") { // 兜底:重置分页并主动刷新 currentPage.setData({ page: 1, hasMore: true }); currentPage.fetchOrders(); } // 精确刷新当前弹窗和列表中的该笔订单 if ( payload.orderId && typeof currentPage.refreshOrderById === "function" ) { currentPage.refreshOrderById(payload.orderId); } } } catch (e) { console.error("处理 points_order_verified 消息失败:", e); } break; } }, // 封装请求 request(url, data = {}, method = "GET") { return new Promise((resolve, reject) => { const showErrorToast = (message) => { const title = (message && String(message).trim()) || "网络异常,请稍后重试"; wx.showToast({ title, icon: "none" }); }; wx.request({ url: `${this.globalData.baseUrl}${url}`, method, data, header: { Authorization: `Bearer ${this.globalData.token}`, }, success: (res) => { if (res.data.code === 0) { resolve(res.data); } else if (res.data.code === 401) { // 登录过期 this.globalData.token = null; wx.removeStorageSync("token"); showErrorToast("登录已过期,请重新登录"); wx.reLaunch({ url: "/pages/user/index" }); reject({ message: res.data.message || "登录已过期", ...res.data }); } else { showErrorToast(res.data.message || "请求失败"); reject({ message: res.data.message || "请求失败", ...res.data }); } }, fail: (err) => { showErrorToast("网络异常,请检查网络后重试"); reject({ message: "网络异常,请检查网络后重试", err }); }, }); }); }, });