c3f160afa5
error-bus 提供框架无关的订阅式错误总线:notify/dismiss/clear、负载归一化、 3 条上限截断、订阅返回取消函数防泄漏;GlobalErrorContainer 订阅并渲染可关闭 错误条,挂在 AdminLayout 内容区顶部。
57 lines
1.6 KiB
TypeScript
57 lines
1.6 KiB
TypeScript
/** 全局请求错误提示容器(任务 13):框架无关的订阅式错误总线。 */
|
|
|
|
export interface GlobalErrorItem {
|
|
id: number
|
|
message: string
|
|
}
|
|
|
|
export const GLOBAL_ERROR_LIMIT = 3
|
|
export const GLOBAL_ERROR_FALLBACK = '请求失败,请稍后重试'
|
|
|
|
/** 把任意负载归一化为可展示文案。 */
|
|
export function normalizeErrorMessage(message: unknown): string {
|
|
if (message instanceof Error) return message.message.trim() || GLOBAL_ERROR_FALLBACK
|
|
if (typeof message === 'string') return message.trim() || GLOBAL_ERROR_FALLBACK
|
|
return GLOBAL_ERROR_FALLBACK
|
|
}
|
|
|
|
type Listener = (items: GlobalErrorItem[]) => void
|
|
|
|
let items: GlobalErrorItem[] = []
|
|
let nextId = 1
|
|
const listeners = new Set<Listener>()
|
|
|
|
function emit(): void {
|
|
for (const listener of listeners) listener(items.slice())
|
|
}
|
|
|
|
/** 订阅错误流,返回取消订阅函数(组件卸载时必须调用以防泄漏)。 */
|
|
export function subscribeGlobalError(listener: Listener): () => void {
|
|
listeners.add(listener)
|
|
listener(items.slice())
|
|
return () => {
|
|
listeners.delete(listener)
|
|
}
|
|
}
|
|
|
|
/** 通知一条全局请求错误;超出上限丢弃最旧,保证不堆积。 */
|
|
export function notifyGlobalError(message: unknown): void {
|
|
items = [...items, { id: nextId++, message: normalizeErrorMessage(message) }].slice(-GLOBAL_ERROR_LIMIT)
|
|
emit()
|
|
}
|
|
|
|
/** 按 id 关闭单条。 */
|
|
export function dismissGlobalError(id: number): void {
|
|
items = items.filter((item) => item.id !== id)
|
|
emit()
|
|
}
|
|
|
|
export function clearGlobalErrors(): void {
|
|
items = []
|
|
emit()
|
|
}
|
|
|
|
export function snapshotGlobalErrors(): GlobalErrorItem[] {
|
|
return items.slice()
|
|
}
|