This commit is contained in:
yvan 2025-09-05 21:16:21 +08:00
parent 4ae72d107c
commit 53155db139
5 changed files with 1555 additions and 777 deletions

44
App.vue
View File

@ -1,13 +1,57 @@
<script> <script>
import WechatAuth from '@/utils/wechat-auth.js'
import { getUserInfo } from '@/http/api/profile.js'
export default { export default {
onLaunch: function() { onLaunch: function() {
console.log('App Launch') console.log('App Launch')
this.initApp()
}, },
onShow: function() { onShow: function() {
console.log('App Show') console.log('App Show')
}, },
onHide: function() { onHide: function() {
console.log('App Hide') console.log('App Hide')
},
methods: {
//
async initApp() {
try {
await this.checkLoginStatus()
} catch (error) {
//
}
},
//
async checkLoginStatus() {
const token = WechatAuth.getToken()
if (!token) {
return
}
try {
// token
const userInfo = await getUserInfo({
custom: {
loading: false,
toast: false
}
})
//
if (userInfo) {
WechatAuth.saveLoginInfo(token, WechatAuth.getRefreshToken(), userInfo)
}
} catch (error) {
// token
if (error.code === 401 || error.statusCode === 401) {
WechatAuth.clearLoginInfo()
}
}
}
} }
} }
</script> </script>

View File

