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:
zdl
2025-10-18 07:48:00 +08:00
parent 69784d094d
commit 36558e0715
10 changed files with 1075 additions and 208 deletions

64
src/utils/axiosConfig.js Normal file
View File

@@ -0,0 +1,64 @@
// src/utils/axiosConfig.js
// Axios 全局配置和拦截器
import axios from 'axios';
import { logger } from './logger';
// 判断当前是否是生产环境
const isProduction = process.env.NODE_ENV === 'production';
// 配置基础 URL
const API_BASE_URL = isProduction ? '' : process.env.REACT_APP_API_URL;
// 配置 axios 默认值
axios.defaults.baseURL = API_BASE_URL;
axios.defaults.withCredentials = true;
axios.defaults.headers.common['Content-Type'] = 'application/json';
/**
* 请求拦截器
* 自动记录所有请求日志
*/
axios.interceptors.request.use(
(config) => {
const method = config.method?.toUpperCase() || 'GET';
const url = config.url || '';
const data = config.data || config.params || null;
logger.api.request(method, url, data);
return config;
},
(error) => {
logger.api.error('REQUEST', 'Interceptor', error);
return Promise.reject(error);
}
);
/**
* 响应拦截器
* 自动记录所有响应/错误日志
*/
axios.interceptors.response.use(
(response) => {
const method = response.config.method?.toUpperCase() || 'GET';
const url = response.config.url || '';
const status = response.status;
const data = response.data;
logger.api.response(method, url, status, data);
return response;
},
(error) => {
const method = error.config?.method?.toUpperCase() || 'UNKNOWN';
const url = error.config?.url || 'UNKNOWN';
const requestData = error.config?.data || error.config?.params || null;
logger.api.error(method, url, error, requestData);
return Promise.reject(error);
}
);
export default axios;

144
src/utils/logger.js Normal file
View File

@@ -0,0 +1,144 @@
// src/utils/logger.js
// 统一日志工具
const isDevelopment = process.env.NODE_ENV === 'development';
/**
* 统一日志工具
* 开发环境:输出详细日志
* 生产环境:仅输出错误日志
*/
export const logger = {
/**
* API 相关日志
*/
api: {
/**
* 记录 API 请求
* @param {string} method - 请求方法 (GET, POST, etc.)
* @param {string} url - 请求 URL
* @param {object} data - 请求参数/body
*/
request: (method, url, data = null) => {
if (isDevelopment) {
console.group(`🌐 API Request: ${method} ${url}`);
console.log('Timestamp:', new Date().toISOString());
if (data) console.log('Data:', data);
console.groupEnd();
}
},
/**
* 记录 API 响应成功
* @param {string} method - 请求方法
* @param {string} url - 请求 URL
* @param {number} status - HTTP 状态码
* @param {any} data - 响应数据
*/
response: (method, url, status, data) => {
if (isDevelopment) {
console.group(`✅ API Response: ${method} ${url}`);
console.log('Status:', status);
console.log('Data:', data);
console.log('Timestamp:', new Date().toISOString());
console.groupEnd();
}
},
/**
* 记录 API 错误
* @param {string} method - 请求方法
* @param {string} url - 请求 URL
* @param {Error|any} error - 错误对象
* @param {object} requestData - 请求参数(可选)
*/
error: (method, url, error, requestData = null) => {
console.group(`❌ API Error: ${method} ${url}`);
console.error('Error:', error);
console.error('Message:', error?.message || error);
if (error?.response) {
console.error('Response Status:', error.response.status);
console.error('Response Data:', error.response.data);
}
if (requestData) console.error('Request Data:', requestData);
console.error('Timestamp:', new Date().toISOString());
if (error?.stack) console.error('Stack:', error.stack);
console.groupEnd();
}
},
/**
* 组件错误日志
* @param {string} component - 组件名称
* @param {string} method - 方法名称
* @param {Error|any} error - 错误对象
* @param {object} context - 上下文信息(可选)
*/
error: (component, method, error, context = {}) => {
console.group(`🔴 Error in ${component}.${method}`);
console.error('Error:', error);
console.error('Message:', error?.message || error);
if (Object.keys(context).length > 0) {
console.error('Context:', context);
}
console.error('Timestamp:', new Date().toISOString());
if (error?.stack) console.error('Stack:', error.stack);
console.groupEnd();
},
/**
* 警告日志
* @param {string} component - 组件名称
* @param {string} message - 警告信息
* @param {object} data - 相关数据(可选)
*/
warn: (component, message, data = {}) => {
if (isDevelopment) {
console.group(`⚠️ Warning: ${component}`);
console.warn('Message:', message);
if (Object.keys(data).length > 0) {
console.warn('Data:', data);
}
console.warn('Timestamp:', new Date().toISOString());
console.groupEnd();
}
},
/**
* 调试日志(仅开发环境)
* @param {string} component - 组件名称
* @param {string} message - 调试信息
* @param {object} data - 相关数据(可选)
*/
debug: (component, message, data = {}) => {
if (isDevelopment) {
console.group(`🐛 Debug: ${component}`);
console.log('Message:', message);
if (Object.keys(data).length > 0) {
console.log('Data:', data);
}
console.log('Timestamp:', new Date().toISOString());
console.groupEnd();
}
},
/**
* 信息日志(仅开发环境)
* @param {string} component - 组件名称
* @param {string} message - 信息内容
* @param {object} data - 相关数据(可选)
*/
info: (component, message, data = {}) => {
if (isDevelopment) {
console.group(` Info: ${component}`);
console.log('Message:', message);
if (Object.keys(data).length > 0) {
console.log('Data:', data);
}
console.log('Timestamp:', new Date().toISOString());
console.groupEnd();
}
}
};
export default logger;