yingsa/miniprogram/app.js
ethanfly 8f9eb38666 fix(dependencies): Remove peer flags from package-lock.json and update Vite dependencies
- Removed unnecessary "peer" flags from various dependencies in package-lock.json to streamline package management.
- Updated Vite dependencies and their corresponding metadata for improved performance and compatibility.
- Adjusted import paths in CSS files to reflect the correct directory structure.
- Deleted unused CSS files related to the "col" component to clean up the project.
2026-02-07 02:05:34 +08:00

564 lines
19 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.getUserInfo();
}
},
// 微信登录第一步获取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,
);
if (currentStoreLadderUser) {
this.globalData.ladderUser = currentStoreLadderUser;
} else {
// 当前门店没有天梯用户,取第一个
this.globalData.ladderUser =
loginRes.data.data.userInfo.ladderUsers[0];
}
} else {
// 没有当前门店,取第一个天梯用户
this.globalData.ladderUser =
loginRes.data.data.userInfo.ladderUsers[0];
}
} 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();
},
// 获取用户信息
getUserInfo() {
return new Promise((resolve, reject) => {
this.request("/api/user/info")
.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,
);
if (currentStoreLadderUser) {
this.globalData.ladderUser = currentStoreLadderUser;
} else {
// 当前门店没有天梯用户,取第一个
this.globalData.ladderUser = res.data.ladderUsers[0];
}
} else {
// 没有当前门店,取第一个天梯用户
this.globalData.ladderUser = res.data.ladderUsers[0];
}
} else {
// 没有天梯用户
this.globalData.ladderUser = null;
}
this.connectWebSocket();
resolve(res.data);
})
.catch(reject);
});
},
// 获取当前门店
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;
// 如果当前门店有 ladderUserId获取该门店的天梯用户信息
if (res.data && res.data.ladderUserId) {
this.getLadderUser(res.data.storeId);
} else if (res.data && res.data.storeId) {
// 如果当前门店没有 ladderUserId但用户信息中有该门店的天梯用户使用它
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;
// 如果当前门店有 ladderUserId获取该门店的天梯用户信息
if (res.data && res.data.ladderUserId) {
this.getLadderUser(res.data.storeId);
} else if (res.data && res.data.storeId) {
// 如果当前门店没有 ladderUserId但用户信息中有该门店的天梯用户使用它
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);
},
});
});
},
// 获取天梯用户信息
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 });
},
});
});
},
});