@ -71,13 +71,23 @@ export const userLogin = (loginData, config = {}) => {
} }
/** /**
* 微信登录 * 微信小程序登录
* @param {Object} wxData 微信登录数据 * @param {Object} wxData 微信登录数据
* @param {string} wxData.code 微信授权码必需
* @param {string} wxData.encryptedData 加密数据可选用户授权后获取
* @param {string} wxData.iv 初始向量可选用户授权后获取
* @param {string} wxData.signature 签名可选用户授权后获取
* @param {Object} wxData.userInfo 用户信息可选用户授权后获取
* @param {Object} config 自定义配置 * @param {Object} config 自定义配置
* @returns {Promise} * @returns {Promise} 返回包含token和用户信息的Promise
*/ */
export const wxLogin = (wxData, config = {}) => { export const wxLogin = (wxData, config = {}) => {
return uni.$u.http.post('/auth/wx-login', wxData, { // 验证必需参数
if (!wxData || !wxData.code) {
return Promise.reject(new Error('微信授权码(code)是必需的'))
}
return uni.$u.http.post('/wechat/user/mini/login', wxData, {
custom: { custom: {
auth: false, auth: false,
loading: true, loading: true,
@ -210,12 +220,16 @@ export const updateUserSettings = (settings, config = {}) => {
/** /**
* 绑定手机号 * 绑定手机号
* @param {Object} phoneData 手机号数据 * @param {Object} phoneData 手机号数据
* @param {string} phoneData.encryptedData 加密数据
* @param {string} phoneData.iv 初始向量
* @param {string} phoneData.cloudID 云函数ID可选
* @param {Object} config 自定义配置 * @param {Object} config 自定义配置
* @returns {Promise} * @returns {Promise}
*/ */
export const bindPhone = (phoneData, config = {}) => { export const bindPhone = (phoneData, config = {}) => {
return uni.$u.http.post('/user/bind-phone', phoneData, { return uni.$u.http.post('/user/bind-phone', phoneData, {
custom: { custom: {
auth: true,
loading: true, loading: true,
loadingText: '正在绑定手机号...', loadingText: '正在绑定手机号...',
...config.custom ...config.custom
@ -224,6 +238,32 @@ export const bindPhone = (phoneData, config = {}) => {
}) })
} }
/**
* 微信小程序登录并绑定手机号
* @param {Object} loginData 登录和手机号数据
* @param {string} loginData.code 微信授权码
* @param {string} loginData.phoneEncryptedData 手机号加密数据可选
* @param {string} loginData.phoneIv 手机号初始向量可选
* @param {string} loginData.phoneCloudID 手机号云函数ID可选
* @param {Object} config 自定义配置
* @returns {Promise}
*/
export const wxLoginWithPhone = (loginData, config = {}) => {
if (!loginData || !loginData.code) {
return Promise.reject(new Error('微信授权码(code)是必需的'))
}
return uni.$u.http.post('/auth/wx-login-phone', loginData, {
custom: {
auth: false,
loading: true,
loadingText: '正在登录...',
...config.custom
},
...config
})
}
/** /**
* 获取用户权限 * 获取用户权限
* @param {Object} config 自定义配置 * @param {Object} config 自定义配置

View File

@ -6,7 +6,7 @@
const ENV_CONFIG = { const ENV_CONFIG = {
// 开发环境 // 开发环境
development: { development: {
baseURL: 'https://dev-api.pet-ai.com', baseURL: 'http://127.0.0.1:8080',
timeout: 30000 timeout: 30000
}, },
// 测试环境 // 测试环境
@ -33,8 +33,8 @@ export const HTTP_CONFIG = {
// 当前环境配置 // 当前环境配置
...ENV_CONFIG[CURRENT_ENV], ...ENV_CONFIG[CURRENT_ENV],
// 登录页面路径 // 登录页面路径(个人中心页面,点击头像登录)
loginPage: '/pages/login/login', loginPage: '/pages/profile/profile',
// 存储键名配置 // 存储键名配置
storageKeys: { storageKeys: {
@ -59,7 +59,7 @@ export const NO_AUTH_APIS = [
// 用户认证相关 // 用户认证相关
'/auth/login', '/auth/login',
'/auth/register', '/auth/register',
'/auth/wx-login', '/wechat/user/mini/login',
'/auth/refresh', '/auth/refresh',
// 公开浏览的接口 // 公开浏览的接口

View File

@ -1,7 +1,7 @@
<template> <template>
<view class="profile-container page-container-with-bg"> <view class="profile-container page-container-with-bg">
<!-- 用户信息卡片 --> <!-- 用户信息卡片 -->
<view class="user-info-card"> <view class="user-info-card" @click="handleWxLogin">
<view class="user-avatar-section"> <view class="user-avatar-section">
<view class="avatar-wrapper"> <view class="avatar-wrapper">
<u-avatar <u-avatar
@ -23,8 +23,19 @@
<view class="user-status">{{ userInfo.nickName ? '已登录' : '未登录' }}</view> <view class="user-status">{{ userInfo.nickName ? '已登录' : '未登录' }}</view>
<view class="login-days" v-if="userInfo.nickName">已使用 {{ loginDays }} </view> <view class="login-days" v-if="userInfo.nickName">已使用 {{ loginDays }} </view>
</view> </view>
<view class="user-action" @click="handleUserAction"> <view class="user-action">
<text class="action-icon">{{ userInfo.nickName ? '⚙️' : '👋' }}</text> <!-- 登录按钮 -->
<button
v-if="!userInfo.nickName"
class="login-btn"
>
<text class="action-icon">👋</text>
</button>
<!-- 已登录状态 -->
<view v-else @click="handleUserAction" class="logged-in-action">
<text class="action-icon"></text>
</view>
</view> </view>
</view> </view>
@ -149,11 +160,37 @@
</view> </view>
</view> </view>
</view> </view>
<!-- 手机号授权按钮 -->
<view v-if="showPhoneAuthBtn" class="phone-auth-modal">
<view class="auth-overlay" @click="cancelPhoneAuth"></view>
<view class="auth-content">
<view class="auth-title">手机号授权</view>
<view class="auth-desc">为了更好的服务体验需要获取您的手机号</view>
<view class="auth-buttons">
<button
class="auth-btn primary"
open-type="getPhoneNumber"
@getphonenumber="handlePhoneAuth"
>
授权手机号
</button>
<button
class="auth-btn secondary"
@click="cancelPhoneAuth"
>
跳过
</button>
</view>
</view>
</view>
</view> </view>
</template> </template>
<script> <script>
import { reactive, ref, onMounted, computed } from 'vue' import {reactive, ref, onMounted, computed} from 'vue'
import WechatAuth from '@/utils/wechat-auth.js'
import {wxLogin, wxLoginWithPhone, bindPhone} from '@/http/api/profile.js'
export default { export default {
name: 'ProfilePage', name: 'ProfilePage',
@ -166,6 +203,8 @@ export default {
const loginDays = ref(0) const loginDays = ref(0)
const notificationCount = ref(3) const notificationCount = ref(3)
const showPhoneAuthBtn = ref(false)
const currentLoginCode = ref('')
// //
const petStats = reactive({ const petStats = reactive({
@ -193,12 +232,14 @@ export default {
const checkLogin = () => { const checkLogin = () => {
// //
const savedUserInfo = uni.getStorageSync('userInfo') if (WechatAuth.isLoggedIn()) {
const savedUserInfo = WechatAuth.getUserInfoFromStorage()
if (savedUserInfo) { if (savedUserInfo) {
userInfo.value = savedUserInfo userInfo.value = savedUserInfo
calculateLoginDays() calculateLoginDays()
} }
} }
}
const calculateLoginDays = () => { const calculateLoginDays = () => {
const loginDate = uni.getStorageSync('loginDate') const loginDate = uni.getStorageSync('loginDate')
@ -234,7 +275,7 @@ export default {
petStats.reminderCount = pendingReminders.length petStats.reminderCount = pendingReminders.length
// //
const familyData = uni.getStorageSync('familyData') || { members: [] } const familyData = uni.getStorageSync('familyData') || {members: []}
familyStats.memberCount = familyData.members.length || 1 familyStats.memberCount = familyData.members.length || 1
// //
@ -266,38 +307,306 @@ export default {
if (userInfo.value.nickName) { if (userInfo.value.nickName) {
// //
navigateTo('/pages/profile/user-info') navigateTo('/pages/profile/user-info')
} else {
//
wxLogin()
} }
} }
const wxLogin = () => { const handleWxLogin = () => {
uni.login({
provider: 'weixin', wx.login({
success: (res) => { success: (loginRes) => {
console.log('登录成功', res) if (loginRes.code) {
// console.log(loginRes)
userInfo.value = { // 3.
nickName: '宠物主人', handleWxLoginSuccess(loginRes.code, userInfo.value)
avatarUrl: '' } else {
handleLoginError(new Error('获取微信授权码失败'))
} }
uni.setStorageSync('userInfo', userInfo.value) },
fail: (error) => {
handleLoginError(new Error('微信登录失败: ' + (error.errMsg || '未知错误')))
}
})
//
// performWxLogin()
}
const handleUserInfo = (e) => {
//
console.log('用户信息授权结果:', e.detail)
}
const performWxLogin = async () => {
try {
console.log(999)
// 1.
wx.getUserProfile({
desc: "获取用户头像昵称",
success: (res) => {
//
userInfo.value = {
...res.userInfo,
avatarUrl: res.userInfo.avatarUrl || '',
nickName: res.userInfo.nickName || "未命名用户",
}
console.log("111")
// 2.
wx.login({
success: (loginRes) => {
if (loginRes.code) {
// 3.
handleWxLoginSuccess(loginRes.code, userInfo.value)
} else {
handleLoginError(new Error('获取微信授权码失败'))
}
},
fail: (error) => {
handleLoginError(new Error('微信登录失败: ' + (error.errMsg || '未知错误')))
}
})
},
fail: (error) => {
console.log(error)
handleLoginError(new Error('获取用户信息失败: ' + (error.errMsg || '未知错误')))
}
})
} catch (error) {
console.log(error)
handleLoginError(error)
}
}
const handleWxLoginSuccess = async (code, wxUserInfo) => {
try {
uni.showLoading({
title: '正在登录...',
mask: true
})
//
const response = await wxLogin({
code: code,
userInfo: wxUserInfo
})
//
handleLoginSuccess(response)
} catch (error) {
handleLoginError(error)
}
}
const showPhoneAuthModal = (code) => {
//
currentLoginCode.value = code
//
showPhoneAuthBtn.value = true
//
uni.showToast({
title: '请点击授权按钮',
icon: 'none',
duration: 2000
})
}
const doBasicLogin = async (code) => {
try {
uni.showLoading({
title: '正在登录...',
mask: true
})
//
const response = await wxLogin({code})
//
handleLoginSuccess(response)
} catch (error) {
handleLoginError(error)
}
}
const doWxLoginWithPhone = async () => {
try {
uni.showLoading({
title: '正在登录...',
mask: true
})
// 1.
const code = await WechatAuth.getWxCode()
// 2.
uni.hideLoading()
uni.showModal({
title: '手机号授权',
content: '为了更好的服务体验,需要获取您的手机号',
confirmText: '授权',
cancelText: '跳过',
success: (res) => {
if (res.confirm) {
//
showPhoneAuthPage(code)
} else {
// 使
doWxLoginOnly(code)
}
}
})
} catch (error) {
handleLoginError(error)
}
}
const showPhoneAuthPage = (code) => {
//
uni.navigateTo({
url: `/pages/profile/phone-auth?code=${code}`,
fail: () => {
// 使
doWxLoginOnly(code)
}
})
}
const doWxLoginOnly = async (code) => {
try {
uni.showLoading({
title: '正在登录...',
mask: true
})
const response = await wxLogin({code})
handleLoginSuccess(response)
} catch (error) {
handleLoginError(error)
}
}
const handleLoginSuccess = (response) => {
if (response && response.token) {
WechatAuth.saveLoginInfo(
response.token,
response.refreshToken,
response.userInfo || userInfo.value
)
// 使使
if (response.userInfo) {
userInfo.value = response.userInfo
}
//
uni.setStorageSync('loginDate', new Date().toISOString()) uni.setStorageSync('loginDate', new Date().toISOString())
calculateLoginDays() calculateLoginDays()
//
loadUserStats()
uni.hideLoading()
//
uni.showModal({
title: '完善信息',
content: '是否授权获取手机号,以便为您提供更好的服务?',
confirmText: '授权',
cancelText: '跳过',
success: (res) => {
if (res.confirm) {
//
showPhoneAuthBtn.value = true
} else {
//
uni.showToast({ uni.showToast({
title: '登录成功', title: '登录成功',
icon: 'success' icon: 'success'
}) })
}, }
fail: (err) => { }
console.error('登录失败', err) })
} else {
throw new Error('登录响应数据异常')
}
}
const handlePhoneAuth = async (e) => {
//
showPhoneAuthBtn.value = false
try {
uni.showLoading({
title: '正在绑定手机号...',
mask: true
})
//
const phoneResult = WechatAuth.getPhoneNumber(e)
if (phoneResult.success) {
//
const response = await bindPhone({
encryptedData: phoneResult.encryptedData,
iv: phoneResult.iv,
cloudID: phoneResult.cloudID
})
uni.hideLoading()
uni.showToast({ uni.showToast({
title: '登录失败', title: '手机号绑定成功',
icon: 'success'
})
} else {
//
uni.hideLoading()
uni.showToast({
title: '手机号授权失败',
icon: 'none' icon: 'none'
}) })
} }
} catch (error) {
uni.hideLoading()
uni.showToast({
title: '绑定失败',
icon: 'none'
})
}
}
const cancelPhoneAuth = () => {
//
showPhoneAuthBtn.value = false
// 使
doBasicLogin(currentLoginCode.value)
}
const handleLoginError = (error) => {
uni.hideLoading()
let errorMessage = '登录失败'
if (error.message.includes('用户拒绝授权')) {
errorMessage = '需要授权才能使用完整功能'
} else if (error.message.includes('网络')) {
errorMessage = '网络连接失败,请检查网络'
} else if (error.message.includes('code')) {
errorMessage = '微信授权失败,请重试'
}
uni.showModal({
title: '登录提示',
content: errorMessage,
showCancel: false,
confirmText: '确定'
}) })
} }
@ -395,7 +704,7 @@ export default {
// //
onMounted(() => { onMounted(() => {
initPage() initPage()
checkNewFeatures() // checkNewFeatures()
}) })
return { return {
@ -405,7 +714,12 @@ export default {
petStats, petStats,
familyStats, familyStats,
adoptionStats, adoptionStats,
showPhoneAuthBtn,
handleUserAction, handleUserAction,
handleWxLogin,
handleUserInfo,
handlePhoneAuth,
cancelPhoneAuth,
navigateTo, navigateTo,
navigateToFamily, navigateToFamily,
inviteFamily, inviteFamily,
@ -914,9 +1228,118 @@ export default {
animation: fadeIn 0.5s ease-out; animation: fadeIn 0.5s ease-out;
} }
.profile-container > view:nth-child(1) { animation-delay: 0.1s; } .profile-container > view:nth-child(1) {
.profile-container > view:nth-child(2) { animation-delay: 0.2s; } animation-delay: 0.1s;
.profile-container > view:nth-child(3) { animation-delay: 0.3s; } }
.profile-container > view:nth-child(4) { animation-delay: 0.4s; }
.profile-container > view:nth-child(5) { animation-delay: 0.5s; } .profile-container > view:nth-child(2) {
animation-delay: 0.2s;
}
.profile-container > view:nth-child(3) {
animation-delay: 0.3s;
}
.profile-container > view:nth-child(4) {
animation-delay: 0.4s;
}
.profile-container > view:nth-child(5) {
animation-delay: 0.5s;
}
/* 手机号授权模态框 */
.phone-auth-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
.auth-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
}
.auth-content {
position: relative;
background: white;
margin: 0 60rpx;
border-radius: 24rpx;
padding: 60rpx 40rpx;
text-align: center;
box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.3);
.auth-title {
font-size: 36rpx;
font-weight: 600;
color: #333;
margin-bottom: 20rpx;
}
.auth-desc {
font-size: 28rpx;
color: #666;
line-height: 1.5;
margin-bottom: 60rpx;
}
.auth-buttons {
display: flex;
flex-direction: column;
gap: 20rpx;
.auth-btn {
height: 88rpx;
border-radius: 44rpx;
font-size: 32rpx;
font-weight: 600;
border: none;
&.primary {
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
color: white;
}
&.secondary {
background: #f5f5f5;
color: #666;
}
}
}
}
}
/* 登录按钮样式 */
.login-btn {
background: transparent;
border: none;
padding: 0;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
.action-icon {
font-size: 32rpx;
}
}
.logged-in-action {
display: flex;
align-items: center;
justify-content: center;
.action-icon {
font-size: 32rpx;
}
}
</style> </style>

271
utils/wechat-auth.js Normal file
View File

@ -0,0 +1,271 @@
// 微信小程序认证工具类
// 封装微信小程序登录的核心逻辑
import { HTTP_CONFIG } from '@/http/config/config.js'
/**
* 微信小程序认证工具类
*/
export class WechatAuth {
/**
* 微信登录获取code
* @returns {Promise<string>} 微信授权码
*/
static async getWxCode() {
return new Promise((resolve, reject) => {
wx.login({
success: (res) => {
console.log(res)
if (res.code) {
resolve(res.code)
} else {
reject(new Error('获取微信授权码失败'))
}
},
fail: (error) => {
reject(new Error('微信登录失败: ' + (error.errMsg || '未知错误')))
}
})
})
}
/**
* 获取用户信息需要用户授权
* @param {string} desc 申请理由
* @returns {Promise<Object>} 用户信息
*/
static async getUserProfile(desc = '获取用户头像昵称') {
return new Promise((resolve, reject) => {
// #ifdef MP-WEIXIN
wx.getUserProfile({
desc: desc,
success: (res) => {
resolve(res)
},
fail: (error) => {
if (error.errMsg && error.errMsg.includes('auth deny')) {
reject(new Error('用户拒绝授权'))
} else {
reject(new Error('获取用户信息失败: ' + (error.errMsg || '未知错误')))
}
}
})
// #endif
// #ifndef MP-WEIXIN
reject(new Error('当前环境不支持微信授权'))
// #endif
})
}
/**
* 获取用户基本信息无需授权但信息有限
* @returns {Promise<Object>} 用户基本信息
*/
static async getUserInfo() {
return new Promise((resolve, reject) => {
uni.getUserInfo({
success: (res) => {
resolve(res)
},
fail: (error) => {
reject(new Error('获取用户基本信息失败: ' + (error.errMsg || '未知错误')))
}
})
})
}
/**
* 获取用户手机号需要用户授权
* 注意这个方法需要在button组件的open-type="getPhoneNumber"的回调中使用
* @param {Object} e 手机号授权回调事件对象
* @returns {Object} 手机号相关数据
*/
static getPhoneNumber(e) {
if (e.detail.errMsg === 'getPhoneNumber:ok') {
return {
success: true,
encryptedData: e.detail.encryptedData,
iv: e.detail.iv,
cloudID: e.detail.cloudID
}
} else {
return {
success: false,
error: e.detail.errMsg || '获取手机号失败'
}
}
}
/**
* 生成随机头像
* @returns {string} 随机头像URL
*/
static generateRandomAvatar() {
const avatars = [
'https://img.yzcdn.cn/vant/cat.jpeg',
'https://img.yzcdn.cn/vant/dog.jpeg',
'https://img.yzcdn.cn/vant/rabbit.jpeg',
'https://img.yzcdn.cn/vant/bird.jpeg'
]
return avatars[Math.floor(Math.random() * avatars.length)]
}
/**
* 保存登录信息到本地存储
* @param {string} token 访问令牌
* @param {string} refreshToken 刷新令牌可选
* @param {Object} userInfo 用户信息
*/
static saveLoginInfo(token, refreshToken = null, userInfo = null) {
try {
// 使用配置中定义的存储键名
uni.setStorageSync(HTTP_CONFIG.storageKeys.token, token)
if (refreshToken) {
uni.setStorageSync(HTTP_CONFIG.storageKeys.refreshToken, refreshToken)
}
if (userInfo) {
uni.setStorageSync(HTTP_CONFIG.storageKeys.userInfo, userInfo)
}
console.log('登录信息保存成功')
} catch (error) {
console.error('保存登录信息失败:', error)
throw new Error('保存登录信息失败')
}
}
/**
* 获取本地存储的token
* @returns {string|null} 访问令牌
*/
static getToken() {
try {
return uni.getStorageSync(HTTP_CONFIG.storageKeys.token) || null
} catch (error) {
console.error('获取token失败:', error)
return null
}
}
/**
* 获取本地存储的刷新令牌
* @returns {string|null} 刷新令牌
*/
static getRefreshToken() {
try {
return uni.getStorageSync(HTTP_CONFIG.storageKeys.refreshToken) || null
} catch (error) {
console.error('获取refreshToken失败:', error)
return null
}
}
/**
* 获取本地存储的用户信息
* @returns {Object|null} 用户信息
*/
static getUserInfoFromStorage() {
try {
const userInfo = uni.getStorageSync(HTTP_CONFIG.storageKeys.userInfo)
return userInfo ? (typeof userInfo === 'string' ? JSON.parse(userInfo) : userInfo) : null
} catch (error) {
console.error('获取用户信息失败:', error)
return null
}
}
/**
* 检查是否已登录
* @returns {boolean} 是否已登录
*/
static isLoggedIn() {
const token = this.getToken()
return !!token
}
/**
* 清除所有登录信息
*/
static clearLoginInfo() {
try {
uni.removeStorageSync(HTTP_CONFIG.storageKeys.token)
uni.removeStorageSync(HTTP_CONFIG.storageKeys.refreshToken)
uni.removeStorageSync(HTTP_CONFIG.storageKeys.userInfo)
console.log('登录信息清除成功')
} catch (error) {
console.error('清除登录信息失败:', error)
}
}
/**
* 跳转到登录页面
*/
static navigateToLogin() {
uni.reLaunch({
url: HTTP_CONFIG.loginPage
})
}
/**
* 检查登录状态并处理
* @returns {boolean} 是否已登录
*/
static checkLoginStatus() {
if (!this.isLoggedIn()) {
console.log('用户未登录,跳转到登录页')
this.navigateToLogin()
return false
}
return true
}
/**
* 完整的微信小程序登录流程
* @param {boolean} needUserInfo 是否需要获取用户详细信息
* @returns {Promise<Object>} 登录结果
*/
static async performWxLogin(needUserInfo = true) {
try {
// 1. 获取微信授权码
const code = await this.getWxCode()
// 2. 准备登录数据
const loginData = { code }
// 3. 如果需要用户信息,尝试获取
if (needUserInfo) {
try {
const userProfile = await this.getUserProfile()
loginData.encryptedData = userProfile.encryptedData
loginData.iv = userProfile.iv
loginData.signature = userProfile.signature
loginData.userInfo = userProfile.userInfo
} catch (userInfoError) {
console.warn('获取用户详细信息失败,使用基本登录:', userInfoError.message)
// 继续使用基本登录,不中断流程
}
}
return {
success: true,
data: loginData,
message: '微信授权成功'
}
} catch (error) {
console.error('微信登录流程失败:', error)
return {
success: false,
error: error.message,
message: '微信登录失败'
}
}
}
}
/**
* 默认导出便于直接导入使用
*/
export default WechatAuth