日志模块(文件持久化 + 事件总线联动 + 脱敏)
新增:
- shared/types/logging.ts — LogLevel / LogCategory / LogEntry 类型
- electron/main/logger.ts — 主进程日志核心(JSON Lines / 每日轮转 / 7天清理)
- electron/main/log-ipc.ts — 渲染进程日志 IPC 通道接收
- src/utils/logger.ts — 渲染进程日志器(IPC 转发 / DEV 控制台 / 事件总线钩子)
- shared/utils/sanitize.ts — 脱敏工具(ID哈希 / 邮箱 / 手机 / 名称 / Token)
修改:
- electron/main.ts — initLogger + flushLogger + uncaughtException
- src/main.tsx — renderer 全局错误捕获
- src/utils/event-bus.ts — setEventLogListener 钩子,emit 自动审计
- src/services/request.ts — 拦截器结构化错误分级记录
- electron/main/updater.ts — 14处 console → logger 迁移
- src/components/AppProvider.tsx — 登录/登出/自动登录 auth 事件日志
- shared/constants/ipc-channels.ts — 新增 LOG_MESSAGE 通道
netRequest 封装(Electron net.request 的 axios 风格 API)
新增:
- electron/main/net-request.ts — netRequest.get/post/put/del 命名空间
修改:
- electron/main/updater.ts — fetchUpdateInfo 改用 netRequest(22→12行)
文档更新
- PROJECT.md — 目录结构 / 状态管理 / 日志系统 / IPC 章节同步现状
- TODO.md — 增量更新改造 + 日志模块待办
- UpdateA.md — API blockmap 字段 / 数据库字段说明
73 lines
2.1 KiB
TypeScript
73 lines
2.1 KiB
TypeScript
// ============================================================
|
||
// 事件总线 — 跨组件/跨模块事件通信
|
||
// 用于 axios 拦截器 → App 触发登录弹窗等解耦场景
|
||
// ============================================================
|
||
|
||
type Listener = (...args: unknown[]) => void;
|
||
|
||
const listeners = new Map<string, Set<Listener>>();
|
||
|
||
// ---------- 日志钩子(由 logger 模块注册,避免循环依赖)----------
|
||
|
||
type EventLogListener = (event: string, ...args: unknown[]) => void;
|
||
let eventLogListener: EventLogListener | null = null;
|
||
|
||
/**
|
||
* 注册事件日志监听器(由 logger 模块调用)
|
||
* 每次 emit() 时回调,用于审计追踪
|
||
*/
|
||
export function setEventLogListener(fn: EventLogListener): void {
|
||
eventLogListener = fn;
|
||
}
|
||
|
||
// ---------- API ----------
|
||
|
||
/** 监听事件 */
|
||
export function on(event: string, fn: Listener): void {
|
||
if (!listeners.has(event)) {
|
||
listeners.set(event, new Set());
|
||
}
|
||
listeners.get(event)!.add(fn);
|
||
}
|
||
|
||
/** 取消监听 */
|
||
export function off(event: string, fn: Listener): void {
|
||
listeners.get(event)?.delete(fn);
|
||
}
|
||
|
||
/** 触发事件 */
|
||
export function emit(event: string, ...args: unknown[]): void {
|
||
// ① 通知日志监听器(在触发业务监听器之前记录)
|
||
if (eventLogListener) {
|
||
try {
|
||
eventLogListener(event, ...args);
|
||
} catch {
|
||
/* 日志钩子异常不影响事件投递 */
|
||
}
|
||
}
|
||
|
||
// ② 通知业务监听器
|
||
listeners.get(event)?.forEach((fn) => {
|
||
try {
|
||
fn(...args);
|
||
} catch (e) {
|
||
console.error(`[EventBus] ${event} 回调出错:`, e);
|
||
}
|
||
});
|
||
}
|
||
|
||
// ============================================================
|
||
// 预定义事件名
|
||
// ============================================================
|
||
|
||
export const EVENTS = {
|
||
/** 需要登录(axios 返回 401 时触发) */
|
||
AUTH_REQUIRED: 'auth:required',
|
||
/** 显示登录弹窗(用户点击登录按钮触发) */
|
||
SHOW_LOGIN: 'auth:show-login',
|
||
/** 登录成功 */
|
||
LOGIN_SUCCESS: 'auth:login-success',
|
||
/** 退出登录 */
|
||
LOGOUT: 'auth:logout',
|
||
} as const;
|