feat: 全站 PageShell 设计系统与专业 UI 统一
- 新增 PageShell/PageTabs/ContentPanel/PageLoading/PageEmpty 页面骨架 - index.css 设计令牌文档化,布局令牌与纯色主按钮(去除渐变粉彩) - 全站路由页接入 PageShell,云账单三 Tab 为标杆 - 主题体系:跟随系统 + 主流/开发者分组,新增 Dracula/Tokyo Night,One Dark 暖灰差异化 - 登录页/侧栏/顶栏去渐变光球,企业克制风 - 修复 AIAlertAnalyzer JSX 与构建依赖导入问题
This commit is contained in:
1 parent
1acb0c49af
commit
e363ded445
213 files changed
+7148
-6818
No files matched your search
@@ -31,12 +31,14 @@ import {
|
||||
import {
|
||||
Select, SelectContent, SelectItem, SelectTrigger, SelectValue
|
||||
} from '@/components/ui/select';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
import { toast } from 'sonner';
|
||||
import { traceApi } from '@/api';
|
||||
import { PageShell } from '@/components/layout/PageShell';
|
||||
import { PageLoading } from '@/components/layout/PageLoading';
|
||||
import { PageEmpty } from '@/components/layout/PageEmpty';
|
||||
import type { JsonData } from '@/types/common';
|
||||
|
||||
interface Trace {
|
||||
@@ -162,7 +164,7 @@ const TraceManager: React.FC = () => {
|
||||
case 'success': return 'bg-green-500';
|
||||
case 'error': return 'bg-red-500';
|
||||
case 'pending': return 'bg-yellow-500';
|
||||
default: return 'bg-gray-500';
|
||||
default: return 'bg-[var(--dg-bg-active)]';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -257,28 +259,14 @@ const TraceManager: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* 统计卡片 */}
|
||||
<StatStrip
|
||||
items={[
|
||||
{ label: '总请求', value: services.reduce((sum, s) => sum + s.requestCount, 0).toLocaleString(), color: 'blue' },
|
||||
{ label: '错误率', value: `${(services.reduce((sum, s) => sum + s.errorRate, 0) / (services.length || 1)).toFixed(2)}%`, color: 'red' },
|
||||
{ label: '平均延迟', value: formatDuration(services.reduce((sum, s) => sum + s.avgDuration, 0) / (services.length || 1)), color: 'amber' },
|
||||
{ label: '服务数', value: services.length, color: 'purple' },
|
||||
]}
|
||||
/>
|
||||
const pageTabs = [
|
||||
{ id: 'traces', label: '链路追踪' },
|
||||
{ id: 'services', label: '服务拓扑' },
|
||||
{ id: 'metrics', label: '性能指标' },
|
||||
];
|
||||
|
||||
<Tabs value={activeTab} onValueChange={setActiveTab}>
|
||||
<TabsList className="grid w-full grid-cols-3 lg:w-[400px]">
|
||||
<TabsTrigger value="traces">链路追踪</TabsTrigger>
|
||||
<TabsTrigger value="services">服务拓扑</TabsTrigger>
|
||||
<TabsTrigger value="metrics">性能指标</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="traces" className="space-y-4">
|
||||
{/* 查询工具栏 */}
|
||||
<div className="flex flex-wrap items-center justify-between gap-4">
|
||||
const tracesToolbar = activeTab === 'traces' ? (
|
||||
<div className="flex flex-wrap items-center justify-between gap-4 w-full">
|
||||
<div className="flex items-center gap-2 flex-1 min-w-[400px]">
|
||||
<div className="relative flex-1">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
|
||||
@@ -324,16 +312,44 @@ const TraceManager: React.FC = () => {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="outline" onClick={fetchTraces}>
|
||||
<RefreshCw className="w-4 h-4 mr-2" />
|
||||
刷新
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="outline" className="dg-btn-secondary" onClick={fetchTraces}>
|
||||
<RefreshCw className="w-4 h-4 mr-2" />
|
||||
刷新
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
) : undefined;
|
||||
|
||||
{/* Trace列表 */}
|
||||
<Card>
|
||||
return (
|
||||
<PageShell
|
||||
variant="list"
|
||||
title="链路追踪"
|
||||
subtitle="分布式链路查询与服务性能分析"
|
||||
icon={<GitBranch className="h-5 w-5" />}
|
||||
tabs={pageTabs}
|
||||
activeTab={activeTab}
|
||||
onTabChange={setActiveTab}
|
||||
toolbar={tracesToolbar}
|
||||
metrics={(
|
||||
<StatStrip
|
||||
items={[
|
||||
{ label: '总请求', value: services.reduce((sum, s) => sum + s.requestCount, 0).toLocaleString(), color: 'blue' },
|
||||
{ label: '错误率', value: `${(services.reduce((sum, s) => sum + s.errorRate, 0) / (services.length || 1)).toFixed(2)}%`, color: 'red' },
|
||||
{ label: '平均延迟', value: formatDuration(services.reduce((sum, s) => sum + s.avgDuration, 0) / (services.length || 1)), color: 'amber' },
|
||||
{ label: '服务数', value: services.length, color: 'purple' },
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
actions={activeTab === 'traces' ? undefined : (
|
||||
<Button variant="outline" className="dg-btn-secondary" onClick={fetchData}>
|
||||
<RefreshCw className="w-4 h-4 mr-2" />
|
||||
刷新
|
||||
</Button>
|
||||
)}
|
||||
>
|
||||
{activeTab === 'traces' && (
|
||||
<Card>
|
||||
<CardContent className="p-0">
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full">
|
||||
@@ -351,17 +367,17 @@ const TraceManager: React.FC = () => {
|
||||
<tbody className="divide-y">
|
||||
{loading ? (
|
||||
<tr>
|
||||
<td colSpan={7} className="px-4 py-8 text-center text-muted-foreground">加载中...</td>
|
||||
<td colSpan={7} className="px-4 py-2"><PageLoading label="加载链路数据..." /></td>
|
||||
</tr>
|
||||
) : filteredTraces.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={7} className="px-4 py-8 text-center text-muted-foreground">暂无链路数据</td>
|
||||
<td colSpan={7} className="px-4 py-2"><PageEmpty title="暂无链路数据" className="py-8" /></td>
|
||||
</tr>
|
||||
) : (
|
||||
filteredTraces.map((trace) => (
|
||||
<tr key={trace.id} className="hover:bg-muted/50">
|
||||
<td className="px-4 py-3">
|
||||
<span className="font-mono text-sm text-blue-500">{trace.traceId.slice(0, 16)}...</span>
|
||||
<span className="font-mono text-sm dg-text-blue">{trace.traceId.slice(0, 16)}...</span>
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
<div className="font-medium">{trace.operationName}</div>
|
||||
@@ -394,9 +410,9 @@ const TraceManager: React.FC = () => {
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
<TabsContent value="services" className="space-y-4">
|
||||
{activeTab === 'services' && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>服务性能概览</CardTitle>
|
||||
@@ -420,7 +436,7 @@ const TraceManager: React.FC = () => {
|
||||
<td className="px-4 py-3 font-medium">{service.serviceName}</td>
|
||||
<td className="px-4 py-3">{service.requestCount.toLocaleString()}</td>
|
||||
<td className="px-4 py-3">
|
||||
<span className={service.errorRate > 1 ? 'text-red-500' : 'text-green-500'}>
|
||||
<span className={service.errorRate > 1 ? 'text-red-500' : 'dg-text-green'}>
|
||||
{service.errorRate.toFixed(2)}%
|
||||
</span>
|
||||
</td>
|
||||
@@ -434,9 +450,9 @@ const TraceManager: React.FC = () => {
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
<TabsContent value="metrics" className="space-y-4">
|
||||
{activeTab === 'metrics' && (
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
@@ -457,8 +473,7 @@ const TraceManager: React.FC = () => {
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
)}
|
||||
|
||||
{/* Trace详情对话框 */}
|
||||
<Dialog open={traceDetailOpen} onOpenChange={setTraceDetailOpen}>
|
||||
@@ -580,7 +595,7 @@ const TraceManager: React.FC = () => {
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</PageShell>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user