diff --git a/src/components/monitoring/ResourceMonitor.tsx b/src/components/monitoring/ResourceMonitor.tsx
new file mode 100644
index 00000000..5596770e
--- /dev/null
+++ b/src/components/monitoring/ResourceMonitor.tsx
@@ -0,0 +1,294 @@
+/**
+ * 资源监控组件
+ *
+ * 显示系统资源使用情况,包括:
+ * - CPU 使用率(带历史图表)
+ * - 内存使用率(带历史图表)
+ * - 磁盘使用率(带历史图表)
+ */
+
+'use client'
+
+import React from 'react'
+import { Cpu, HardDrive, MemoryStick, TrendingUp, TrendingDown, Minus } from 'lucide-react'
+import Card from '@/components/ui/Card'
+import { Title3, Body, Caption1 } from '@/components/ui/Typography'
+import ProgressBar from '@/components/ui/ProgressBar'
+
+export interface ResourceData {
+ current: number // 当前使用百分比
+ history: number[] // 历史数据点(最近N个)
+ total?: number // 总量(MB)
+ used?: number // 已用(MB)
+ free?: number // 空闲(MB)
+}
+
+export interface ResourceMonitorProps {
+ cpu?: ResourceData
+ memory?: ResourceData
+ disk?: ResourceData
+ cpuCores?: number
+ className?: string
+ showHistory?: boolean
+ historyPoints?: number
+}
+
+export default function ResourceMonitor({
+ cpu,
+ memory,
+ disk,
+ cpuCores,
+ className = '',
+ showHistory = true,
+ historyPoints = 20,
+}: ResourceMonitorProps) {
+ return (
+
+ {/* CPU 监控 */}
+ {cpu && (
+ }
+ title="CPU 使用率"
+ subtitle={cpuCores ? `${cpuCores} 核心` : undefined}
+ data={cpu}
+ showHistory={showHistory}
+ historyPoints={historyPoints}
+ unit="%"
+ warningThreshold={70}
+ criticalThreshold={90}
+ />
+ )}
+
+ {/* 内存监控 */}
+ {memory && (
+ }
+ title="内存使用率"
+ subtitle={memory.total ? `${formatMB(memory.used || 0)} / ${formatMB(memory.total)}` : undefined}
+ data={memory}
+ showHistory={showHistory}
+ historyPoints={historyPoints}
+ unit="%"
+ warningThreshold={75}
+ criticalThreshold={90}
+ />
+ )}
+
+ {/* 磁盘监控 */}
+ {disk && (
+ }
+ title="磁盘使用率"
+ subtitle={disk.total ? `${formatMB(disk.used || 0)} / ${formatMB(disk.total)}` : undefined}
+ data={disk}
+ showHistory={showHistory}
+ historyPoints={historyPoints}
+ unit="%"
+ warningThreshold={80}
+ criticalThreshold={95}
+ />
+ )}
+
+ )
+}
+
+interface ResourceCardProps {
+ icon: React.ReactNode
+ title: string
+ subtitle?: string
+ data: ResourceData
+ showHistory: boolean
+ historyPoints: number
+ unit: string
+ warningThreshold: number
+ criticalThreshold: number
+}
+
+function ResourceCard({
+ icon,
+ title,
+ subtitle,
+ data,
+ showHistory,
+ historyPoints,
+ unit,
+ warningThreshold,
+ criticalThreshold,
+}: ResourceCardProps) {
+ const getStatusType = (value: number) => {
+ if (value >= criticalThreshold) return 'error'
+ if (value >= warningThreshold) return 'warning'
+ return 'success'
+ }
+
+ const getTrend = () => {
+ if (data.history.length < 2) return 'stable'
+ const recent = data.history.slice(-5)
+ const avg = recent.reduce((a, b) => a + b, 0) / recent.length
+ const diff = data.current - avg
+ if (diff > 5) return 'up'
+ if (diff < -5) return 'down'
+ return 'stable'
+ }
+
+ const trend = getTrend()
+
+ return (
+
+
+
+
{icon}
+
+ {title}
+ {subtitle && (
+
+ {subtitle}
+
+ )}
+
+
+
+
+ {data.current.toFixed(1)}{unit}
+
+ {trend === 'up' && }
+ {trend === 'down' && }
+ {trend === 'stable' && }
+
+
+
+ {/* 进度条 */}
+
+
+ {/* 历史图表 */}
+ {showHistory && data.history.length > 0 && (
+
+
+
+ )}
+
+ )
+}
+
+interface MiniChartProps {
+ data: number[]
+ warningThreshold: number
+ criticalThreshold: number
+}
+
+function MiniChart({ data, warningThreshold, criticalThreshold }: MiniChartProps) {
+ const height = 40
+ const width = 200
+ const padding = 2
+
+ if (data.length === 0) return null
+
+ const max = 100
+ const min = 0
+ const range = max - min
+
+ const points = data.map((value, index) => {
+ const x = padding + (index / (data.length - 1 || 1)) * (width - padding * 2)
+ const y = height - padding - ((value - min) / range) * (height - padding * 2)
+ return `${x},${y}`
+ }).join(' ')
+
+ const getColor = (value: number) => {
+ if (value >= criticalThreshold) return 'var(--color-red)'
+ if (value >= warningThreshold) return 'var(--color-orange)'
+ return 'var(--color-green)'
+ }
+
+ // 创建渐变区域
+ const areaPoints = `${padding},${height - padding} ${points} ${width - padding},${height - padding}`
+
+ return (
+
+
+
+
+ {data.length > 0 ? `最低 ${Math.min(...data).toFixed(0)}%` : ''}
+
+
+ {data.length > 0 ? `最高 ${Math.max(...data).toFixed(0)}%` : ''}
+
+
+
+ )
+}
+
+function formatMB(mb: number): string {
+ if (mb >= 1024) {
+ return `${(mb / 1024).toFixed(1)} GB`
+ }
+ return `${mb.toFixed(0)} MB`
+}
diff --git a/src/components/monitoring/ServiceStatusCard.tsx b/src/components/monitoring/ServiceStatusCard.tsx
new file mode 100644
index 00000000..6e9f1cf1
--- /dev/null
+++ b/src/components/monitoring/ServiceStatusCard.tsx
@@ -0,0 +1,124 @@
+/**
+ * 服务状态卡片组件
+ *
+ * 显示单个服务的状态信息,包括:
+ * - 服务名称和状态指示器
+ * - 响应时间显示
+ * - 错误信息显示
+ */
+
+'use client'
+
+import React from 'react'
+import { CheckCircle, XCircle, AlertTriangle, Loader2, Clock } from 'lucide-react'
+import Card from '@/components/ui/Card'
+import { Title3, Body, Caption1 } from '@/components/ui/Typography'
+import Badge from '@/components/ui/Badge'
+
+export interface ServiceStatus {
+ name: string
+ status: 'healthy' | 'unhealthy' | 'degraded' | 'unknown' | 'loading'
+ responseTime?: number // 毫秒
+ lastChecked?: Date
+ errorMessage?: string
+ details?: Record
+}
+
+interface ServiceStatusCardProps {
+ service: ServiceStatus
+ className?: string
+}
+
+export default function ServiceStatusCard({ service, className = '' }: ServiceStatusCardProps) {
+ const getStatusIcon = () => {
+ switch (service.status) {
+ case 'healthy':
+ return
+ case 'unhealthy':
+ return
+ case 'degraded':
+ return
+ case 'loading':
+ return
+ default:
+ return
+ }
+ }
+
+ const getStatusBadge = () => {
+ const statusMap = {
+ healthy: { type: 'success' as const, label: '正常' },
+ unhealthy: { type: 'error' as const, label: '异常' },
+ degraded: { type: 'warning' as const, label: '降级' },
+ unknown: { type: 'info' as const, label: '未知' },
+ loading: { type: 'info' as const, label: '检查中' },
+ }
+ const config = statusMap[service.status]
+ return {config.label}
+ }
+
+ const getResponseTimeColor = () => {
+ if (!service.responseTime) return 'var(--color-label-tertiary)'
+ if (service.responseTime < 100) return 'var(--color-green)'
+ if (service.responseTime < 500) return 'var(--color-orange)'
+ return 'var(--color-red)'
+ }
+
+ return (
+
+
+
+ {getStatusIcon()}
+ {service.name}
+
+ {getStatusBadge()}
+
+
+ {/* 响应时间 */}
+ {service.responseTime !== undefined && (
+
+
+
+ {service.responseTime}ms
+
+
+ 响应时间
+
+
+ )}
+
+ {/* 最后检查时间 */}
+ {service.lastChecked && (
+
+ 最后检查: {service.lastChecked.toLocaleTimeString()}
+
+ )}
+
+ {/* 错误信息 */}
+ {service.errorMessage && (
+
+
+ {service.errorMessage}
+
+
+ )}
+
+ {/* 详细信息 */}
+ {service.details && Object.keys(service.details).length > 0 && (
+
+ {Object.entries(service.details).map(([key, value]) => (
+
+ {key}
+
+ {typeof value === 'boolean' ? (value ? '是' : '否') : String(value)}
+
+
+ ))}
+
+ )}
+
+ )
+}
diff --git a/src/components/monitoring/index.ts b/src/components/monitoring/index.ts
new file mode 100644
index 00000000..c92418c8
--- /dev/null
+++ b/src/components/monitoring/index.ts
@@ -0,0 +1,9 @@
+/**
+ * 监控组件导出
+ */
+
+export { default as ServiceStatusCard } from './ServiceStatusCard'
+export type { ServiceStatus } from './ServiceStatusCard'
+
+export { default as ResourceMonitor } from './ResourceMonitor'
+export type { ResourceData, ResourceMonitorProps } from './ResourceMonitor'