- 使用 shadcn/ui 重新实现 TopBar、ThemeSidebar、AlertBadge 组件 - 解决 @oicl/openbridge-webcomponents ESM 模块解析问题 - 添加 OpenBridge 四种主题 CSS 变量 (day/bright/dusk/night) - Night 主题使用暗黄色文字保护夜视能力 - 更新 API 端点适配新的按模型分组数据结构
141 lines
3.6 KiB
TypeScript
141 lines
3.6 KiB
TypeScript
/**
|
||
* 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>
|
||
)
|
||
}
|