refactor(api): 调整二维码登录相关接口路径

- 将 qr-login 相关接口统一迁移至 passport 模块下
- 更新 QRScanModal 组件中的接口引用路径- 更新 useQRLogin hook 中的接口引用路径
- 更新 useUnifiedQRScan hook 中的接口引用路径
- 更新 qr-confirm 页面中的接口引用路径
This commit is contained in:
2025-09-24 16:50:49 +08:00
parent 13b56cd7f8
commit 555c348799
5 changed files with 4 additions and 4 deletions

View File

@@ -0,0 +1,246 @@
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();
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<any>>(
SERVER_API_URL + '/qr-login/confirm',
data
);
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 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;
}
}