You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
275 lines
6.6 KiB
275 lines
6.6 KiB
import request from '@/utils/request';
|
|
import type { ApiResult } from '@/api';
|
|
import Taro from '@tarojs/taro';
|
|
import {SERVER_API_URL} from "@/utils/server";
|
|
import {getUserInfo} from "@/api/layout";
|
|
|
|
/**
|
|
* 扫码登录相关接口
|
|
*/
|
|
|
|
// 生成扫码token请求参数
|
|
export interface GenerateQRTokenParam {
|
|
// 客户端类型:web, app, wechat
|
|
clientType?: string;
|
|
// 设备信息
|
|
deviceInfo?: string;
|
|
// 过期时间(分钟)
|
|
expireMinutes?: number;
|
|
}
|
|
|
|
// 生成扫码token响应
|
|
export interface GenerateQRTokenResult {
|
|
// 扫码token
|
|
token: string;
|
|
// 二维码内容(通常是包含token的URL或JSON)
|
|
qrContent: string;
|
|
// 过期时间戳
|
|
expireTime: number;
|
|
// 二维码图片URL(可选)
|
|
qrImageUrl?: string;
|
|
}
|
|
|
|
// 扫码状态枚举
|
|
export enum QRLoginStatus {
|
|
PENDING = 'pending', // 等待扫码
|
|
SCANNED = 'scanned', // 已扫码,等待确认
|
|
CONFIRMED = 'confirmed', // 已确认登录
|
|
EXPIRED = 'expired', // 已过期
|
|
CANCELLED = 'cancelled' // 已取消
|
|
}
|
|
|
|
// 检查扫码状态响应
|
|
export interface QRLoginStatusResult {
|
|
// 当前状态
|
|
status: QRLoginStatus;
|
|
// 状态描述
|
|
message?: string;
|
|
// 如果已确认登录,返回JWT token
|
|
accessToken?: string;
|
|
// 用户信息
|
|
userInfo?: {
|
|
userId: number;
|
|
nickname?: string;
|
|
avatar?: string;
|
|
phone?: string;
|
|
};
|
|
// 剩余有效时间(秒)
|
|
remainingTime?: number;
|
|
}
|
|
|
|
// 确认登录请求参数
|
|
export interface ConfirmLoginParam {
|
|
// 扫码token
|
|
token: string;
|
|
// 用户ID
|
|
userId: number;
|
|
// 登录平台:web, app, wechat
|
|
platform?: string;
|
|
// 微信用户信息(当platform为wechat时)
|
|
wechatInfo?: {
|
|
openid?: string;
|
|
unionid?: string;
|
|
nickname?: string;
|
|
avatar?: string;
|
|
gender?: string;
|
|
};
|
|
// 设备信息
|
|
deviceInfo?: string;
|
|
}
|
|
|
|
// 确认登录响应
|
|
export interface ConfirmLoginResult {
|
|
// 是否成功
|
|
success: boolean;
|
|
// 消息
|
|
message: string;
|
|
// 登录用户信息
|
|
userInfo?: {
|
|
userId: number;
|
|
nickname?: string;
|
|
avatar?: string;
|
|
phone?: string;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 生成扫码登录token
|
|
*/
|
|
export async function generateQRToken(data?: GenerateQRTokenParam) {
|
|
const res = await request.post<ApiResult<GenerateQRTokenResult>>(
|
|
SERVER_API_URL + '/qr-login/generate',
|
|
{
|
|
clientType: 'wechat',
|
|
expireMinutes: 5,
|
|
...data
|
|
}
|
|
);
|
|
if (res.code === 0 && res.data) {
|
|
return res.data;
|
|
}
|
|
return Promise.reject(new Error(res.message));
|
|
}
|
|
|
|
/**
|
|
* 检查扫码登录状态
|
|
*/
|
|
export async function checkQRLoginStatus(token: string) {
|
|
const res = await request.get<ApiResult<QRLoginStatusResult>>(
|
|
SERVER_API_URL + `/qr-login/status/${token}`
|
|
);
|
|
if (res.code === 0 && res.data) {
|
|
return res.data;
|
|
}
|
|
return Promise.reject(new Error(res.message));
|
|
}
|
|
|
|
/**
|
|
* 确认扫码登录(通用接口)
|
|
*/
|
|
export async function confirmQRLogin(data: ConfirmLoginParam) {
|
|
const res = await request.post<ApiResult<ConfirmLoginResult>>(
|
|
SERVER_API_URL + '/qr-login/confirm',
|
|
data
|
|
);
|
|
if (res.code === 0 && res.data) {
|
|
return res.data;
|
|
}
|
|
return Promise.reject(new Error(res.message));
|
|
}
|
|
|
|
/**
|
|
* 微信小程序扫码登录确认(便捷接口)
|
|
*/
|
|
export async function confirmWechatQRLogin(token: string, userId: number) {
|
|
try {
|
|
// 获取微信用户信息
|
|
const userInfo = await getUserInfo();
|
|
console.log('获取微信用户信息3:', userInfo)
|
|
|
|
const data: ConfirmLoginParam = {
|
|
token,
|
|
userId,
|
|
platform: 'wechat',
|
|
wechatInfo: {
|
|
nickname: userInfo?.nickname,
|
|
avatar: userInfo?.avatar,
|
|
gender: userInfo?.sex
|
|
},
|
|
deviceInfo: await getDeviceInfo()
|
|
};
|
|
|
|
const res = await request.post<ApiResult<ConfirmLoginResult>>(
|
|
SERVER_API_URL + '/qr-login/confirm',
|
|
data
|
|
);
|
|
console.log(res,'ConfirmLoginParamResult>')
|
|
if (res.code === 0 && res.data) {
|
|
return res.data;
|
|
}
|
|
return Promise.reject(new Error(res.message));
|
|
} catch (error: any) {
|
|
return Promise.reject(new Error(error.message || '确认登录失败'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取微信用户信息
|
|
*/
|
|
async function getUserProfile() {
|
|
return new Promise<any>((resolve, reject) => {
|
|
Taro.getUserProfile({
|
|
desc: '用于扫码登录身份确认',
|
|
success: (res) => {
|
|
resolve(res.userInfo);
|
|
},
|
|
fail: (err) => {
|
|
// 如果获取失败,尝试使用已存储的用户信息
|
|
const storedUser = Taro.getStorageSync('User');
|
|
if (storedUser) {
|
|
resolve({
|
|
nickName: storedUser.nickname,
|
|
avatarUrl: storedUser.avatar,
|
|
gender: storedUser.gender
|
|
});
|
|
} else {
|
|
reject(err);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 获取设备信息
|
|
*/
|
|
async function getDeviceInfo() {
|
|
return new Promise<string>((resolve) => {
|
|
Taro.getSystemInfo({
|
|
success: (res) => {
|
|
const deviceInfo = {
|
|
platform: res.platform,
|
|
system: res.system,
|
|
version: res.version,
|
|
model: res.model,
|
|
brand: res.brand,
|
|
screenWidth: res.screenWidth,
|
|
screenHeight: res.screenHeight
|
|
};
|
|
resolve(JSON.stringify(deviceInfo));
|
|
},
|
|
fail: () => {
|
|
resolve('unknown');
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 解析二维码内容,提取token
|
|
*/
|
|
export function parseQRContent(qrContent: string): string | null {
|
|
try {
|
|
console.log('解析二维码内容1:', qrContent);
|
|
|
|
// 尝试解析JSON格式
|
|
if (qrContent.startsWith('{')) {
|
|
const parsed = JSON.parse(qrContent);
|
|
return parsed.token || parsed.qrCodeKey || null;
|
|
}
|
|
|
|
// 尝试解析URL格式
|
|
if (qrContent.includes('http')) {
|
|
const url = new URL(qrContent);
|
|
// 支持多种参数名
|
|
return url.searchParams.get('token') ||
|
|
url.searchParams.get('qrCodeKey') ||
|
|
url.searchParams.get('qr_code_key') ||
|
|
null;
|
|
}
|
|
|
|
// 尝试解析简单的key=value格式
|
|
if (qrContent.includes('=')) {
|
|
const params = new URLSearchParams(qrContent);
|
|
return params.get('token') ||
|
|
params.get('qrCodeKey') ||
|
|
params.get('qr_code_key') ||
|
|
null;
|
|
}
|
|
|
|
// 如果是以qr-login:开头的格式
|
|
if (qrContent.startsWith('qr-login:')) {
|
|
return qrContent.replace('qr-login:', '');
|
|
}
|
|
|
|
// 直接返回内容作为token(如果是32位以上的字符串)
|
|
if (qrContent.length >= 32) {
|
|
return qrContent;
|
|
}
|
|
|
|
return null;
|
|
} catch (error) {
|
|
console.error('解析二维码内容失败:', error);
|
|
return null;
|
|
}
|
|
}
|