Files
openbridge-token-usage-viewer/src/components/ui/AlertBadge.tsx
MAO Dongyang d22a0f8d69 feat: 替换 OpenBridge 组件并实现航海规范主题系统
- 使用 shadcn/ui 重新实现 TopBar、ThemeSidebar、AlertBadge 组件
- 解决 @oicl/openbridge-webcomponents ESM 模块解析问题
- 添加 OpenBridge 四种主题 CSS 变量 (day/bright/dusk/night)
- Night 主题使用暗黄色文字保护夜视能力
- 更新 API 端点适配新的按模型分组数据结构
2026-01-26 21:17:56 +08:00

141 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* AlertBadge 组件
*
* 告警徽章组件,显示告警数量和状态。
* 支持三种告警类型Alarm紧急、Warning警告、Caution注意
*/
import { AlertTriangle, Bell, BellOff, XCircle } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { cn } from '@/lib/utils'
/** 告警类型枚举 */
export enum AlertType {
Caution = 'caution',
Warning = 'warning',
Alarm = 'alarm',
}
export interface AlertBadgeProps {
/** 告警数量 */
count: number
/** 告警类型 */
alertType: AlertType
/** 是否静音 */
muted?: boolean
/** 静音按钮点击事件 */
onMuteClick?: () => void
/** 额外的 className */
className?: string
}
/** 告警类型对应的颜色配置 - 使用 OpenBridge CSS 变量 */
const ALERT_COLORS: Record<
AlertType,
{ bgVar: string; textClass: string; icon: typeof AlertTriangle }
> = {
[AlertType.Alarm]: {
bgVar: 'var(--alert-alarm-color, rgb(227, 0, 25))',
textClass: 'text-white',
icon: XCircle,
},
[AlertType.Warning]: {
bgVar: 'var(--alert-warning-color, rgb(254, 148, 19))',
textClass: 'text-white',
icon: AlertTriangle,
},
[AlertType.Caution]: {
bgVar: 'var(--alert-caution-color, rgb(255, 219, 55))',
textClass: 'text-gray-900',
icon: AlertTriangle,
},
}
export const AlertBadge = ({
count,
alertType,
muted = false,
onMuteClick,
className,
}: AlertBadgeProps) => {
const { bgVar, textClass, icon: Icon } = ALERT_COLORS[alertType]
if (count === 0) {
return null
}
return (
<div className={cn('flex items-center gap-1', className)}>
{/* 告警徽章 */}
<div
className={cn(
'flex items-center gap-1.5 px-2.5 py-1 rounded-full',
textClass,
)}
style={{ backgroundColor: bgVar }}
>
<Icon className="size-4" />
<span className="text-sm font-medium">{count}</span>
</div>
{/* 静音按钮 */}
{onMuteClick && (
<Button
variant="ghost"
size="icon-sm"
onClick={onMuteClick}
className={cn(
'hover:bg-[var(--element-hover-color,rgba(0,0,0,0.12))]',
muted && 'opacity-50',
)}
aria-label={muted ? '取消静音' : '静音告警'}
>
{muted ? (
<BellOff className="size-4 text-[var(--element-inactive-color,#707070)]" />
) : (
<Bell className="size-4 text-[var(--element-active-color,#3d3d3d)]" />
)}
</Button>
)}
</div>
)
}
export interface AlertNotificationProps {
/** 账户名 */
account: string
/** 剩余百分比 */
remainingPercent: number
/** 告警类型 */
alertType: AlertType
}
/** 获取告警类型对应的 CSS 变量颜色 */
const getAlertColor = (alertType: AlertType): string => {
switch (alertType) {
case AlertType.Alarm:
return 'var(--alert-alarm-color, rgb(227, 0, 25))'
case AlertType.Warning:
return 'var(--alert-warning-color, rgb(254, 148, 19))'
case AlertType.Caution:
return 'var(--alert-caution-color, rgb(255, 219, 55))'
}
}
export const AlertNotification = ({
account,
remainingPercent,
alertType,
}: AlertNotificationProps) => {
const { icon: Icon } = ALERT_COLORS[alertType]
const alertColor = getAlertColor(alertType)
return (
<div className="flex items-center gap-2 px-3 py-2 text-sm">
<Icon className="size-4 shrink-0" style={{ color: alertColor }} />
<span className="text-[var(--element-active-color,#3d3d3d)]">
{account}: {remainingPercent}%
</span>
</div>
)
}