chore: 移除微信授权登录
This commit is contained in:
@@ -7,13 +7,6 @@ export interface LoginData {
|
|||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WxLoginData {
|
|
||||||
code: string;
|
|
||||||
encryptedData?: string;
|
|
||||||
iv?: string;
|
|
||||||
phoneCode?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LoginResult {
|
export interface LoginResult {
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
refreshToken?: string;
|
refreshToken?: string;
|
||||||
@@ -23,6 +16,11 @@ export interface LoginResult {
|
|||||||
isProfileComplete?: boolean;
|
isProfileComplete?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SmsLoginData {
|
||||||
|
mobile: string;
|
||||||
|
code: string;
|
||||||
|
}
|
||||||
|
|
||||||
const AuthAPI = {
|
const AuthAPI = {
|
||||||
/**
|
/**
|
||||||
* 账号密码登录
|
* 账号密码登录
|
||||||
@@ -37,42 +35,20 @@ const AuthAPI = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
sendSmsLoginCode(mobile: string): Promise<void> {
|
||||||
* 微信Web授权登录 (使用code进行授权登录)
|
const mobileSafe = encodeURIComponent(mobile);
|
||||||
* @param code 微信授权码
|
return publicRequest<void>({
|
||||||
* @returns 登录结果
|
url: `${AUTH_BASE_URL}/sms/code?mobile=${mobileSafe}`,
|
||||||
*/
|
|
||||||
loginByWechat(code: string): Promise<LoginResult> {
|
|
||||||
return publicRequest<LoginResult>({
|
|
||||||
url: `${AUTH_BASE_URL}/login/wechat`,
|
|
||||||
method: "POST",
|
method: "POST",
|
||||||
data: { code },
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
loginBySms(data: SmsLoginData): Promise<LoginResult> {
|
||||||
* 微信小程序授权登录 (仅使用code获取OpenID)
|
const mobileSafe = encodeURIComponent(data.mobile);
|
||||||
* @param code 微信登录凭证
|
const codeSafe = encodeURIComponent(data.code);
|
||||||
* @returns 登录结果
|
|
||||||
*/
|
|
||||||
loginByWxMiniAppCode(code: string): Promise<LoginResult> {
|
|
||||||
return publicRequest<LoginResult>({
|
return publicRequest<LoginResult>({
|
||||||
url: `${AUTH_BASE_URL}/wx/miniapp/code-login`,
|
url: `${AUTH_BASE_URL}/login/sms?mobile=${mobileSafe}&code=${codeSafe}`,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
data: { code },
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 微信小程序手机号授权登录
|
|
||||||
* @param data 包含code、encryptedData、iv等手机号相关数据
|
|
||||||
* @returns 登录结果
|
|
||||||
*/
|
|
||||||
loginByWxMiniAppPhone(data: WxLoginData): Promise<LoginResult> {
|
|
||||||
return publicRequest<LoginResult>({
|
|
||||||
url: `${AUTH_BASE_URL}/wx/miniapp/phone-login`,
|
|
||||||
method: "POST",
|
|
||||||
data,
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -25,10 +25,7 @@ const UserAPI = {
|
|||||||
url: `${USER_BASE_URL}`,
|
url: `${USER_BASE_URL}`,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
data: queryParams,
|
data: queryParams,
|
||||||
}).then((res: { data: UserPageVO[]; page?: { total?: number } }) => ({
|
});
|
||||||
list: res.data,
|
|
||||||
total: res.page?.total ?? 0,
|
|
||||||
}));
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 添加用户
|
* 添加用户
|
||||||
@@ -138,15 +135,6 @@ const UserAPI = {
|
|||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 获取微信手机号 */
|
|
||||||
getPhoneNumber(data: WechatPhoneData): Promise<PhoneNumberResult> {
|
|
||||||
return request<PhoneNumberResult>({
|
|
||||||
url: `${USER_BASE_URL}/wechat-phone`,
|
|
||||||
method: "POST",
|
|
||||||
data: data,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
export default UserAPI;
|
export default UserAPI;
|
||||||
|
|
||||||
@@ -326,23 +314,3 @@ export interface UserForm {
|
|||||||
/** 用户名 */
|
/** 用户名 */
|
||||||
username?: string;
|
username?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 微信手机号授权数据 */
|
|
||||||
export interface WechatPhoneData {
|
|
||||||
/** 微信授权码 */
|
|
||||||
code: string;
|
|
||||||
/** 加密数据 */
|
|
||||||
encryptedData?: string;
|
|
||||||
/** 初始向量 */
|
|
||||||
iv?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 手机号获取结果 */
|
|
||||||
export interface PhoneNumberResult {
|
|
||||||
/** 手机号 */
|
|
||||||
phoneNumber: string;
|
|
||||||
/** 纯手机号(去除+86) */
|
|
||||||
purePhoneNumber?: string;
|
|
||||||
/** 国家代码 */
|
|
||||||
countryCode?: string;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,159 +0,0 @@
|
|||||||
/**
|
|
||||||
* 微信授权服务
|
|
||||||
* 处理微信登录授权、获取用户信息等功能
|
|
||||||
*/
|
|
||||||
|
|
||||||
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,7 +6,7 @@
|
|||||||
<!-- 登录卡片 -->
|
<!-- 登录卡片 -->
|
||||||
<view class="login-card">
|
<view class="login-card">
|
||||||
<!-- 账号密码登录表单 -->
|
<!-- 账号密码登录表单 -->
|
||||||
<wd-form v-if="loginType === 'account'" ref="loginFormRef" :model="loginFormData">
|
<wd-form v-if="loginMode === 'ACCOUNT'" ref="loginFormRef" :model="loginFormData">
|
||||||
<!-- 用户名输入框 -->
|
<!-- 用户名输入框 -->
|
||||||
<view class="login-form__item">
|
<view class="login-form__item">
|
||||||
<wd-icon name="user" size="22" class="mr-20rpx" />
|
<wd-icon name="user" size="22" class="mr-20rpx" />
|
||||||
@@ -47,49 +47,51 @@
|
|||||||
>
|
>
|
||||||
{{ loading ? "登录中..." : "账号登录" }}
|
{{ loading ? "登录中..." : "账号登录" }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- 切换登录方式 -->
|
|
||||||
<view class="login-switch" @click="loginType = 'phone'">
|
|
||||||
<text>使用手机号一键登录</text>
|
|
||||||
<wd-icon name="arrow-right" size="12" />
|
|
||||||
</view>
|
|
||||||
</wd-form>
|
</wd-form>
|
||||||
|
|
||||||
<!-- 手机号登录 -->
|
<wd-form v-else ref="smsLoginFormRef" :model="smsLoginFormData">
|
||||||
<view v-else class="phone-login">
|
<view class="login-form__item">
|
||||||
<view class="phone-login__title">微信一键登录</view>
|
<wd-icon name="phone" size="22" class="mr-20rpx" />
|
||||||
<view class="phone-login__subtitle">授权后将获取您的手机号</view>
|
<input
|
||||||
|
v-model="smsLoginFormData.mobile"
|
||||||
|
class="login-form__input"
|
||||||
|
placeholder="请输入手机号"
|
||||||
|
placeholder-class="login-form__placeholder"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
<view class="login-form__divider"></view>
|
||||||
|
|
||||||
|
<view class="login-form__item">
|
||||||
|
<wd-icon name="security" size="22" class="mr-20rpx" />
|
||||||
|
<input
|
||||||
|
v-model="smsLoginFormData.code"
|
||||||
|
class="login-form__input"
|
||||||
|
placeholder="请输入验证码"
|
||||||
|
placeholder-class="login-form__placeholder"
|
||||||
|
/>
|
||||||
|
<wd-button
|
||||||
|
size="small"
|
||||||
|
plain
|
||||||
|
:disabled="smsCountdown > 0"
|
||||||
|
@click="handleSendSmsLoginCode"
|
||||||
|
>
|
||||||
|
{{ smsCountdown > 0 ? `${smsCountdown}s后重试` : "发送验证码" }}
|
||||||
|
</wd-button>
|
||||||
|
</view>
|
||||||
|
<view class="login-form__divider"></view>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="wechat-btn"
|
class="login-btn"
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
open-type="getPhoneNumber"
|
:class="{ 'login-btn--loading': loading }"
|
||||||
@getphonenumber="handleWechatPhoneLogin"
|
@click="handleSmsLogin"
|
||||||
>
|
>
|
||||||
<wd-icon name="weixin" size="24" color="#ffffff" />
|
{{ loading ? "登录中..." : "短信登录" }}
|
||||||
<text class="ml-16rpx">微信一键登录</text>
|
|
||||||
</button>
|
</button>
|
||||||
|
</wd-form>
|
||||||
|
|
||||||
<!-- 切换登录方式 -->
|
<view class="login-switch" @click="loginMode = loginMode === 'ACCOUNT' ? 'SMS' : 'ACCOUNT'">
|
||||||
<view class="login-switch" @click="loginType = 'account'">
|
{{ loginMode === "ACCOUNT" ? "使用短信验证码登录" : "使用账号密码登录" }}
|
||||||
<text>使用账号密码登录</text>
|
|
||||||
<wd-icon name="arrow-right" size="12" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 其他登录方式 -->
|
|
||||||
<view class="other-login">
|
|
||||||
<view class="other-login__title">
|
|
||||||
<view class="other-login__line"></view>
|
|
||||||
<text class="other-login__text">其他登录方式</text>
|
|
||||||
<view class="other-login__line"></view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="flex-center" @click="handleWechatLogin">
|
|
||||||
<view class="wechat-icon">
|
|
||||||
<image src="/static/icons/weixin.png" class="w-40rpx h-40rpx" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 底部协议 -->
|
<!-- 底部协议 -->
|
||||||
@@ -120,19 +122,21 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onLoad } from "@dcloudio/uni-app";
|
import { onLoad } from "@dcloudio/uni-app";
|
||||||
import { type LoginData } from "@/api/auth";
|
import AuthAPI, { type LoginData } from "@/api/auth";
|
||||||
import { useUserStore } from "@/store/modules/user-store";
|
import { useUserStore } from "@/store/modules/user-store";
|
||||||
import { useToast } from "wot-design-uni";
|
import { useToast } from "wot-design-uni";
|
||||||
import { useWechat } from "@/composables/useWechat";
|
|
||||||
|
|
||||||
const loginFormRef = ref();
|
const loginFormRef = ref();
|
||||||
|
const smsLoginFormRef = ref();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const showPassword = ref(false);
|
const showPassword = ref(false);
|
||||||
const loginType = ref<"account" | "phone">("account");
|
|
||||||
const isAgreePolicy = ref(false); // 是否同意隐私协议
|
const isAgreePolicy = ref(false); // 是否同意隐私协议
|
||||||
const { authState, getLoginCode, getPhoneNumber } = useWechat();
|
|
||||||
|
const loginMode = ref<"ACCOUNT" | "SMS">("ACCOUNT");
|
||||||
|
const smsCountdown = ref(0);
|
||||||
|
const smsTimer = ref<ReturnType<typeof setInterval> | null>(null);
|
||||||
|
|
||||||
// 登录表单数据
|
// 登录表单数据
|
||||||
const loginFormData = ref<LoginData>({
|
const loginFormData = ref<LoginData>({
|
||||||
@@ -140,9 +144,14 @@ const loginFormData = ref<LoginData>({
|
|||||||
password: "123456",
|
password: "123456",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const smsLoginFormData = ref({
|
||||||
|
mobile: "",
|
||||||
|
code: "",
|
||||||
|
});
|
||||||
|
|
||||||
// 仅使用 query 作为重定向来源
|
// 仅使用 query 作为重定向来源
|
||||||
const redirect = ref("/pages/index/index");
|
const redirect = ref("/pages/index/index");
|
||||||
onLoad((options) => {
|
onLoad((options: any) => {
|
||||||
const fromQuery = options && options.redirect ? decodeURIComponent(options.redirect) : "";
|
const fromQuery = options && options.redirect ? decodeURIComponent(options.redirect) : "";
|
||||||
if (fromQuery && fromQuery !== "/pages/login/index") {
|
if (fromQuery && fromQuery !== "/pages/login/index") {
|
||||||
redirect.value = fromQuery;
|
redirect.value = fromQuery;
|
||||||
@@ -184,7 +193,7 @@ const handleAccountLogin = () => {
|
|||||||
uni.reLaunch({ url: redirect.value });
|
uni.reLaunch({ url: redirect.value });
|
||||||
}, 1000);
|
}, 1000);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error: any) => {
|
||||||
toast.error(error?.message || "登录失败");
|
toast.error(error?.message || "登录失败");
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
@@ -192,100 +201,63 @@ const handleAccountLogin = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 微信一键登录(通过手机号)
|
const handleSendSmsLoginCode = async () => {
|
||||||
const handleWechatPhoneLogin = async (e: any) => {
|
if (smsCountdown.value > 0) return;
|
||||||
if (loading.value || authState.value.isLogining) return;
|
if (!smsLoginFormData.value.mobile) {
|
||||||
|
toast.error("请输入手机号");
|
||||||
// 检查是否同意隐私协议
|
|
||||||
if (!isAgreePolicy.value) {
|
|
||||||
toast.error("请先阅读并同意用户协议和隐私政策");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
loading.value = true;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 获取手机号加密数据
|
await AuthAPI.sendSmsLoginCode(smsLoginFormData.value.mobile);
|
||||||
const phoneData = await getPhoneNumber(e);
|
toast.success("验证码已发送");
|
||||||
|
smsCountdown.value = 60;
|
||||||
// 调用登录接口
|
if (smsTimer.value) clearInterval(smsTimer.value);
|
||||||
const result: any = await userStore.loginWithWxPhone(phoneData);
|
smsTimer.value = setInterval(() => {
|
||||||
|
smsCountdown.value -= 1;
|
||||||
// 获取用户信息
|
if (smsCountdown.value <= 0) {
|
||||||
await userStore.getInfo();
|
smsCountdown.value = 0;
|
||||||
toast.success("登录成功");
|
if (smsTimer.value) {
|
||||||
|
clearInterval(smsTimer.value);
|
||||||
// 检查是否为新用户或信息不完整
|
smsTimer.value = null;
|
||||||
if (result.isNewUser || !userStore.isUserInfoComplete()) {
|
}
|
||||||
// 跳转到完善信息页面
|
}
|
||||||
setTimeout(() => {
|
}, 1000);
|
||||||
// 跳转完善资料,redirect 保持在缓存中供目标页读取
|
|
||||||
uni.navigateTo({ url: "/pages/mine/profile/complete-profile" });
|
|
||||||
}, 1000);
|
|
||||||
} else {
|
|
||||||
// 跳转到重定向页面
|
|
||||||
setTimeout(() => {
|
|
||||||
uni.reLaunch({ url: redirect.value });
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (error.message === "用户拒绝授权") {
|
toast.error(error?.message || "发送失败");
|
||||||
toast.error("您已拒绝授权获取手机号");
|
|
||||||
} else {
|
|
||||||
toast.error(error?.message || "登录失败");
|
|
||||||
}
|
|
||||||
console.error("微信手机号登录失败:", error);
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 微信授权登录处理
|
const handleSmsLogin = () => {
|
||||||
const handleWechatLogin = async () => {
|
|
||||||
if (loading.value) return;
|
if (loading.value) return;
|
||||||
|
|
||||||
// 检查是否同意隐私协议
|
|
||||||
if (!isAgreePolicy.value) {
|
if (!isAgreePolicy.value) {
|
||||||
toast.error("请先阅读并同意用户协议和隐私政策");
|
toast.error("请先阅读并同意用户协议和隐私政策");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!smsLoginFormData.value.mobile) {
|
||||||
|
toast.error("请输入手机号");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!smsLoginFormData.value.code) {
|
||||||
|
toast.error("请输入验证码");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
userStore
|
||||||
try {
|
.loginBySms({ mobile: smsLoginFormData.value.mobile, code: smsLoginFormData.value.code })
|
||||||
// #ifdef MP-WEIXIN
|
.then(() => userStore.getInfo())
|
||||||
// 获取微信登录的临时 code
|
.then(() => {
|
||||||
const code = await getLoginCode();
|
toast.success("登录成功");
|
||||||
|
|
||||||
// 在微信小程序环境下,使用小程序授权登录接口
|
|
||||||
const result: any = await userStore.loginWithWxMiniAppCode(code);
|
|
||||||
|
|
||||||
// 获取用户信息
|
|
||||||
await userStore.getInfo();
|
|
||||||
toast.success("登录成功");
|
|
||||||
|
|
||||||
// 检查用户信息是否完整
|
|
||||||
if (result.isNewUser || !userStore.isUserInfoComplete()) {
|
|
||||||
// 如果信息不完整,跳转到完善信息页面
|
|
||||||
setTimeout(() => {
|
|
||||||
uni.navigateTo({ url: "/pages/mine/profile/complete-profile" });
|
|
||||||
}, 1000);
|
|
||||||
} else {
|
|
||||||
// 否则直接跳转到重定向页面
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.reLaunch({ url: redirect.value });
|
uni.reLaunch({ url: redirect.value });
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
})
|
||||||
// #endif
|
.catch((error: any) => {
|
||||||
|
toast.error(error?.message || "登录失败");
|
||||||
// #ifndef MP-WEIXIN
|
})
|
||||||
toast.error("当前环境不支持微信登录");
|
.finally(() => {
|
||||||
// #endif
|
loading.value = false;
|
||||||
} catch (error: any) {
|
});
|
||||||
toast.error(error?.message || "微信登录失败");
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 跳转到用户协议页面
|
// 跳转到用户协议页面
|
||||||
@@ -416,20 +388,6 @@ const navigateToPrivacy = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 微信按钮
|
|
||||||
.wechat-btn {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
height: 88rpx;
|
|
||||||
font-size: 32rpx;
|
|
||||||
color: #ffffff;
|
|
||||||
background-color: #07c160;
|
|
||||||
border: none;
|
|
||||||
border-radius: 44rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 其他登录方式
|
// 其他登录方式
|
||||||
.other-login {
|
.other-login {
|
||||||
margin-top: 60rpx;
|
margin-top: 60rpx;
|
||||||
@@ -454,17 +412,6 @@ const navigateToPrivacy = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 微信图标
|
|
||||||
.wechat-icon {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 80rpx;
|
|
||||||
height: 80rpx;
|
|
||||||
background-color: #07c160;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 登录协议
|
// 登录协议
|
||||||
.login-agreement {
|
.login-agreement {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -102,22 +102,12 @@
|
|||||||
手机号
|
手机号
|
||||||
<text class="required">*</text>
|
<text class="required">*</text>
|
||||||
</view>
|
</view>
|
||||||
<view v-if="!profileForm.mobile" class="phone-auth">
|
<wd-input
|
||||||
<button
|
v-model="profileForm.mobile"
|
||||||
class="phone-auth-btn"
|
placeholder="请输入手机号"
|
||||||
open-type="getPhoneNumber"
|
prop="mobile"
|
||||||
:disabled="phoneAuthLoading"
|
custom-class="nickname-input"
|
||||||
@getphonenumber="onGetPhoneNumber"
|
/>
|
||||||
>
|
|
||||||
<wd-icon name="phone" size="20" color="#165DFF" />
|
|
||||||
<text class="auth-text">{{ phoneAuthLoading ? "授权中..." : "授权获取手机号" }}</text>
|
|
||||||
</button>
|
|
||||||
</view>
|
|
||||||
<view v-else class="phone-display">
|
|
||||||
<wd-icon name="phone" size="20" color="#52c41a" />
|
|
||||||
<text class="phone-number">{{ formatPhoneNumber(profileForm.mobile) }}</text>
|
|
||||||
<text class="change-phone" @click="changePhone">更换</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</wd-form>
|
</wd-form>
|
||||||
</view>
|
</view>
|
||||||
@@ -183,7 +173,6 @@ const rules = {
|
|||||||
|
|
||||||
// 状态管理
|
// 状态管理
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const phoneAuthLoading = ref(false);
|
|
||||||
const cropperVisible = ref(false);
|
const cropperVisible = ref(false);
|
||||||
const originalImageSrc = ref("");
|
const originalImageSrc = ref("");
|
||||||
const profileFormRef = ref();
|
const profileFormRef = ref();
|
||||||
@@ -280,45 +269,6 @@ const handleAvatarConfirm = async (event: any) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取手机号授权
|
|
||||||
const onGetPhoneNumber = async (e: any) => {
|
|
||||||
console.log("手机号授权回调:", e);
|
|
||||||
|
|
||||||
if (e.detail.errMsg === "getPhoneNumber:ok") {
|
|
||||||
phoneAuthLoading.value = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 调用后端接口解析手机号
|
|
||||||
const phoneData = await UserAPI.getPhoneNumber({
|
|
||||||
code: e.detail.code,
|
|
||||||
encryptedData: e.detail.encryptedData,
|
|
||||||
iv: e.detail.iv,
|
|
||||||
});
|
|
||||||
|
|
||||||
profileForm.mobile = phoneData.phoneNumber;
|
|
||||||
toast.success("手机号授权成功");
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error("手机号授权失败:", error);
|
|
||||||
toast.error(error?.message || "手机号授权失败");
|
|
||||||
} finally {
|
|
||||||
phoneAuthLoading.value = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
toast.error("手机号授权失败");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 更换手机号
|
|
||||||
const changePhone = () => {
|
|
||||||
profileForm.mobile = "";
|
|
||||||
};
|
|
||||||
|
|
||||||
// 格式化手机号显示
|
|
||||||
const formatPhoneNumber = (phone: string) => {
|
|
||||||
if (!phone) return "";
|
|
||||||
return phone.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2");
|
|
||||||
};
|
|
||||||
|
|
||||||
// 完成信息填写
|
// 完成信息填写
|
||||||
const handleComplete = async () => {
|
const handleComplete = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -327,7 +277,7 @@ const handleComplete = async () => {
|
|||||||
if (!valid) return;
|
if (!valid) return;
|
||||||
|
|
||||||
if (!profileForm.mobile) {
|
if (!profileForm.mobile) {
|
||||||
toast.error("请先授权获取手机号");
|
toast.error("请输入手机号");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,51 +427,6 @@ const handleSkip = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.phone-auth {
|
|
||||||
.phone-auth-btn {
|
|
||||||
display: flex;
|
|
||||||
gap: 12rpx;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
height: 88rpx;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #fff;
|
|
||||||
background: linear-gradient(90deg, #165dff, #4080ff);
|
|
||||||
border: none;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
|
|
||||||
&[disabled] {
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.auth-text {
|
|
||||||
font-size: 28rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.phone-display {
|
|
||||||
display: flex;
|
|
||||||
gap: 12rpx;
|
|
||||||
align-items: center;
|
|
||||||
padding: 24rpx 20rpx;
|
|
||||||
background: #f0f9ff;
|
|
||||||
border: 1rpx solid #bae6fd;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
|
|
||||||
.phone-number {
|
|
||||||
flex: 1;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.change-phone {
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #165dff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
.complete-btn {
|
.complete-btn {
|
||||||
margin-bottom: 30rpx;
|
margin-bottom: 30rpx;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import AuthAPI, { type LoginData, type WxLoginData } from "@/api/auth";
|
import AuthAPI, { type LoginData, type SmsLoginData } from "@/api/auth";
|
||||||
import UserAPI, { type UserInfo } from "@/api/user";
|
import UserAPI, { type UserInfo } from "@/api/user";
|
||||||
import { setAccessToken, clearTokens } from "@/utils/auth";
|
import { setAccessToken, clearTokens } from "@/utils/auth";
|
||||||
import { getUserInfo, setUserInfo } from "@/utils/storage";
|
import { getUserInfo, setUserInfo } from "@/utils/storage";
|
||||||
@@ -24,46 +24,15 @@ export const useUserStore = defineStore("user", () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 微信Web授权登录
|
const loginBySms = (data: SmsLoginData) => {
|
||||||
const loginWithWxCode = (code: string) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
AuthAPI.loginByWechat(code)
|
AuthAPI.loginBySms(data)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
setAccessToken(data.accessToken);
|
setAccessToken(data.accessToken);
|
||||||
resolve(data);
|
resolve(data);
|
||||||
})
|
})
|
||||||
.catch((error: any) => {
|
.catch((error) => {
|
||||||
console.error("微信授权登录失败", error);
|
console.error("登录失败", error);
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 微信小程序授权登录 (仅使用code获取OpenID)
|
|
||||||
const loginWithWxMiniAppCode = (code: string) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
AuthAPI.loginByWxMiniAppCode(code)
|
|
||||||
.then((data) => {
|
|
||||||
setAccessToken(data.accessToken);
|
|
||||||
resolve(data);
|
|
||||||
})
|
|
||||||
.catch((error: any) => {
|
|
||||||
console.error("微信小程序授权登录失败", error);
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 微信手机号授权登录
|
|
||||||
const loginWithWxPhone = (data: WxLoginData): Promise<any> => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
AuthAPI.loginByWxMiniAppPhone(data)
|
|
||||||
.then((result: any) => {
|
|
||||||
setAccessToken(result.accessToken);
|
|
||||||
resolve(result);
|
|
||||||
})
|
|
||||||
.catch((error: any) => {
|
|
||||||
console.error("微信手机号登录失败", error);
|
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -126,9 +95,7 @@ export const useUserStore = defineStore("user", () => {
|
|||||||
return {
|
return {
|
||||||
userInfo,
|
userInfo,
|
||||||
login,
|
login,
|
||||||
loginWithWxCode,
|
loginBySms,
|
||||||
loginWithWxMiniAppCode,
|
|
||||||
loginWithWxPhone,
|
|
||||||
logout,
|
logout,
|
||||||
getInfo,
|
getInfo,
|
||||||
checkSession,
|
checkSession,
|
||||||
|
|||||||
2
src/types/auto-imports.d.ts
vendored
2
src/types/auto-imports.d.ts
vendored
@@ -179,7 +179,6 @@ declare global {
|
|||||||
const useUploadFile: typeof import('@uni-helper/uni-use')['useUploadFile']
|
const useUploadFile: typeof import('@uni-helper/uni-use')['useUploadFile']
|
||||||
const useUserStore: typeof import('../store/modules/user-store')['useUserStore']
|
const useUserStore: typeof import('../store/modules/user-store')['useUserStore']
|
||||||
const useVisible: typeof import('@uni-helper/uni-use')['useVisible']
|
const useVisible: typeof import('@uni-helper/uni-use')['useVisible']
|
||||||
const useWechat: typeof import('../composables/useWechat')['useWechat']
|
|
||||||
const user: typeof import('../api/user')['default']
|
const user: typeof import('../api/user')['default']
|
||||||
const watch: typeof import('vue')['watch']
|
const watch: typeof import('vue')['watch']
|
||||||
const watchEffect: typeof import('vue')['watchEffect']
|
const watchEffect: typeof import('vue')['watchEffect']
|
||||||
@@ -320,7 +319,6 @@ declare module 'vue' {
|
|||||||
readonly useThemeStore: UnwrapRef<typeof import('../store/modules/theme-store')['useThemeStore']>
|
readonly useThemeStore: UnwrapRef<typeof import('../store/modules/theme-store')['useThemeStore']>
|
||||||
readonly useToast: UnwrapRef<typeof import('wot-design-uni')['useToast']>
|
readonly useToast: UnwrapRef<typeof import('wot-design-uni')['useToast']>
|
||||||
readonly useUserStore: UnwrapRef<typeof import('../store/modules/user-store')['useUserStore']>
|
readonly useUserStore: UnwrapRef<typeof import('../store/modules/user-store')['useUserStore']>
|
||||||
readonly useWechat: UnwrapRef<typeof import('../composables/useWechat')['useWechat']>
|
|
||||||
readonly user: UnwrapRef<typeof import('../api/user')['default']>
|
readonly user: UnwrapRef<typeof import('../api/user')['default']>
|
||||||
readonly watch: UnwrapRef<typeof import('vue')['watch']>
|
readonly watch: UnwrapRef<typeof import('vue')['watch']>
|
||||||
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
|
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
|
||||||
|
|||||||
@@ -54,11 +54,7 @@ function request<T = any>(options: RequestOptions): Promise<T> {
|
|||||||
success: (res: any) => {
|
success: (res: any) => {
|
||||||
// 请求成功
|
// 请求成功
|
||||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||||
if (res.data && typeof res.data === "object" && "page" in res.data && res.data.page != null) {
|
resolve(res.data.data);
|
||||||
resolve({ data: res.data.data, page: res.data.page } as any);
|
|
||||||
} else {
|
|
||||||
resolve(res.data.data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 未授权错误
|
// 未授权错误
|
||||||
else if (res.statusCode === 401) {
|
else if (res.statusCode === 401) {
|
||||||
|
|||||||
Reference in New Issue
Block a user