message / frontend /src /components /console /IssueList.tsx
hunian
feat: 重构前端控制台和工具页面
a43ac26
Raw
History Blame Contribute Delete
2.65 kB
import React from 'react';
import { cn } from '@/lib/utils';
import { AlertTriangle, Info, XCircle } from 'lucide-react';
/**
* 控制台问题列表组件
* 用于展示错误、警告、信息等诊断问题
*/
export type IssueSeverity = 'error' | 'warning' | 'info';
export interface Issue {
/** 问题唯一标识 */
id: string;
/** 严重程度 */
severity: IssueSeverity;
/** 问题消息 */
message: string;
/** 可选的来源或位置 */
source?: string;
}
interface IssueListProps {
/** 问题列表 */
issues: Issue[];
/** 空状态文案 */
emptyText?: string;
/** 额外的 className */
className?: string;
/** 问题点击回调 */
onIssueClick?: (issue: Issue) => void;
}
// 严重程度图标映射
const severityIcons: Record<IssueSeverity, React.ReactNode> = {
error: <XCircle className="w-3.5 h-3.5 text-console-status-error" />,
warning: <AlertTriangle className="w-3.5 h-3.5 text-console-status-warning" />,
info: <Info className="w-3.5 h-3.5 text-console-status-info" />,
};
// 严重程度背景色映射
const severityBg: Record<IssueSeverity, string> = {
error: 'bg-console-status-error-bg',
warning: 'bg-console-status-warning-bg',
info: 'bg-console-status-info-bg',
};
/**
* 问题列表组件
* 用于控制台中展示诊断问题
*/
export function IssueList({
issues,
emptyText = '暂无问题',
className,
onIssueClick,
}: IssueListProps) {
if (issues.length === 0) {
return (
<div className={cn('py-4 text-center text-xs text-console-text-muted', className)}>
{emptyText}
</div>
);
}
return (
<ul className={cn('space-y-1', className)} role="list">
{issues.map((issue) => (
<li
key={issue.id}
className={cn(
'flex items-start gap-2 px-2 py-1.5 rounded-console-sm text-xs',
severityBg[issue.severity],
onIssueClick && 'cursor-pointer hover:opacity-80'
)}
onClick={() => onIssueClick?.(issue)}
role={onIssueClick ? 'button' : undefined}
tabIndex={onIssueClick ? 0 : undefined}
>
{/* 图标 */}
<span className="mt-0.5 shrink-0" aria-hidden="true">
{severityIcons[issue.severity]}
</span>
{/* 内容 */}
<div className="flex-1 min-w-0">
<span className="text-console-text-primary">{issue.message}</span>
{issue.source && (
<span className="ml-1 text-console-text-muted">
({issue.source})
</span>
)}
</div>
</li>
))}
</ul>
);
}