Files
template-10584/src/api/qr-login/index.ts

276 lines
6.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
}