wip: 临时提交
This commit is contained in:
@@ -38,39 +38,26 @@ const AuthAPI = {
|
||||
},
|
||||
|
||||
/**
|
||||
* 微信登录 (基础版)
|
||||
* 微信小程序授权登录 (仅使用code获取OpenID)
|
||||
* @param code 微信登录凭证
|
||||
* @returns 登录结果
|
||||
*/
|
||||
wechatLogin(code: string): Promise<LoginResult> {
|
||||
return request<LoginResult>({
|
||||
url: `${AUTH_BASE_URL}/wechat/login`,
|
||||
url: `${AUTH_BASE_URL}/wx/miniapp/code-login`,
|
||||
method: "POST",
|
||||
data: { code },
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 微信小程序增强登录 (获取手机号)
|
||||
* @param data 包含code, encryptedData, iv等的登录数据
|
||||
* @returns 登录结果
|
||||
*/
|
||||
wechatMiniLogin(data: WxLoginData): Promise<LoginResult> {
|
||||
return request<LoginResult>({
|
||||
url: `${AUTH_BASE_URL}/wechat/mini-login`,
|
||||
method: "POST",
|
||||
data,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 微信一键登录 (通过手机号)
|
||||
* @param data 包含code和phoneCode的登录数据
|
||||
* 微信小程序手机号授权登录
|
||||
* @param data 包含code、encryptedData、iv等手机号相关数据
|
||||
* @returns 登录结果
|
||||
*/
|
||||
wechatPhoneLogin(data: WxLoginData): Promise<LoginResult> {
|
||||
return request<LoginResult>({
|
||||
url: `${AUTH_BASE_URL}/wechat/phone-login`,
|
||||
url: `${AUTH_BASE_URL}/wx/miniapp/phone-login`,
|
||||
method: "POST",
|
||||
data,
|
||||
});
|
||||
|
||||
159
src/composables/useWechat.ts
Normal file
159
src/composables/useWechat.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* 微信授权服务
|
||||
* 处理微信登录授权、获取用户信息等功能
|
||||
*/
|
||||
|
||||
import { ref } from "vue";
|
||||
import { getAccessToken } from "@/utils/auth";
|
||||
|
||||
export function useWechat() {
|
||||
// 定义微信授权状态
|
||||
const authState = ref({
|
||||
isLogining: false,
|
||||
authDenied: false,
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取微信登录凭证code
|
||||
* @returns Promise 返回登录凭证code
|
||||
*/
|
||||
const getLoginCode = (): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// #ifdef MP-WEIXIN
|
||||
uni.login({
|
||||
provider: "weixin",
|
||||
success: (res) => {
|
||||
if (res.code) {
|
||||
resolve(res.code);
|
||||
} else {
|
||||
reject(new Error("获取微信登录凭证失败"));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
},
|
||||
});
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
reject(new Error("当前环境不支持微信登录"));
|
||||
// #endif
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取微信用户手机号
|
||||
* @param e 微信授权返回的事件对象
|
||||
* @returns Promise 返回包含手机号加密数据的对象
|
||||
*/
|
||||
const getPhoneNumber = (
|
||||
e: any
|
||||
): Promise<{ code: string; encryptedData?: string; iv?: string }> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
authState.value.isLogining = true;
|
||||
|
||||
// 判断授权是否成功
|
||||
if (e.detail.errMsg !== "getPhoneNumber:ok") {
|
||||
authState.value.isLogining = false;
|
||||
authState.value.authDenied = true;
|
||||
reject(new Error("用户拒绝授权"));
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取登录凭证code
|
||||
getLoginCode()
|
||||
.then((code) => {
|
||||
// 在微信小程序环境下,可以获取encryptedData和iv
|
||||
// #ifdef MP-WEIXIN
|
||||
resolve({
|
||||
code,
|
||||
encryptedData: e.detail.encryptedData,
|
||||
iv: e.detail.iv,
|
||||
});
|
||||
// #endif
|
||||
|
||||
// 其他环境或新版本接口
|
||||
// #ifndef MP-WEIXIN
|
||||
resolve({
|
||||
code,
|
||||
// 新版本接口在e.detail.code中包含手机号获取凭证
|
||||
...(e.detail.code ? { phoneCode: e.detail.code } : {}),
|
||||
});
|
||||
// #endif
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
})
|
||||
.finally(() => {
|
||||
authState.value.isLogining = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查会话有效性
|
||||
* @returns Promise 返回会话是否有效
|
||||
*/
|
||||
const checkSession = (): Promise<boolean> => {
|
||||
return new Promise((resolve) => {
|
||||
const token = getAccessToken();
|
||||
|
||||
if (!token) {
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用后端接口验证token有效性
|
||||
uni.request({
|
||||
url: "/api/v1/auth/check-session",
|
||||
method: "GET",
|
||||
header: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
success: (res: any) => {
|
||||
if (res.statusCode === 200 && res.data.valid) {
|
||||
resolve(true);
|
||||
} else {
|
||||
resolve(false);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
resolve(false);
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取用户头像昵称
|
||||
* 注意:此接口已于2021年弃用,仅作为兼容保留
|
||||
* 推荐使用button组件的open-type="chooseAvatar"让用户选择头像
|
||||
*/
|
||||
const getUserProfile = (): Promise<any> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// #ifdef MP-WEIXIN
|
||||
uni.getUserProfile({
|
||||
desc: "用于完善用户资料",
|
||||
success: (res) => {
|
||||
resolve(res.userInfo);
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
},
|
||||
});
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
reject(new Error("当前环境不支持获取用户信息"));
|
||||
// #endif
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
authState,
|
||||
getLoginCode,
|
||||
getPhoneNumber,
|
||||
checkSession,
|
||||
getUserProfile,
|
||||
};
|
||||
}
|
||||
@@ -6,11 +6,6 @@
|
||||
"style": {},
|
||||
"layout": "tabbar"
|
||||
},
|
||||
{
|
||||
"path": "pages/login/complete-profile",
|
||||
"type": "page",
|
||||
"style": {}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/index",
|
||||
"type": "page",
|
||||
@@ -37,6 +32,11 @@
|
||||
"type": "page",
|
||||
"style": {}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/profile/complete-profile",
|
||||
"type": "page",
|
||||
"style": {}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/profile/index",
|
||||
"type": "page",
|
||||
|
||||
@@ -3,48 +3,43 @@
|
||||
<!-- 背景图 -->
|
||||
<image src="/static/images/login-bg.svg" mode="aspectFill" class="login-bg" />
|
||||
|
||||
<!-- Logo和标题区域 -->
|
||||
<view class="header">
|
||||
<image src="/static/images/logo.png" mode="aspectFit" class="logo" />
|
||||
<text class="title">您好,欢迎回来</text>
|
||||
<text class="subtitle">登录您的账号,开始愉快的旅程</text>
|
||||
<image src="/static/logo.png" class="logo" />
|
||||
<text class="title">有来开源</text>
|
||||
<text class="subtitle">专注于构建高效开发的应用解决方案</text>
|
||||
</view>
|
||||
|
||||
<view class="login-card">
|
||||
<view class="form-wrap">
|
||||
<!-- 账号密码登录表单 -->
|
||||
<wd-form :model="LoginData" v-if="loginType === 'account'" ref="loginFormRef">
|
||||
<wd-form v-if="loginType === 'account'" ref="loginFormRef" :model="loginFormData">
|
||||
<!-- 用户名输入框 -->
|
||||
<view class="form-item">
|
||||
<wd-icon name="user" size="20" class="input-icon" />
|
||||
<wd-icon name="user" size="22" class="input-icon" />
|
||||
<input
|
||||
v-model="LoginData.username"
|
||||
v-model="loginFormData.username"
|
||||
class="form-input"
|
||||
placeholder="请输入用户名"
|
||||
placeholder-class="input-placeholder"
|
||||
/>
|
||||
<wd-icon
|
||||
v-if="LoginData.username"
|
||||
name="error-fill"
|
||||
size="14"
|
||||
class="clear-icon"
|
||||
@click="LoginData.username = ''"
|
||||
/>
|
||||
</view>
|
||||
<view class="divider"></view>
|
||||
|
||||
<!-- 密码输入框 -->
|
||||
<view class="form-item">
|
||||
<wd-icon name="lock" size="20" class="input-icon" />
|
||||
<wd-icon name="lock-on" size="22" class="input-icon" />
|
||||
<input
|
||||
v-model="LoginData.password"
|
||||
v-model="loginFormData.password"
|
||||
class="form-input"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
placeholder="请输入密码"
|
||||
placeholder-class="input-placeholder"
|
||||
/>
|
||||
<wd-icon
|
||||
:name="showPassword ? 'view' : 'view-off'"
|
||||
size="14"
|
||||
:name="showPassword ? 'eye-open' : 'eye-close'"
|
||||
size="18"
|
||||
color="#9ca3af"
|
||||
class="eye-icon"
|
||||
@click="showPassword = !showPassword"
|
||||
/>
|
||||
@@ -124,8 +119,7 @@ import { onLoad } from "@dcloudio/uni-app";
|
||||
import { type LoginData } from "@/api/auth";
|
||||
import { useUserStore } from "@/store/modules/user.store";
|
||||
import { useToast } from "wot-design-uni";
|
||||
import { getWxLoginCode, getWxPhoneNumber, wxAuthState } from "@/services/wechat.service";
|
||||
import { useTheme } from "@/composables/useTheme";
|
||||
import { useWechat } from "@/composables/useWechat";
|
||||
|
||||
const loginFormRef = ref();
|
||||
const toast = useToast();
|
||||
@@ -133,58 +127,32 @@ const loading = ref(false);
|
||||
const userStore = useUserStore();
|
||||
const showPassword = ref(false);
|
||||
const loginType = ref<"account" | "phone">("account");
|
||||
const { theme } = useTheme();
|
||||
const { authState, getLoginCode, getPhoneNumber } = useWechat();
|
||||
|
||||
// 登录表单数据
|
||||
const LoginData = ref<LoginData>({
|
||||
const loginFormData = ref<LoginData>({
|
||||
username: "",
|
||||
password: "",
|
||||
});
|
||||
|
||||
// 获取重定向参数
|
||||
const redirect = ref("");
|
||||
const redirect = ref("/pages/index/index");
|
||||
onLoad((options) => {
|
||||
if (options) {
|
||||
redirect.value = options.redirect ? decodeURIComponent(options.redirect) : "/pages/index/index";
|
||||
} else {
|
||||
redirect.value = "/pages/index/index";
|
||||
if (options && options.redirect) {
|
||||
redirect.value = decodeURIComponent(options.redirect);
|
||||
}
|
||||
|
||||
// 检查是否已登录
|
||||
checkLoginStatus();
|
||||
});
|
||||
|
||||
// 检查登录状态
|
||||
const checkLoginStatus = async () => {
|
||||
try {
|
||||
const token = uni.getStorageSync("app_token");
|
||||
if (token) {
|
||||
// 验证token有效性
|
||||
const isValid = await userStore.checkSession();
|
||||
if (isValid) {
|
||||
// 已登录,获取用户信息
|
||||
await userStore.getInfo();
|
||||
// 重定向到首页或指定页面
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({ url: redirect.value });
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("检查登录状态失败", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 账号密码登录处理
|
||||
const handleAccountLogin = () => {
|
||||
if (loading.value) return;
|
||||
|
||||
// 表单验证
|
||||
if (!LoginData.value.username) {
|
||||
if (!loginFormData.value.username) {
|
||||
toast.error("请输入用户名");
|
||||
return;
|
||||
}
|
||||
if (!LoginData.value.password) {
|
||||
if (!loginFormData.value.password) {
|
||||
toast.error("请输入密码");
|
||||
return;
|
||||
}
|
||||
@@ -192,27 +160,17 @@ const handleAccountLogin = () => {
|
||||
loading.value = true;
|
||||
|
||||
userStore
|
||||
.login(LoginData.value)
|
||||
.login(loginFormData.value)
|
||||
.then(() => userStore.getInfo())
|
||||
.then(() => {
|
||||
toast.success("登录成功");
|
||||
|
||||
// 检查用户信息是否完整
|
||||
if (!userStore.isUserInfoComplete()) {
|
||||
// 信息不完整,跳转到完善信息页面
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/login/complete-profile?redirect=${encodeURIComponent(redirect.value)}`,
|
||||
});
|
||||
}, 1000);
|
||||
} else {
|
||||
// 否则直接跳转到重定向页面
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: redirect.value,
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
// 账号密码登录直接跳转到重定向页面
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: redirect.value,
|
||||
});
|
||||
}, 1000);
|
||||
})
|
||||
.catch((error) => {
|
||||
toast.error(error?.message || "登录失败");
|
||||
@@ -223,16 +181,16 @@ const handleAccountLogin = () => {
|
||||
};
|
||||
|
||||
// 微信一键登录(通过手机号)
|
||||
const handleWechatPhoneLogin = async (e) => {
|
||||
if (loading.value || wxAuthState.value.isLogining) return;
|
||||
const handleWechatPhoneLogin = async (e: any) => {
|
||||
if (loading.value || authState.value.isLogining) return;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
// 获取手机号加密数据
|
||||
const phoneData = await getWxPhoneNumber(e);
|
||||
const phoneData = await getPhoneNumber(e);
|
||||
|
||||
// 调用登录接口
|
||||
const result = await userStore.loginByWechatPhone(phoneData);
|
||||
const result: any = await userStore.loginWithWxPhone(phoneData);
|
||||
|
||||
// 获取用户信息
|
||||
await userStore.getInfo();
|
||||
@@ -243,7 +201,7 @@ const handleWechatPhoneLogin = async (e) => {
|
||||
// 跳转到完善信息页面
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/login/complete-profile?redirect=${encodeURIComponent(redirect.value)}`,
|
||||
url: `/pages/mine/profile/complete-profile?redirect=${encodeURIComponent(redirect.value)}`,
|
||||
});
|
||||
}, 1000);
|
||||
} else {
|
||||
@@ -254,7 +212,7 @@ const handleWechatPhoneLogin = async (e) => {
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
if (error.message === "用户拒绝授权") {
|
||||
toast.error("您已拒绝授权获取手机号");
|
||||
} else {
|
||||
@@ -266,7 +224,7 @@ const handleWechatPhoneLogin = async (e) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 微信登录处理
|
||||
// 微信授权登录处理
|
||||
const handleWechatLogin = async () => {
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
@@ -274,10 +232,10 @@ const handleWechatLogin = async () => {
|
||||
try {
|
||||
// #ifdef MP-WEIXIN
|
||||
// 获取微信登录的临时 code
|
||||
const code = await getWxLoginCode();
|
||||
const code = await getLoginCode();
|
||||
|
||||
// 尝试使用微信登录接口
|
||||
const result = await userStore.loginByWechat(code);
|
||||
// 尝试使用微信授权登录接口
|
||||
const result: any = await userStore.loginWithWxCode(code);
|
||||
|
||||
// 获取用户信息
|
||||
await userStore.getInfo();
|
||||
@@ -288,7 +246,7 @@ const handleWechatLogin = async () => {
|
||||
// 如果信息不完整,跳转到完善信息页面
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/login/complete-profile?redirect=${encodeURIComponent(redirect.value)}`,
|
||||
url: `/pages/mine/profile/complete-profile?redirect=${encodeURIComponent(redirect.value)}`,
|
||||
});
|
||||
}, 1000);
|
||||
} else {
|
||||
@@ -304,7 +262,7 @@ const handleWechatLogin = async () => {
|
||||
// #ifndef MP-WEIXIN
|
||||
toast.error("当前环境不支持微信登录");
|
||||
// #endif
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
toast.error(error?.message || "微信登录失败");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
/**
|
||||
* 微信授权服务
|
||||
* 处理微信登录授权、获取用户信息等功能
|
||||
*/
|
||||
|
||||
import { ref } from "vue";
|
||||
import { getAccessToken } from "@/utils/auth";
|
||||
|
||||
// 定义微信授权状态
|
||||
export const wxAuthState = ref({
|
||||
isLogining: false,
|
||||
authDenied: false,
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取微信登录凭证
|
||||
* @returns Promise 返回登录凭证code
|
||||
*/
|
||||
export function getWxLoginCode(): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// #ifdef MP-WEIXIN
|
||||
uni.login({
|
||||
provider: "weixin",
|
||||
success: (res) => {
|
||||
if (res.code) {
|
||||
resolve(res.code);
|
||||
} else {
|
||||
reject(new Error("获取微信登录凭证失败"));
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
},
|
||||
});
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
reject(new Error("当前环境不支持微信登录"));
|
||||
// #endif
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信用户手机号
|
||||
* @param e 微信授权返回的事件对象
|
||||
* @returns Promise 返回包含加密数据的对象
|
||||
*/
|
||||
export function getWxPhoneNumber(
|
||||
e: any
|
||||
): Promise<{ code: string; encryptedData?: string; iv?: string }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
wxAuthState.value.isLogining = true;
|
||||
|
||||
// 判断授权是否成功
|
||||
if (e.detail.errMsg !== "getPhoneNumber:ok") {
|
||||
wxAuthState.value.isLogining = false;
|
||||
wxAuthState.value.authDenied = true;
|
||||
reject(new Error("用户拒绝授权"));
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取登录凭证code
|
||||
getWxLoginCode()
|
||||
.then((code) => {
|
||||
// 在微信小程序环境下,可以获取encryptedData和iv
|
||||
// #ifdef MP-WEIXIN
|
||||
resolve({
|
||||
code,
|
||||
encryptedData: e.detail.encryptedData,
|
||||
iv: e.detail.iv,
|
||||
});
|
||||
// #endif
|
||||
|
||||
// 其他环境或新版本接口
|
||||
// #ifndef MP-WEIXIN
|
||||
resolve({
|
||||
code,
|
||||
// 新版本接口在e.detail.code中包含手机号获取凭证
|
||||
...(e.detail.code ? { phoneCode: e.detail.code } : {}),
|
||||
});
|
||||
// #endif
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
})
|
||||
.finally(() => {
|
||||
wxAuthState.value.isLogining = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查微信会话有效性
|
||||
* 检查本地token是否存在,如存在则检查其有效性
|
||||
*/
|
||||
export function checkWxSession(): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
const token = getAccessToken();
|
||||
|
||||
if (!token) {
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用后端接口验证token有效性
|
||||
uni.request({
|
||||
url: "/api/v1/auth/check-session",
|
||||
method: "GET",
|
||||
header: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
success: (res: any) => {
|
||||
if (res.statusCode === 200 && res.data.valid) {
|
||||
resolve(true);
|
||||
} else {
|
||||
resolve(false);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
resolve(false);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信用户信息(如头像、昵称等)
|
||||
* 注意:此接口在2021年4月后的小程序新版本中需要额外授权
|
||||
*/
|
||||
export function getWxUserProfile(): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// #ifdef MP-WEIXIN
|
||||
uni.getUserProfile({
|
||||
desc: "用于完善用户资料",
|
||||
success: (res) => {
|
||||
resolve(res.userInfo);
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
},
|
||||
});
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
reject(new Error("当前环境不支持获取用户信息"));
|
||||
// #endif
|
||||
});
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import { Storage } from "@/utils/storage";
|
||||
export const useUserStore = defineStore("user", () => {
|
||||
const userInfo = ref<UserInfo | undefined>(getUserInfo());
|
||||
|
||||
// 登录
|
||||
// 账号密码登录
|
||||
const login = (data: LoginData) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
AuthAPI.login(data)
|
||||
@@ -24,8 +24,8 @@ export const useUserStore = defineStore("user", () => {
|
||||
});
|
||||
};
|
||||
|
||||
// 微信登录
|
||||
const loginByWechat = (code: string) => {
|
||||
// 微信基础授权登录
|
||||
const loginWithWxCode = (code: string) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
AuthAPI.wechatLogin(code)
|
||||
.then((data) => {
|
||||
@@ -33,29 +33,14 @@ export const useUserStore = defineStore("user", () => {
|
||||
resolve(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("微信登录失败", error);
|
||||
console.error("微信授权登录失败", error);
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 微信小程序增强登录
|
||||
const loginByWechatMini = (data: WxLoginData): Promise<any> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
AuthAPI.wechatMiniLogin(data)
|
||||
.then((result) => {
|
||||
setAccessToken(result.accessToken);
|
||||
resolve(result);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("微信小程序登录失败", error);
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 微信手机号一键登录
|
||||
const loginByWechatPhone = (data: WxLoginData): Promise<any> => {
|
||||
// 微信手机号授权登录
|
||||
const loginWithWxPhone = (data: WxLoginData): Promise<any> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
AuthAPI.wechatPhoneLogin(data)
|
||||
.then((result) => {
|
||||
@@ -121,9 +106,8 @@ export const useUserStore = defineStore("user", () => {
|
||||
return {
|
||||
userInfo,
|
||||
login,
|
||||
loginByWechat,
|
||||
loginByWechatMini,
|
||||
loginByWechatPhone,
|
||||
loginWithWxCode,
|
||||
loginWithWxPhone,
|
||||
logout,
|
||||
getInfo,
|
||||
checkSession,
|
||||
|
||||
@@ -140,33 +140,3 @@ export function requireLogin(): void {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查令牌是否过期
|
||||
* 这是一个简单实现,如果需要更精确的检查,应该解析JWT的payload
|
||||
* @returns 是否过期
|
||||
*/
|
||||
export function isTokenExpired(token: string): boolean {
|
||||
if (!token) return true;
|
||||
|
||||
try {
|
||||
// 简单解析JWT payload (不验证签名)
|
||||
const base64Url = token.split(".")[1];
|
||||
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
|
||||
const payload = JSON.parse(
|
||||
decodeURIComponent(
|
||||
atob(base64)
|
||||
.split("")
|
||||
.map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2))
|
||||
.join("")
|
||||
)
|
||||
);
|
||||
|
||||
// 检查过期时间
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
return payload.exp < now;
|
||||
} catch (e) {
|
||||
console.error("解析token失败", e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getAccessToken, getRefreshToken, isTokenExpired, setAccessToken } from "./auth";
|
||||
import { getAccessToken, getRefreshToken, setAccessToken } from "./auth";
|
||||
|
||||
// 刷新令牌的锁,防止多个请求同时刷新令牌
|
||||
let isRefreshing = false;
|
||||
@@ -58,8 +58,6 @@ interface RequestOptions<T = any> {
|
||||
header?: Record<string, string>;
|
||||
timeout?: number;
|
||||
responseType?: "text" | "arraybuffer";
|
||||
// 是否跳过令牌刷新 (用于刷新令牌接口本身)
|
||||
skipTokenRefresh?: boolean;
|
||||
}
|
||||
|
||||
// 请求函数
|
||||
@@ -89,12 +87,6 @@ function request<T = any>(options: RequestOptions): Promise<T> {
|
||||
}
|
||||
// 未授权错误
|
||||
else if (res.statusCode === 401) {
|
||||
// 跳过令牌刷新的请求直接返回错误
|
||||
if (options.skipTokenRefresh) {
|
||||
reject(new Error("未授权"));
|
||||
return;
|
||||
}
|
||||
|
||||
// 尝试刷新令牌
|
||||
if (!isRefreshing) {
|
||||
isRefreshing = true;
|
||||
@@ -141,7 +133,7 @@ function request<T = any>(options: RequestOptions): Promise<T> {
|
||||
};
|
||||
|
||||
// 检查令牌是否过期
|
||||
if (token && !options.skipTokenRefresh && isTokenExpired(token)) {
|
||||
if (token) {
|
||||
if (!isRefreshing) {
|
||||
isRefreshing = true;
|
||||
|
||||
|
||||
2
uni-pages.d.ts
vendored
2
uni-pages.d.ts
vendored
@@ -5,12 +5,12 @@
|
||||
|
||||
interface NavigateToOptions {
|
||||
url: "/pages/index/index" |
|
||||
"/pages/login/complete-profile" |
|
||||
"/pages/login/index" |
|
||||
"/pages/mine/index" |
|
||||
"/pages/mine/about/index" |
|
||||
"/pages/mine/faq/index" |
|
||||
"/pages/mine/feedback/index" |
|
||||
"/pages/mine/profile/complete-profile" |
|
||||
"/pages/mine/profile/index" |
|
||||
"/pages/mine/settings/index" |
|
||||
"/pages/mine/settings/account/index" |
|
||||
|
||||
Reference in New Issue
Block a user