344 lines
9.9 KiB
JavaScript
344 lines
9.9 KiB
JavaScript
|
|
const { config } = require('../../config/index');
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 微信登录服务
|
|||
|
|
*/
|
|||
|
|
class WeChatAuthService {
|
|||
|
|
constructor() {
|
|||
|
|
this.apiBase = config.apiBase;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 微信授权登录
|
|||
|
|
* @param {Object} options - 登录选项
|
|||
|
|
* @param {boolean} options.withUserInfo - 是否获取用户信息
|
|||
|
|
* @returns {Promise} 登录结果
|
|||
|
|
*/
|
|||
|
|
async login(options = {}) {
|
|||
|
|
const { withUserInfo = false } = options;
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 1. 获取微信登录code
|
|||
|
|
const loginResult = await this.getWeChatLoginCode();
|
|||
|
|
|
|||
|
|
if (withUserInfo) {
|
|||
|
|
// 2. 如果需要用户信息,先获取用户信息
|
|||
|
|
const userInfo = await this.getUserInfo();
|
|||
|
|
return await this.loginWithUserInfo(loginResult.code, userInfo);
|
|||
|
|
} else {
|
|||
|
|
// 3. 仅使用code登录
|
|||
|
|
return await this.loginWithCode(loginResult.code);
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('微信登录失败:', error);
|
|||
|
|
throw error;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 微信授权登录
|
|||
|
|
* @returns {Promise} 登录结果
|
|||
|
|
*/
|
|||
|
|
async authorizeLogin(userInfo = null) {
|
|||
|
|
try {
|
|||
|
|
console.log('开始微信授权登录...');
|
|||
|
|
|
|||
|
|
// 1. 获取微信登录code
|
|||
|
|
const loginResult = await this.getWeChatLoginCode();
|
|||
|
|
console.log('获取微信登录code成功:', loginResult.code);
|
|||
|
|
|
|||
|
|
// 2. 使用一次性 code 完成登录(避免重复获取)
|
|||
|
|
let loginData;
|
|||
|
|
if (userInfo) {
|
|||
|
|
console.log('使用code+用户信息登录');
|
|||
|
|
loginData = await this.loginWithUserInfo(loginResult.code, userInfo);
|
|||
|
|
} else {
|
|||
|
|
console.log('使用code登录');
|
|||
|
|
loginData = await this.loginWithCode(loginResult.code);
|
|||
|
|
}
|
|||
|
|
console.log('登录成功:', loginData);
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
success: true,
|
|||
|
|
data: {
|
|||
|
|
...loginData,
|
|||
|
|
userInfo: userInfo || null
|
|||
|
|
},
|
|||
|
|
message: '授权登录成功'
|
|||
|
|
};
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('微信授权登录失败:', error);
|
|||
|
|
return {
|
|||
|
|
success: false,
|
|||
|
|
message: error.message || '授权登录失败'
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 更新用户资料
|
|||
|
|
* @param {Object} userInfo - 用户信息对象
|
|||
|
|
* @returns {Promise} 更新结果
|
|||
|
|
*/
|
|||
|
|
async updateUserProfile(userInfo) {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
console.log('开始更新用户资料...');
|
|||
|
|
console.log('用户信息:', userInfo);
|
|||
|
|
console.log('API地址:', `${this.apiBase}/users/profile`);
|
|||
|
|
console.log('Token:', wx.getStorageSync('token'));
|
|||
|
|
|
|||
|
|
wx.request({
|
|||
|
|
url: `${this.apiBase}/users/profile`,
|
|||
|
|
method: 'PUT',
|
|||
|
|
header: {
|
|||
|
|
'Authorization': `Bearer ${wx.getStorageSync('token')}`,
|
|||
|
|
'Content-Type': 'application/json'
|
|||
|
|
},
|
|||
|
|
data: {
|
|||
|
|
nickname: userInfo.nickName || userInfo.nickname,
|
|||
|
|
avatar: userInfo.avatarUrl || userInfo.avatar,
|
|||
|
|
gender: userInfo.gender || 0,
|
|||
|
|
phone: userInfo.phoneNumber || userInfo.phone,
|
|||
|
|
email: userInfo.email
|
|||
|
|
},
|
|||
|
|
success: (res) => {
|
|||
|
|
if (res.statusCode === 200 && res.data.code === 200) {
|
|||
|
|
console.log('用户资料更新成功:', res.data);
|
|||
|
|
resolve(res.data.data);
|
|||
|
|
} else {
|
|||
|
|
reject(new Error(res.data.message || '更新用户资料失败'));
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
fail: (error) => {
|
|||
|
|
console.error('更新用户资料失败:', error);
|
|||
|
|
reject(new Error(`网络请求失败: ${error.errMsg}`));
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取微信登录code(临时登录凭证)
|
|||
|
|
* 按照微信官方文档标准实现
|
|||
|
|
* @returns {Promise} 登录结果
|
|||
|
|
*/
|
|||
|
|
getWeChatLoginCode() {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
wx.login({
|
|||
|
|
success: (res) => {
|
|||
|
|
if (res.code) {
|
|||
|
|
console.log('获取微信登录code成功:', res.code);
|
|||
|
|
// 验证code格式(微信code通常是32位字符串)
|
|||
|
|
if (res.code.length < 10) {
|
|||
|
|
reject(new Error('获取的登录凭证格式异常'));
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
resolve(res);
|
|||
|
|
} else {
|
|||
|
|
console.error('wx.login成功但未返回code');
|
|||
|
|
reject(new Error('获取微信登录凭证失败'));
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
fail: (error) => {
|
|||
|
|
console.error('wx.login调用失败:', error);
|
|||
|
|
reject(new Error(`微信登录失败: ${error.errMsg || '未知错误'}`));
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取用户信息(新版本兼容方式)
|
|||
|
|
* 由于getUserProfile已废弃,现在使用头像昵称填写组件或直接跳过用户信息获取
|
|||
|
|
* @returns {Promise} 用户信息
|
|||
|
|
*/
|
|||
|
|
getUserInfo() {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
// 由于getUserProfile已废弃,我们提供一个默认的用户信息结构
|
|||
|
|
// 实际的头像和昵称应该通过头像昵称填写组件获取
|
|||
|
|
console.log('注意:getUserProfile API已废弃,建议使用头像昵称填写组件');
|
|||
|
|
|
|||
|
|
// 返回一个基础的用户信息结构
|
|||
|
|
const defaultUserInfo = {
|
|||
|
|
nickName: '微信用户',
|
|||
|
|
avatarUrl: '', // 空头像,后续可通过头像组件更新
|
|||
|
|
gender: 0,
|
|||
|
|
country: '',
|
|||
|
|
province: '',
|
|||
|
|
city: ''
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
console.log('使用默认用户信息:', defaultUserInfo);
|
|||
|
|
resolve(defaultUserInfo);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 通过头像昵称组件获取用户信息
|
|||
|
|
* @param {Object} userInfo - 从头像昵称组件获取的用户信息
|
|||
|
|
* @returns {Promise} 处理后的用户信息
|
|||
|
|
*/
|
|||
|
|
getUserInfoFromComponent(userInfo) {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
try {
|
|||
|
|
// 验证用户信息
|
|||
|
|
if (!userInfo) {
|
|||
|
|
reject(new Error('用户信息不能为空'));
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建标准的用户信息格式
|
|||
|
|
const standardUserInfo = {
|
|||
|
|
nickName: userInfo.nickName || '微信用户',
|
|||
|
|
avatarUrl: userInfo.avatarUrl || '',
|
|||
|
|
gender: userInfo.gender || 0,
|
|||
|
|
country: userInfo.country || '',
|
|||
|
|
province: userInfo.province || '',
|
|||
|
|
city: userInfo.city || ''
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
console.log('从组件获取用户信息成功:', standardUserInfo);
|
|||
|
|
resolve(standardUserInfo);
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('处理用户信息失败:', error);
|
|||
|
|
reject(new Error('处理用户信息失败'));
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 使用code登录
|
|||
|
|
* @param {string} code - 微信登录code
|
|||
|
|
* @returns {Promise} 登录结果
|
|||
|
|
*/
|
|||
|
|
loginWithCode(code) {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
wx.request({
|
|||
|
|
url: `${this.apiBase}/users/wechat-login`,
|
|||
|
|
method: 'POST',
|
|||
|
|
data: {
|
|||
|
|
code: code
|
|||
|
|
},
|
|||
|
|
header: {
|
|||
|
|
'Content-Type': 'application/json'
|
|||
|
|
},
|
|||
|
|
success: (res) => {
|
|||
|
|
if (res.statusCode === 200 && res.data.code === 200) {
|
|||
|
|
const result = res.data.data;
|
|||
|
|
// 保存token到本地存储
|
|||
|
|
if (result.token) {
|
|||
|
|
wx.setStorageSync('token', result.token);
|
|||
|
|
wx.setStorageSync('jwt_token', result.token);
|
|||
|
|
}
|
|||
|
|
resolve(result);
|
|||
|
|
} else {
|
|||
|
|
reject(new Error(res.data.message || '登录失败'));
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
fail: (error) => {
|
|||
|
|
reject(new Error(`网络请求失败: ${error.errMsg}`));
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 使用code和用户信息登录
|
|||
|
|
* @param {string} code - 微信登录code
|
|||
|
|
* @param {Object} userInfo - 用户信息
|
|||
|
|
* @returns {Promise} 登录结果
|
|||
|
|
*/
|
|||
|
|
loginWithUserInfo(code, userInfo) {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
wx.request({
|
|||
|
|
url: `${this.apiBase}/users/wechat-login`,
|
|||
|
|
method: 'POST',
|
|||
|
|
data: {
|
|||
|
|
code: code,
|
|||
|
|
userInfo: {
|
|||
|
|
nickName: userInfo.nickName,
|
|||
|
|
avatarUrl: userInfo.avatarUrl,
|
|||
|
|
gender: userInfo.gender,
|
|||
|
|
country: userInfo.country,
|
|||
|
|
province: userInfo.province,
|
|||
|
|
city: userInfo.city
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
header: {
|
|||
|
|
'Content-Type': 'application/json'
|
|||
|
|
},
|
|||
|
|
success: (res) => {
|
|||
|
|
if (res.statusCode === 200 && res.data.code === 200) {
|
|||
|
|
const result = res.data.data;
|
|||
|
|
// 保存token到本地存储
|
|||
|
|
if (result.token) {
|
|||
|
|
wx.setStorageSync('token', result.token);
|
|||
|
|
wx.setStorageSync('jwt_token', result.token);
|
|||
|
|
}
|
|||
|
|
resolve(result);
|
|||
|
|
} else {
|
|||
|
|
reject(new Error(res.data.message || '登录失败'));
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
fail: (error) => {
|
|||
|
|
reject(new Error(`网络请求失败: ${error.errMsg}`));
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取微信会话信息
|
|||
|
|
* @returns {Promise} 会话信息
|
|||
|
|
*/
|
|||
|
|
getWeChatSession() {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
const token = wx.getStorageSync('token');
|
|||
|
|
if (!token) {
|
|||
|
|
reject(new Error('未找到登录token'));
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
wx.request({
|
|||
|
|
url: `${this.apiBase}/users/wechat-session`,
|
|||
|
|
method: 'GET',
|
|||
|
|
header: {
|
|||
|
|
'Authorization': `Bearer ${token}`,
|
|||
|
|
'Content-Type': 'application/json'
|
|||
|
|
},
|
|||
|
|
success: (res) => {
|
|||
|
|
if (res.statusCode === 200 && res.data.code === 200) {
|
|||
|
|
resolve(res.data.data);
|
|||
|
|
} else {
|
|||
|
|
reject(new Error(res.data.message || '获取会话信息失败'));
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
fail: (error) => {
|
|||
|
|
reject(new Error(`网络请求失败: ${error.errMsg}`));
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 检查登录状态
|
|||
|
|
* @returns {boolean} 是否已登录
|
|||
|
|
*/
|
|||
|
|
isLoggedIn() {
|
|||
|
|
const token = wx.getStorageSync('token');
|
|||
|
|
return !!token;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 退出登录
|
|||
|
|
*/
|
|||
|
|
logout() {
|
|||
|
|
wx.removeStorageSync('token');
|
|||
|
|
wx.removeStorageSync('jwt_token');
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 创建单例实例
|
|||
|
|
const weChatAuthService = new WeChatAuthService();
|
|||
|
|
|
|||
|
|
module.exports = weChatAuthService;
|