feat: 使用mitt库

This commit is contained in:
2026-06-22 14:36:20 +08:00
parent fe8918c06f
commit 70c4bab3f6
4 changed files with 22 additions and 79 deletions

View File

@@ -1,6 +1,5 @@
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { eventBus, AppEvents } from '@/utils' import { eventBus, AppEvents } from '@/utils'
import type { RequestErrorEvent } from './types'
/** /**
* 注册请求错误 UI 展示 * 注册请求错误 UI 展示
@@ -8,7 +7,6 @@ import type { RequestErrorEvent } from './types'
* 订阅应用级 REQUEST_ERROR 事件,统一展示错误提示, * 订阅应用级 REQUEST_ERROR 事件,统一展示错误提示,
* 实现网络模块与 UI 的解耦。 * 实现网络模块与 UI 的解耦。
*/ */
eventBus.on(AppEvents.REQUEST_ERROR, (payload: unknown) => { eventBus.on(AppEvents.REQUEST_ERROR, (payload) => {
const { message: errorMessage } = payload as RequestErrorEvent ElMessage.error(payload.message)
ElMessage.error(errorMessage)
}) })

View File

@@ -1,7 +1,7 @@
import axios, { type AxiosInstance, type CreateAxiosDefaults } from 'axios' import axios, { type AxiosInstance, type CreateAxiosDefaults } from 'axios'
import { useAccountStore } from '@/stores' import { useAccountStore } from '@/stores'
import { eventBus, AppEvents } from '@/utils' import { eventBus, AppEvents } from '@/utils'
import type { ApiResponse, InternalRequestConfig, RequestErrorEvent } from './types' import type { ApiResponse, InternalRequestConfig } from './types'
import { createRefreshTokenInterceptor } from './refreshInterceptor' import { createRefreshTokenInterceptor } from './refreshInterceptor'
/** /**
@@ -106,7 +106,7 @@ class RequestClient {
type: 'business', type: 'business',
code: data.code, code: data.code,
message: data.message || '请求失败' message: data.message || '请求失败'
} satisfies RequestErrorEvent) })
return Promise.reject(data) return Promise.reject(data)
}, },
(error) => { (error) => {
@@ -121,7 +121,7 @@ class RequestClient {
message: error.response message: error.response
? `请求错误 (${error.response.status})` ? `请求错误 (${error.response.status})`
: '网络异常,请检查网络连接' : '网络异常,请检查网络连接'
} satisfies RequestErrorEvent) })
return Promise.reject(error) return Promise.reject(error)
} }
) )

View File

@@ -43,7 +43,8 @@ export function useSse() {
} }
// Vite 代理: /api/sse/subscribe → 后端 /sse/subscribe // Vite 代理: /api/sse/subscribe → 后端 /sse/subscribe
const url = `/api/sse/subscribe?token=${encodeURIComponent(token)}` // 鉴权走 Cookie登录后 Sa-Token 写入同名 CookieEventSource 同域请求自动携带)
const url = `/api/sse/subscribe`
es = new EventSource(url) es = new EventSource(url)
es.onopen = () => { es.onopen = () => {

View File

@@ -1,16 +1,25 @@
/** 事件处理器类型 */ import mitt from 'mitt'
type EventHandler = (...args: unknown[]) => void
/** 应用级事件类型定义 */
type AppEventsMap = {
/** 401 未授权 */
'app:unauthorized': void
/** 请求错误(业务错误 / HTTP 错误 / 网络错误) */
'app:request:error': {
type: 'business' | 'http' | 'network'
code?: number
message: string
}
}
/** 应用级事件常量 */ /** 应用级事件常量 */
export const AppEvents = { export const AppEvents = {
/** 401 未授权 */
UNAUTHORIZED: 'app:unauthorized', UNAUTHORIZED: 'app:unauthorized',
/** 请求错误(业务错误 / HTTP 错误 / 网络错误) */
REQUEST_ERROR: 'app:request:error' REQUEST_ERROR: 'app:request:error'
} as const } as const
/** /**
* 发布订阅事件总线 * 应用级事件总线(基于 mitt
* *
* @example * @example
* ```ts * ```ts
@@ -23,69 +32,4 @@ export const AppEvents = {
* eventBus.emit(AppEvents.UNAUTHORIZED) * eventBus.emit(AppEvents.UNAUTHORIZED)
* ``` * ```
*/ */
class EventBus { export const eventBus = mitt<AppEventsMap>()
/** 事件名 → 处理器集合 */
private handlers = new Map<string, Set<EventHandler>>()
/**
* 注册事件处理器
* @param event - 事件名
* @param handler - 处理器函数
*/
on(event: string, handler: EventHandler): void {
if (!this.handlers.has(event)) {
this.handlers.set(event, new Set())
}
this.handlers.get(event)!.add(handler)
}
/**
* 注册一次性事件处理器(触发后自动取消注册)
* @param event - 事件名
* @param handler - 处理器函数
*/
once(event: string, handler: EventHandler): void {
const wrapper: EventHandler = (...args: unknown[]) => {
handler(...args)
this.off(event, wrapper)
}
this.on(event, wrapper)
}
/**
* 取消注册事件处理器
* @param event - 事件名
* @param handler - 要取消的处理器函数
*/
off(event: string, handler: EventHandler): void {
this.handlers.get(event)?.delete(handler)
}
/**
* 发布事件
* @param event - 事件名
* @param args - 传递给处理器的参数
*/
emit(event: string, ...args: unknown[]): void {
const handlers = this.handlers.get(event)
if (!handlers) return
handlers.forEach((handler) => {
handler(...args)
})
}
/**
* 清除指定事件的所有处理器,或清除所有事件
* @param event - 可选,不传则清除全部
*/
clear(event?: string): void {
if (event) {
this.handlers.delete(event)
} else {
this.handlers.clear()
}
}
}
/** 事件总线单例 */
export const eventBus = new EventBus()