feat: 替换 OpenBridge 组件并实现航海规范主题系统

- 使用 shadcn/ui 重新实现 TopBar、ThemeSidebar、AlertBadge 组件
- 解决 @oicl/openbridge-webcomponents ESM 模块解析问题
- 添加 OpenBridge 四种主题 CSS 变量 (day/bright/dusk/night)
- Night 主题使用暗黄色文字保护夜视能力
- 更新 API 端点适配新的按模型分组数据结构
This commit is contained in:
2026-01-26 21:17:56 +08:00
parent fa625ca301
commit d22a0f8d69
14 changed files with 1025 additions and 219 deletions

View File

@@ -0,0 +1,140 @@
/**
* 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>
)
}