Files
vf_react/src/mocks/handlers/auth.js

409 lines
14 KiB
JavaScript
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.

// src/mocks/handlers/auth.js
import { http, HttpResponse, delay } from 'msw';
import {
mockUsers,
mockVerificationCodes,
generateVerificationCode,
mockWechatSessions,
generateWechatSessionId,
setCurrentUser,
getCurrentUser,
clearCurrentUser
} from '../data/users';
// 模拟网络延迟(毫秒)
// ⚡ 开发环境使用较短延迟,加快首屏加载速度
const NETWORK_DELAY = 50;
export const authHandlers = [
// ==================== 手机验证码登录 ====================
// 1. 发送验证码
http.post('/api/auth/send-verification-code', async ({ request }) => {
await delay(NETWORK_DELAY);
const body = await request.json();
const { credential, type, purpose } = body;
// 生成验证码
const code = generateVerificationCode();
mockVerificationCodes.set(credential, {
code,
expiresAt: Date.now() + 5 * 60 * 1000 // 5分钟后过期
});
return HttpResponse.json({
success: true,
message: `验证码已发送到 ${credential}Mock: ${code}`,
// 开发环境下返回验证码,方便测试
dev_code: code
});
}),
// 1.1 发送手机验证码(前端实际调用的接口)
http.post('/api/auth/send-sms-code', async ({ request }) => {
await delay(NETWORK_DELAY);
const body = await request.json();
const { phone } = body;
console.log('[Mock] 发送手机验证码请求:', { phone });
// 生成验证码
const code = generateVerificationCode();
mockVerificationCodes.set(phone, {
code,
expiresAt: Date.now() + 5 * 60 * 1000 // 5分钟后过期
});
// 超醒目的验证码提示 - 方便开发调试
console.log(
`%c\n` +
`╔════════════════════════════════════════════╗\n` +
`║ 📱 手机验证码: ${code.padEnd(19)}\n` +
`║ 📞 手机号: ${phone.padEnd(23)}\n` +
`╚════════════════════════════════════════════╝\n`,
'color: #ffffff; background: #16a34a; font-weight: bold; font-size: 16px; padding: 20px; line-height: 1.8;'
);
// 额外的高亮提示
console.log(
`%c 📱 验证码: ${code} `,
'color: #ffffff; background: #dc2626; font-weight: bold; font-size: 24px; padding: 15px 30px; border-radius: 8px; margin: 10px 0;'
);
return HttpResponse.json({
success: true,
message: `验证码已发送到 ${phone}Mock: ${code}`,
// 开发环境下返回验证码,方便测试
dev_code: code
});
}),
// 1.2 发送邮箱验证码(前端实际调用的接口)
http.post('/api/auth/send-email-code', async ({ request }) => {
await delay(NETWORK_DELAY);
const body = await request.json();
const { email } = body;
console.log('[Mock] 发送邮箱验证码请求:', { email });
// 生成验证码
const code = generateVerificationCode();
mockVerificationCodes.set(email, {
code,
expiresAt: Date.now() + 5 * 60 * 1000 // 5分钟后过期
});
// 超醒目的验证码提示 - 方便开发调试
console.log(
`%c\n` +
`╔════════════════════════════════════════════╗\n` +
`║ 📧 邮箱验证码: ${code.padEnd(19)}\n` +
`║ 📮 邮箱: ${email.padEnd(27)}\n` +
`╚════════════════════════════════════════════╝\n`,
'color: #ffffff; background: #2563eb; font-weight: bold; font-size: 16px; padding: 20px; line-height: 1.8;'
);
// 额外的高亮提示
console.log(
`%c 📧 验证码: ${code} `,
'color: #ffffff; background: #dc2626; font-weight: bold; font-size: 24px; padding: 15px 30px; border-radius: 8px; margin: 10px 0;'
);
return HttpResponse.json({
success: true,
message: `验证码已发送到 ${email}Mock: ${code}`,
// 开发环境下返回验证码,方便测试
dev_code: code
});
}),
// 2. 验证码登录
http.post('/api/auth/login-with-code', async ({ request }) => {
await delay(NETWORK_DELAY);
const body = await request.json();
const { credential, verification_code, login_type } = body;
// 验证验证码
const storedCode = mockVerificationCodes.get(credential);
if (!storedCode) {
return HttpResponse.json({
success: false,
error: '验证码不存在或已过期'
}, { status: 400 });
}
if (storedCode.expiresAt < Date.now()) {
mockVerificationCodes.delete(credential);
return HttpResponse.json({
success: false,
error: '验证码已过期'
}, { status: 400 });
}
if (storedCode.code !== verification_code) {
return HttpResponse.json({
success: false,
error: '验证码错误'
}, { status: 400 });
}
// 验证成功,删除验证码
mockVerificationCodes.delete(credential);
// 查找或创建用户
let user = mockUsers[credential];
let isNewUser = false;
if (!user) {
// 新用户
isNewUser = true;
const id = Object.keys(mockUsers).length + 1;
user = {
id,
phone: credential,
nickname: `用户${id}`,
email: null,
avatar_url: `https://i.pravatar.cc/150?img=${id}`,
has_wechat: false,
created_at: new Date().toISOString(),
// 默认订阅信息 - 免费用户
subscription_type: 'free',
subscription_status: 'active',
subscription_end_date: null,
is_subscription_active: true,
subscription_days_left: 0
};
mockUsers[credential] = user;
}
// 设置当前登录用户
setCurrentUser(user);
return HttpResponse.json({
success: true,
message: isNewUser ? '注册成功' : '登录成功',
isNewUser,
user,
token: `mock_token_${user.id}_${Date.now()}`
});
}),
// ==================== 微信登录 ====================
// 3. 获取微信 PC 二维码
http.get('/api/auth/wechat/qrcode', async () => {
await delay(NETWORK_DELAY);
const sessionId = generateWechatSessionId();
// 创建微信 session
mockWechatSessions.set(sessionId, {
status: 'waiting', // waiting, scanned, confirmed, expired
createdAt: Date.now(),
user: null
});
// 模拟微信授权 URL实际是微信的 URL
// 使用真实的微信 AppID 和真实的授权回调地址(必须与微信开放平台配置的域名一致)
const mockRedirectUri = encodeURIComponent('http://valuefrontier.cn/api/auth/wechat/callback');
const authUrl = `https://open.weixin.qq.com/connect/qrconnect?appid=wxa8d74c47041b5f87&redirect_uri=${mockRedirectUri}&response_type=code&scope=snsapi_login&state=${sessionId}#wechat_redirect`;
console.log('[Mock] 生成微信二维码:', { sessionId, authUrl });
// 3秒后自动模拟扫码方便测试已缩短延迟
setTimeout(() => {
const session = mockWechatSessions.get(sessionId);
if (session && session.status === 'waiting') {
session.status = 'scanned';
console.log(`[Mock] 模拟用户扫码: ${sessionId}`);
// 再过5秒自动确认登录延长时间让用户看到 scanned 状态)
setTimeout(() => {
const session2 = mockWechatSessions.get(sessionId);
if (session2 && session2.status === 'scanned') {
session2.status = 'authorized'; // ✅ 使用 'authorized' 状态,与后端保持一致
session2.user = {
id: 999,
nickname: '微信用户',
wechat_openid: 'mock_openid_' + sessionId,
avatar_url: 'https://ui-avatars.com/api/?name=微信用户&size=150&background=4299e1&color=fff',
phone: null,
email: null,
has_wechat: true,
created_at: new Date().toISOString(),
// 添加默认订阅信息
subscription_type: 'free',
subscription_status: 'active',
subscription_end_date: null,
is_subscription_active: true,
subscription_days_left: 0
};
session2.user_info = { user_id: session2.user.id }; // ✅ 添加 user_info 字段
console.log(`[Mock] 模拟用户确认登录: ${sessionId}`, session2.user);
}
}, 2000);
}
}, 3000);
return HttpResponse.json({
code: 0,
message: '成功',
data: {
auth_url: authUrl,
session_id: sessionId
}
});
}),
// 4. 检查微信扫码状态
http.post('/api/auth/wechat/check', async ({ request }) => {
await delay(200); // 轮询请求,延迟短一些
const body = await request.json();
const { session_id } = body;
const session = mockWechatSessions.get(session_id);
if (!session) {
return HttpResponse.json({
code: 404,
message: 'Session 不存在',
data: { status: 'expired' }
});
}
// 检查是否过期5分钟
if (Date.now() - session.createdAt > 5 * 60 * 1000) {
session.status = 'expired';
mockWechatSessions.delete(session_id);
}
console.log('[Mock] 检查微信状态:', { session_id, status: session.status });
// ✅ 返回与后端真实 API 一致的扁平化数据结构
return HttpResponse.json({
status: session.status,
user_info: session.user_info,
expires_in: Math.floor((session.createdAt + 5 * 60 * 1000 - Date.now()) / 1000)
});
}),
// 5. 微信登录确认
http.post('/api/auth/login/wechat', async ({ request }) => {
await delay(NETWORK_DELAY);
const body = await request.json();
const { session_id } = body;
const session = mockWechatSessions.get(session_id);
if (!session || session.status !== 'authorized') { // ✅ 使用 'authorized' 状态,与前端保持一致
return HttpResponse.json({
success: false,
error: '微信登录未确认或已过期'
}, { status: 400 });
}
const user = session.user;
// 清理 session
mockWechatSessions.delete(session_id);
console.log('[Mock] 微信登录成功:', user);
// 设置当前登录用户
setCurrentUser(user);
return HttpResponse.json({
success: true,
message: '微信登录成功',
user,
token: `mock_wechat_token_${user.id}_${Date.now()}`
});
}),
// 6. 获取微信 H5 授权 URL手机浏览器用
http.post('/api/auth/wechat/h5-auth', async ({ request }) => {
await delay(NETWORK_DELAY);
const body = await request.json();
const { redirect_url } = body;
const state = generateWechatSessionId();
// Mock 模式下直接返回前端回调地址(模拟授权成功)
const authUrl = `${redirect_url}?wechat_login=success&state=${state}`;
console.log('[Mock] 生成微信 H5 授权 URL:', authUrl);
return HttpResponse.json({
auth_url: authUrl,
state
});
}),
// ==================== Session 管理 ====================
// 7. 检查 SessionAuthContext 使用的正确端点)
http.get('/api/auth/session', async () => {
await delay(NETWORK_DELAY); // ⚡ 使用统一延迟配置
// 获取当前登录用户
const currentUser = getCurrentUser();
if (currentUser) {
return HttpResponse.json({
success: true,
isAuthenticated: true,
user: currentUser
});
} else {
return HttpResponse.json({
success: true,
isAuthenticated: false,
user: null
});
}
}),
// 8. 检查 Session旧端点保留兼容
http.get('/api/auth/check-session', async () => {
await delay(NETWORK_DELAY); // ⚡ 使用统一延迟配置
// 获取当前登录用户
const currentUser = getCurrentUser();
if (currentUser) {
return HttpResponse.json({
success: true,
isAuthenticated: true,
user: currentUser
});
} else {
return HttpResponse.json({
success: true,
isAuthenticated: false,
user: null
});
}
}),
// 9. 退出登录
http.post('/api/auth/logout', async () => {
await delay(NETWORK_DELAY);
console.log('[Mock] 退出登录');
// 清除当前登录用户
clearCurrentUser();
return HttpResponse.json({
success: true,
message: '退出成功'
});
})
];