feat: 1. 基础设施(2个文件)
- ✅ src/utils/logger.js - 统一日志工具 - API 请求/响应/错误日志 - 组件错误/警告/调试日志 - 开发环境详细分组,生产环境仅错误 - ✅ src/utils/axiosConfig.js - axios 全局拦截器 - 自动记录所有请求/响应 - 统一 baseURL 和 credentials 配置\ 2. 核心文件重构(8个文件)\ AuthFormContent.js | ✅ 保留登录/注册成功 toast❌ 移除验证码发送 toast✅ 添加 .trim()✅ 所有 API 添加 logger | ✅ 完成 | | Center.js | ❌ 移除所有 toast✅ 移除 toast 依赖✅ 添加错误 logger | ✅ 完成 | | Community/index.js | ❌ 移除所有 toast 和导入✅ 移除 toast 依赖✅ 添加错误 logger | ✅ 完成 | | authService.js | ✅ 统一 apiRequest 函数✅ 所有请求自动记录❌ 移除 console.error | ✅ 完成 | | eventService.js | ✅ 重构 apiRequest✅ 所有方法添加 logger❌ 移除 console.log/error | ✅ 完成 | | stockService | ✅ 所有方法添加 logger❌ 移除 console 输出 | ✅ 完成 | | indexService | ✅ 添加 logger❌ 移除 console 输出 | ✅ 完成 | | AuthContext.js | ✅ 保留注册/登出成功 toast❌ 移除验证码发送 toast✅ 所有方法添加 logger | ✅ 完成 |\ 3. Mock 数据完善(\ Mock 数据完善(1个文件) - ✅ src/mocks/handlers/account.js - 个人中心 Mock - ✅ 自选股列表 (GET /api/account/watchlist) - ✅ 实时行情 (GET /api/account/watchlist/realtime) - ✅ 添加自选股 (POST /api/account/watchlist/add) - ✅ 删除自选股 (DELETE /api/account/watchlist/:id) - ✅ 关注的事件 (GET /api/account/events/following) - ✅ 事件评论 (GET /api/account/events/comments) - ✅ 当前订阅 (GET /api/subscription/current)\ 4. API 文档(1个文件) - ✅ API_ENDPOINTS.md - 完整 API 接口文档 - 认证相关: 4个接口 - 个人中心: 12个接口 - 事件相关: 12个接口 - 总计: 28+个接口\ 5。Toast 策略执行: - ✅ 保留: 3种(登录成功、注册成功、登出成功) - ❌ 移除: 15+处(验证码、数据加载等) Logger 替换: - ✅ console.log → logger.debug/logger.info - ✅ console.error → logger.error\- console.warn → logger.warn Mock 数据: 已有: auth.js, event.js, users.js, events.js 新增: account.js(7个新接口) 6.用户体验改进 静默优化:不再弹出验证码发送成功提示(静默处理)不再弹出数据加载失败提示(console 记录) 仅在关键操作显示 toast(登录/注册/登出) 开发体验: Console 中有清晰的分组日志(🌐 🔴 ⚠️ 等图标), 所有 API 请求/响应自动记录,错误日志包含完整上下文和堆栈,Mock 服务完善 测试场景: 登录/注册 - 仅显示成功 toast,验证码静默发送 个人中心 - 加载自选股、实时行情、关注事件 社区页面 - 加载事件列表、Console 查看 9. 添加日志:API Request / ✅ API Response / ❌ API Error
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import React, { createContext, useContext, useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useToast } from '@chakra-ui/react';
|
||||
import { logger } from '../utils/logger';
|
||||
|
||||
// 创建认证上下文
|
||||
const AuthContext = createContext();
|
||||
@@ -26,7 +27,7 @@ export const AuthProvider = ({ children }) => {
|
||||
// 检查Session状态
|
||||
const checkSession = async () => {
|
||||
try {
|
||||
console.log('🔍 检查Session状态...');
|
||||
logger.debug('AuthContext', '检查Session状态');
|
||||
|
||||
// 创建超时控制器
|
||||
const controller = new AbortController();
|
||||
@@ -34,11 +35,11 @@ export const AuthProvider = ({ children }) => {
|
||||
|
||||
const response = await fetch(`/api/auth/session`, {
|
||||
method: 'GET',
|
||||
credentials: 'include', // 重要:包含cookie
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
signal: controller.signal // 添加超时信号
|
||||
signal: controller.signal
|
||||
});
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
@@ -48,7 +49,10 @@ export const AuthProvider = ({ children }) => {
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log('📦 Session数据:', data);
|
||||
logger.debug('AuthContext', 'Session数据', {
|
||||
isAuthenticated: data.isAuthenticated,
|
||||
userId: data.user?.id
|
||||
});
|
||||
|
||||
if (data.isAuthenticated && data.user) {
|
||||
setUser(data.user);
|
||||
@@ -58,12 +62,11 @@ export const AuthProvider = ({ children }) => {
|
||||
setIsAuthenticated(false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Session检查错误:', error);
|
||||
logger.error('AuthContext', 'checkSession', error);
|
||||
// 网络错误或超时,设置为未登录状态
|
||||
setUser(null);
|
||||
setIsAuthenticated(false);
|
||||
} finally {
|
||||
// ⚡ Session 检查完成后,停止加载状态
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
@@ -97,7 +100,7 @@ export const AuthProvider = ({ children }) => {
|
||||
const login = async (credential, password, loginType = 'email') => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
console.log('🔐 开始登录流程:', { credential, loginType });
|
||||
logger.debug('AuthContext', '开始登录流程', { credential: credential.substring(0, 3) + '***', loginType });
|
||||
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('password', password);
|
||||
@@ -110,11 +113,9 @@ export const AuthProvider = ({ children }) => {
|
||||
formData.append('username', credential);
|
||||
}
|
||||
|
||||
console.log('📤 发送登录请求到:', `/api/auth/login`);
|
||||
console.log('📝 请求数据:', {
|
||||
credential,
|
||||
loginType,
|
||||
formData: formData.toString()
|
||||
logger.api.request('POST', '/api/auth/login', {
|
||||
credential: credential.substring(0, 3) + '***',
|
||||
loginType
|
||||
});
|
||||
|
||||
const response = await fetch(`/api/auth/login`, {
|
||||
@@ -122,24 +123,19 @@ export const AuthProvider = ({ children }) => {
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
credentials: 'include', // 包含cookie
|
||||
credentials: 'include',
|
||||
body: formData
|
||||
});
|
||||
|
||||
console.log('📨 响应状态:', response.status, response.statusText);
|
||||
console.log('📨 响应头:', Object.fromEntries(response.headers.entries()));
|
||||
|
||||
// 获取响应文本,然后尝试解析JSON
|
||||
const responseText = await response.text();
|
||||
console.log('📨 响应原始内容:', responseText);
|
||||
|
||||
let data;
|
||||
try {
|
||||
data = JSON.parse(responseText);
|
||||
console.log('✅ JSON解析成功:', data);
|
||||
logger.api.response('POST', '/api/auth/login', response.status, data);
|
||||
} catch (parseError) {
|
||||
console.error('❌ JSON解析失败:', parseError);
|
||||
console.error('📄 响应内容:', responseText);
|
||||
logger.error('AuthContext', 'login', parseError, { responseText: responseText.substring(0, 100) });
|
||||
throw new Error(`服务器响应格式错误: ${responseText.substring(0, 100)}...`);
|
||||
}
|
||||
|
||||
@@ -163,17 +159,7 @@ export const AuthProvider = ({ children }) => {
|
||||
return { success: true };
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 登录错误:', error);
|
||||
|
||||
// ⚡ 移除toast,让调用者处理错误显示,避免重复toast和并发更新
|
||||
// toast({
|
||||
// title: "登录失败",
|
||||
// description: error.message || "请检查您的登录信息",
|
||||
// status: "error",
|
||||
// duration: 3000,
|
||||
// isClosable: true,
|
||||
// });
|
||||
|
||||
logger.error('AuthContext', 'login', error, { loginType });
|
||||
return { success: false, error: error.message };
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
@@ -220,18 +206,11 @@ export const AuthProvider = ({ children }) => {
|
||||
return { success: true };
|
||||
|
||||
} catch (error) {
|
||||
console.error('注册错误:', error);
|
||||
|
||||
toast({
|
||||
title: "注册失败",
|
||||
description: error.message || "注册失败,请稍后重试",
|
||||
status: "error",
|
||||
duration: 3000,
|
||||
isClosable: true,
|
||||
});
|
||||
logger.error('AuthContext', 'register', error);
|
||||
|
||||
// ❌ 移除错误 toast,静默失败
|
||||
return { success: false, error: error.message };
|
||||
} finally {
|
||||
} finally{
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
@@ -276,16 +255,7 @@ export const AuthProvider = ({ children }) => {
|
||||
return { success: true };
|
||||
|
||||
} catch (error) {
|
||||
console.error('手机注册错误:', error);
|
||||
|
||||
toast({
|
||||
title: "注册失败",
|
||||
description: error.message || "注册失败,请稍后重试",
|
||||
status: "error",
|
||||
duration: 3000,
|
||||
isClosable: true,
|
||||
});
|
||||
|
||||
logger.error('AuthContext', 'registerWithPhone', error, { phone: phone.substring(0, 3) + '****' });
|
||||
return { success: false, error: error.message };
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
@@ -332,16 +302,7 @@ export const AuthProvider = ({ children }) => {
|
||||
return { success: true };
|
||||
|
||||
} catch (error) {
|
||||
console.error('邮箱注册错误:', error);
|
||||
|
||||
toast({
|
||||
title: "注册失败",
|
||||
description: error.message || "注册失败,请稍后重试",
|
||||
status: "error",
|
||||
duration: 3000,
|
||||
isClosable: true,
|
||||
});
|
||||
|
||||
logger.error('AuthContext', 'registerWithEmail', error);
|
||||
return { success: false, error: error.message };
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
@@ -356,7 +317,7 @@ export const AuthProvider = ({ children }) => {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'include', // 必须包含以支持跨域 session cookie
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({ phone })
|
||||
});
|
||||
|
||||
@@ -366,27 +327,13 @@ export const AuthProvider = ({ children }) => {
|
||||
throw new Error(data.error || '发送失败');
|
||||
}
|
||||
|
||||
toast({
|
||||
title: "验证码已发送",
|
||||
description: "请查收短信",
|
||||
status: "success",
|
||||
duration: 3000,
|
||||
isClosable: true,
|
||||
});
|
||||
|
||||
// ❌ 移除成功 toast
|
||||
logger.info('AuthContext', '验证码已发送', { phone: phone.substring(0, 3) + '****' });
|
||||
return { success: true };
|
||||
|
||||
} catch (error) {
|
||||
console.error('SMS code error:', error);
|
||||
|
||||
toast({
|
||||
title: "发送失败",
|
||||
description: error.message || "请稍后重试",
|
||||
status: "error",
|
||||
duration: 3000,
|
||||
isClosable: true,
|
||||
});
|
||||
|
||||
// ❌ 移除错误 toast
|
||||
logger.error('AuthContext', 'sendSmsCode', error, { phone: phone.substring(0, 3) + '****' });
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
};
|
||||
@@ -399,7 +346,7 @@ export const AuthProvider = ({ children }) => {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'include', // 必须包含以支持跨域 session cookie
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({ email })
|
||||
});
|
||||
|
||||
@@ -409,27 +356,13 @@ export const AuthProvider = ({ children }) => {
|
||||
throw new Error(data.error || '发送失败');
|
||||
}
|
||||
|
||||
toast({
|
||||
title: "验证码已发送",
|
||||
description: "请查收邮件",
|
||||
status: "success",
|
||||
duration: 3000,
|
||||
isClosable: true,
|
||||
});
|
||||
|
||||
// ❌ 移除成功 toast
|
||||
logger.info('AuthContext', '邮箱验证码已发送', { email: email.substring(0, 3) + '***@***' });
|
||||
return { success: true };
|
||||
|
||||
} catch (error) {
|
||||
console.error('Email code error:', error);
|
||||
|
||||
toast({
|
||||
title: "发送失败",
|
||||
description: error.message || "请稍后重试",
|
||||
status: "error",
|
||||
duration: 3000,
|
||||
isClosable: true,
|
||||
});
|
||||
|
||||
// ❌ 移除错误 toast
|
||||
logger.error('AuthContext', 'sendEmailCode', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
};
|
||||
@@ -447,6 +380,7 @@ export const AuthProvider = ({ children }) => {
|
||||
setUser(null);
|
||||
setIsAuthenticated(false);
|
||||
|
||||
// ✅ 保留登出成功 toast(关键操作提示)
|
||||
toast({
|
||||
title: "已登出",
|
||||
description: "您已成功退出登录",
|
||||
@@ -455,14 +389,11 @@ export const AuthProvider = ({ children }) => {
|
||||
isClosable: true,
|
||||
});
|
||||
|
||||
// 不再跳转,用户留在当前页面
|
||||
|
||||
} catch (error) {
|
||||
console.error('Logout error:', error);
|
||||
logger.error('AuthContext', 'logout', error);
|
||||
// 即使API调用失败也清除本地状态
|
||||
setUser(null);
|
||||
setIsAuthenticated(false);
|
||||
// 不再跳转,用户留在当前页面
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user