1 Commits
Author SHA1 Message Date
cao123 89cd9d0404 fix 2026-09-07 13:50:02 +08:00
6 changed files with 282 additions and 173 deletions
+1 -6
View File
@@ -76,21 +76,16 @@ App<IAppOption>({
}, },
checkLoginState() { checkLoginState() {
const openId = wx.getStorageSync('openId'); const openId = wx.getStorageSync('openId');
const unionId = wx.getStorageSync('unionId');
const userId = wx.getStorageSync('userId'); const userId = wx.getStorageSync('userId');
const isLoggedIn = !!(openId && userId);
const isLoggedIn = !!(openId && unionId && userId);
if (!isLoggedIn) { if (!isLoggedIn) {
// 清理登录相关缓存 // 清理登录相关缓存
LOGIN_STORAGE_KEYS.forEach(key => wx.removeStorageSync(key)); LOGIN_STORAGE_KEYS.forEach(key => wx.removeStorageSync(key));
} }
// 记录上一次登录状态,用于判断是否从已登录变为未登录 // 记录上一次登录状态,用于判断是否从已登录变为未登录
const prev = this.globalData.isLogin; const prev = this.globalData.isLogin;
this.globalData.isLogin = isLoggedIn; this.globalData.isLogin = isLoggedIn;
this.globalData.wasLogin = prev; this.globalData.wasLogin = prev;
return isLoggedIn; return isLoggedIn;
}, },
login(value: string) { login(value: string) {
+53 -59
View File
@@ -62,7 +62,8 @@ Page({
); );
return; return;
} }
const bool = await app.login("video");
if (!bool) return;
// 开启防截屏(仅限当前页面生命周期内) // 开启防截屏(仅限当前页面生命周期内)
//@ts-ignore //@ts-ignore
wx.setVisualEffectOnCapture({ wx.setVisualEffectOnCapture({
@@ -306,68 +307,61 @@ Page({
return; return;
} }
const { pass } = res.data || {}; const { pass, redPackage } = res.data || {};
if (pass) { if (pass) {
wx.showModal({
content: "🎉 领取红包!",
showCancel: false,
confirmText: "立即领取",
confirmColor: "#FF0000",
success: async (res) => {
if (res.confirm) {
if (redPackage?.packageInfo) {
try {
wx.showLoading({ title: "领取中", mask: true });
if (wx.canIUse?.("requestMerchantTransfer")) {
await new Promise<void>((resolve, reject) => {
// @ts-ignore
wx.requestMerchantTransfer({
mchId: redPackage.mchId,
appId,
package: redPackage.packageInfo,
success: () => {
wx.showToast({ title: "领取成功", icon: "success" });
resolve();
},
fail: (err: any) => {
console.error("拉起转账失败:", err);
wx.showToast({ title: "领取失败", icon: "none" });
reject(new Error(err?.errMsg || "领取失败"));
},
});
});
} else {
wx.showModal({
content: "你的微信版本过低,请更新至最新版本。",
showCancel: false,
});
throw new Error("微信版本过低");
}
} catch (err: any) {
wx.hideLoading();
const msg = err?.data?.msg || err?.errMsg || err?.message || "领取失败";
wx.showToast({ title: msg, icon: "none" });
}
} else {
await this.handleReceive(redPackage.redId);
}
}
},
});
} else {
wx.showToast({ wx.showToast({
title: "提交成功", title: "回答错误,您与红包擦肩而过",
icon: "success", icon: "none",
duration: 2000, duration: 6000,
}); });
} }
// if (pass) {
// wx.showModal({
// content: "🎉 领取红包!",
// showCancel: false,
// confirmText: "立即领取",
// confirmColor: "#FF0000",
// success: async (res) => {
// if (res.confirm) {
// if (redPackage?.packageInfo) {
// try {
// wx.showLoading({ title: "领取中", mask: true });
// if (wx.canIUse?.("requestMerchantTransfer")) {
// await new Promise<void>((resolve, reject) => {
// // @ts-ignore
// wx.requestMerchantTransfer({
// mchId: redPackage.mchId,
// appId,
// package: redPackage.packageInfo,
// success: () => {
// wx.showToast({ title: "领取成功", icon: "success" });
// resolve();
// },
// fail: (err: any) => {
// console.error("拉起转账失败:", err);
// wx.showToast({ title: "领取失败", icon: "none" });
// reject(new Error(err?.errMsg || "领取失败"));
// },
// });
// });
// } else {
// wx.showModal({
// content: "你的微信版本过低,请更新至最新版本。",
// showCancel: false,
// });
// throw new Error("微信版本过低");
// }
// } catch (err: any) {
// wx.hideLoading();
// const msg = err?.data?.msg || err?.errMsg || err?.message || "领取失败";
// wx.showToast({ title: msg, icon: "none" });
// }
// } else {
// await this.handleReceive(redPackage.redId);
// }
// }
// },
// });
// } else {
// wx.showToast({
// title: "回答错误,您与红包擦肩而过",
// icon: "none",
// duration: 6000,
// });
// }
}, },
async handleReceive(id: any) { async handleReceive(id: any) {
const { code } = this.data.store as Record<string, any>; const { code } = this.data.store as Record<string, any>;
+106
View File
@@ -132,3 +132,109 @@
line-height: 34rpx; line-height: 34rpx;
margin-left: 4rpx; margin-left: 4rpx;
} }
/* ============================================
弹窗 — 设置头像和昵称
============================================ */
.popup-title {
display: block;
font-size: 35rpx;
font-weight: 600;
color: #000;
text-align: center;
margin-bottom: 10rpx;
}
.popup-content {
display: flex;
flex-direction: column;
padding: 40rpx;
// 左右布局:左头像 + 右按钮组
.form-row {
display: flex;
align-items: center;
gap: 36rpx;
margin-bottom: 50rpx;
// 左侧:头像选择器
.avatar-picker {
flex-shrink: 0;
width: 140rpx;
height: 140rpx;
padding: 0;
background: transparent;
border: none;
display: flex;
align-items: center;
justify-content: center;
&::after {
border: none;
}
.popup-avatar {
width: 140rpx;
height: 140rpx;
border-radius: 50%;
border: 3rpx solid $primary-color;
}
}
// 右侧:按钮组(上下排列)
.btn-group {
flex: 1;
display: flex;
flex-direction: column;
gap: 20rpx;
.form-btn {
width: 100%;
height: 72rpx;
line-height: 72rpx;
font-size: 26rpx;
color: #fff;
background: linear-gradient(90deg, #005bea 0%, #00c6fb 99%);
border-radius: 36rpx;
border: none;
&::after {
border: none;
}
}
// 昵称输入:外观伪装成按钮,click 唤起微信昵称弹层
.form-input--nickname {
width: 100%;
height: 72rpx;
line-height: 72rpx;
font-size: 26rpx;
color: $primary-color;
background: transparent;
border: 2rpx solid $primary-color;
border-radius: 36rpx;
text-align: center;
padding: 0 20rpx;
box-sizing: border-box;
}
}
}
// 提交按钮
.form-submit {
width: 100%;
.submit-btn {
width: 100%;
height: 96rpx;
line-height: 96rpx;
background: linear-gradient(90deg, #005bea 0%, #00c6fb 99%);
color: #fff;
font-size: 34rpx;
border-radius: 48rpx;
border: none;
&::after {
border: none;
}
}
}
}
+52 -78
View File
@@ -213,12 +213,10 @@ Page({
agree: false, agree: false,
nickFocus: true, nickFocus: true,
showPopup: false, showPopup: false,
avatarUrl: defaultAvatarUrl,
nickname: '',
safeBottom: app.globalData.safeBottom, safeBottom: app.globalData.safeBottom,
showLoginImage: false, showLoginImage: false,
userInfo: {
avatarUrl: defaultAvatarUrl,
nickName: "微信用户",
},
}, },
applyLoginDisplayConfig(options: Record<string, any> = {}) { applyLoginDisplayConfig(options: Record<string, any> = {}) {
@@ -245,10 +243,7 @@ Page({
success: (res: any) => { success: (res: any) => {
const { data } = JSON.parse(res.data); const { data } = JSON.parse(res.data);
this.setData({ this.setData({
userInfo: {
...this.data.userInfo,
avatarUrl: data, avatarUrl: data,
},
}); });
}, },
fail: () => { fail: () => {
@@ -275,7 +270,6 @@ Page({
const tabPages = [ const tabPages = [
"/pages/tab-bar/medicine-box/index", "/pages/tab-bar/medicine-box/index",
"/pages/tab-bar/shopping-cart/shopping-cart", "/pages/tab-bar/shopping-cart/shopping-cart",
"/pages/tab-bar/course/course",
"/pages/tab-bar/user/user", "/pages/tab-bar/user/user",
"/pages/tab-bar/points-mall/points-mall", "/pages/tab-bar/points-mall/points-mall",
"/pages/tab-bar/category/category", "/pages/tab-bar/category/category",
@@ -289,23 +283,7 @@ Page({
wx.removeStorageSync(WXROOM_REDIRECT_PATH_KEY); wx.removeStorageSync(WXROOM_REDIRECT_PATH_KEY);
} else { } else {
const store = app.globalData.store; const store = app.globalData.store;
const state = wx.getStorageSync("state") ?? undefined;
const code = wx.getStorageSync("code") ?? undefined; const code = wx.getStorageSync("code") ?? undefined;
const groupId = wx.getStorageSync("groupId") ?? undefined;
if (state && !code) {
if (self.data.back === "video") {
const storeParams =
typeof store === "string" ? store : this.buildQueryString(store);
fullPath = `/pages/live/video/video?${storeParams}`;
} else if (self.data.back === "red") {
fullPath = `/pages/common/red/red`;
} else if (self.data.back === "user") {
fullPath = `/pages/tab-bar/user/user`;
} else {
fullPath = `/pages/live/registration/registration?state=${state}`;
}
} else if (!state && code) {
if (self.data.back === "video") { if (self.data.back === "video") {
const storeParams = const storeParams =
typeof store === "string" ? store : this.buildQueryString(store); typeof store === "string" ? store : this.buildQueryString(store);
@@ -317,15 +295,7 @@ Page({
} else { } else {
fullPath = `/pages/live/registration/registration?code=${code}`; fullPath = `/pages/live/registration/registration?code=${code}`;
} }
} else {
if (self.data.back === "room") {
fullPath = `/pages/live/room/room?groupId=${groupId}`;
} else if (self.data.back === "red") {
fullPath = `/pages/common/red/red`;
} else if (self.data.back === "user") {
fullPath = `/pages/tab-bar/user/user`;
}
}
} }
} else { } else {
const pages = getCurrentPages(); const pages = getCurrentPages();
@@ -376,65 +346,70 @@ Page({
}); });
if (!this.data.agree) return; if (!this.data.agree) return;
} }
this.setData({
showPopup: true
})
},
closePopup() {
this.setData({
showPopup: false
})
},
// 获取昵称(微信系统填入后失焦触发 bindblur)
onNicknameInput(e: any) {
const { value } = e.detail;
this.setData({
nickname: value
});
},
// 提交登录
async submitLogin() {
const { avatarUrl, nickname } = this.data;
if (!avatarUrl) {
wx.showToast({
title: '请选择头像',
icon: 'none'
});
return;
}
if (!nickname) {
wx.showToast({
title: '请选择昵称',
icon: 'none'
});
return;
}
try { try {
wx.showLoading({ title: "登录中" }); wx.showLoading({ title: "登录中" });
const loginRes = await wxLogin(); const loginRes = await wxLogin();
if (!loginRes.code) throw new Error(loginRes.errMsg); if (!loginRes.code) throw new Error(loginRes.errMsg);
const { avatarUrl, nickName } = this.data.userInfo;
const state = wx.getStorageSync("state");
let loginResult: LoginRes; let loginResult: LoginRes;
if (state) {
const reqData: Record<string, any> = { const reqData: Record<string, any> = {
state: wx.getStorageSync("state") ?? undefined, state: loginRes.code,
...(nickName && nickName !== "微信用户" ? { nickName } : {}), avatarUrl,
...(avatarUrl && avatarUrl !== defaultAvatarUrl ? { avatarUrl } : {}), nickName: nickname
}; };
loginResult = await wxRequest<LoginRes>({ loginResult = await wxRequest<LoginRes>({
url: `${BASE_URL}/api/auth/app-login?appId=${appId}&code=${loginRes.code}`, url: `${BASE_URL}/api/auth/app-auth-new?appId=${appId}&code=${loginRes.code}`,
method: "POST", method: "POST",
data: reqData, data: reqData,
}); });
} else {
const reqData: Record<string, any> = {
state: wx.getStorageSync("code") ?? undefined,
...(nickName && nickName !== "微信用户" ? { nickName } : {}),
...(avatarUrl && avatarUrl !== defaultAvatarUrl ? { avatarUrl } : {}),
};
loginResult = await wxRequest<LoginRes>({ if (loginResult?.statusCode !== 200) {
url: `${BASE_URL}/api/auth/app-auth?appId=${appId}&code=${loginRes.code}`,
method: "POST",
data: reqData,
});
}
if (
loginResult?.statusCode !== 200 ||
(loginResult.data.code && loginResult.data.code !== 200)
) {
throw new Error(loginResult?.data?.msg || "登录失败"); throw new Error(loginResult?.data?.msg || "登录失败");
} }
const {
mpUserId,
id,
openId,
unionId,
nickName: resNickName,
avatarUrl: resAvatarUrl,
} = loginResult.data;
const storageData = { const storageData = {
openId, openId: loginResult.data.openId,
userId: mpUserId, userId: loginResult.data.mpUserId,
mbuId: id, userName: loginResult.data.nickName,
unionId, avatarUrl: loginResult.data.avatarUrl,
userName: resNickName,
avatarUrl: resAvatarUrl,
}; };
Object.entries(storageData).forEach(([key, value]) => { Object.entries(storageData).forEach(([key, value]) => {
@@ -442,18 +417,15 @@ Page({
}); });
app.globalData.isLogin = true; app.globalData.isLogin = true;
this.triggerEvent("loginSuccess", {
userName: resNickName,
avatarUrl: resAvatarUrl,
});
wx.showToast({ wx.showToast({
title: "登录成功", title: "登录成功",
duration: 2000, duration: 2000,
}); });
// 跳转到看课页面
this.redirectUrl(); this.redirectUrl();
} catch (err: any) { } catch (err: any) {
console.log("登录失败:", err);
app.globalData.isLogin = false; app.globalData.isLogin = false;
wx.showToast({ wx.showToast({
title: `登录失败:${err.message || err.errMsg}`, title: `登录失败:${err.message || err.errMsg}`,
@@ -462,8 +434,10 @@ Page({
} finally { } finally {
setTimeout(() => wx.hideToast(), 3000); setTimeout(() => wx.hideToast(), 3000);
} }
},
// 关闭弹窗
this.closePopup();
},
handleToggleAgree() { handleToggleAgree() {
this.setData({ agree: !this.data.agree }); this.setData({ agree: !this.data.agree });
}, },
+29
View File
@@ -24,3 +24,32 @@
</view> </view>
</view> </view>
</view> </view>
<!-- 弹窗:设置头像和昵称 -->
<popup visible="{{showPopup}}" bind:close="closePopup">
<text class="popup-title">手动设置头像和昵称</text>
<view class="popup-content">
<!-- 左右布局:左侧头像 | 右侧按钮组 -->
<view class="form-row">
<!-- 左侧:头像 -->
<button class="avatar-picker" open-type="chooseAvatar" bindchooseavatar="onChooseAvatar">
<image src="{{avatarUrl}}" class="popup-avatar"></image>
</button>
<!-- 右侧:两个按钮 -->
<view class="btn-group">
<button class="form-btn" open-type="chooseAvatar" bindchooseavatar="onChooseAvatar">点击获取头像</button>
<input
type="nickname"
class="form-input--nickname"
placeholder="点击获取昵称"
bindblur="onNicknameInput"
/>
</view>
</view>
<!-- 提交 -->
<view class="form-submit">
<button class="submit-btn" bind:tap="submitLogin">确定授权</button>
</view>
</view>
</popup>
+29 -18
View File
@@ -1,4 +1,5 @@
import { BASE_URL } from "../env"; import { BASE_URL, appId } from "../env";
import { base64Encode } from "./crypto";
type RequestProps = { type RequestProps = {
options: WechatMiniprogram.RequestOption; options: WechatMiniprogram.RequestOption;
loadingTitle?: string; loadingTitle?: string;
@@ -6,27 +7,23 @@ type RequestProps = {
needLogin?: boolean; needLogin?: boolean;
}; };
// 生成设备指纹字符串 // 每次请求动态生成 header,确保使用最新的 openId
const generateFingerprint = (): string => { const fingerprint = wx.getSystemInfoSync();
const info = wx.getSystemInfoSync();
return [
String(info.system),
String(info.platform),
String(info.SDKVersion),
String(info.screenWidth),
String(info.screenHeight),
].join("&");
};
export const request = <T = any>( export const request = <T = any>(
{ options, loadingTitle = "加载中", isLoading = true }: RequestProps { options, loadingTitle = "加载中", isLoading = true, needLogin = true }: RequestProps
): Promise<T> => { ): Promise<T> => {
const app = getApp<IAppOption>();
const header: any = { const header: any = {
"X-Fingerprint": generateFingerprint(), "X-Fingerprint": fingerprint,
}; };
if (needLogin) {
if (!app.checkLoginState()) {
return Promise.reject(new Error('请先登录'));
}
const openId = wx.getStorageSync("openId") || "";
header.Authorization = `Basic ${base64Encode(`${openId}:${appId}`)}`
}
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let showToast = false; let showToast = false;
@@ -47,13 +44,27 @@ export const request = <T = any>(
if (!res.data.code || res.data.code === 200) { if (!res.data.code || res.data.code === 200) {
resolve(res.data as T); resolve(res.data as T);
} else if (res.data.code === 401) { } else if (res.data.code === 401) {
// 保存当前页面路径,登录后跳转回来
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
if (currentPage) {
const route = `/${currentPage.route}`;
const options = currentPage.options || {};
const query = Object.entries(options)
.filter(([, value]) => value !== undefined && value !== null)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value as string)}`)
.join("&");
const fullPath = query ? `${route}?${query}` : route;
wx.setStorageSync("redirectPath", fullPath);
}
wx.showModal({ wx.showModal({
title: "登录提示", title: "登录提示",
content: "请先登录", content: "请先登录",
confirmText: "去登录", confirmText: "去登录",
success: (options) => { success: (options) => {
if (options.confirm) { if (options.confirm) {
wx.navigateTo({ url: "/pages/login/login" }); // 使用 redirectTo 替换当前页,登录页无返回按钮
wx.redirectTo({ url: "/pages/login/login" });
} }
} }
}); });