From efc92ed8e2ea1106f4a8c101583b341f1bc3a1f5 Mon Sep 17 00:00:00 2001 From: dengqichen Date: Sun, 2 Nov 2025 22:59:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BB=A3=E7=A0=81=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E5=99=A8=E8=A1=A8=E5=8D=95=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/Dashboard/index.tsx | 253 +++++++++++++++++- frontend/src/pages/Dashboard/types.ts | 27 +- .../List/components/EditDialog.tsx | 16 -- .../Design/components/NodeConfigModal.tsx | 21 +- 4 files changed, 285 insertions(+), 32 deletions(-) diff --git a/frontend/src/pages/Dashboard/index.tsx b/frontend/src/pages/Dashboard/index.tsx index a25bb8fc..a529e156 100644 --- a/frontend/src/pages/Dashboard/index.tsx +++ b/frontend/src/pages/Dashboard/index.tsx @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { Skeleton } from "@/components/ui/skeleton"; import { cn } from "@/lib/utils"; import { Package, @@ -11,7 +12,11 @@ import { GitBranch, Users, Server, - CheckCircle2 + CheckCircle2, + XCircle, + Clock, + TrendingUp, + History } from "lucide-react"; import { useToast } from '@/components/ui/use-toast'; import { getDeployEnvironments, startDeployment } from './service'; @@ -26,6 +31,63 @@ const LoadingState = () => ( ); +// 格式化持续时间 +const formatDuration = (ms?: number) => { + if (!ms) return '-'; + const seconds = Math.floor(ms / 1000); + const minutes = Math.floor(seconds / 60); + if (minutes > 0) { + return `${minutes}分${seconds % 60}秒`; + } + return `${seconds}秒`; +}; + +// 格式化时间 +const formatTime = (timeStr?: string) => { + if (!timeStr) return '-'; + try { + const date = new Date(timeStr); + return date.toLocaleString('zh-CN', { + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit' + }); + } catch { + return timeStr; + } +}; + +// 获取状态图标和颜色 +const getStatusIcon = (status?: string) => { + switch (status) { + case 'SUCCESS': + return { icon: CheckCircle2, color: 'text-green-600' }; + case 'FAILED': + return { icon: XCircle, color: 'text-red-600' }; + case 'RUNNING': + return { icon: Loader2, color: 'text-blue-600' }; + default: + return { icon: Clock, color: 'text-gray-400' }; + } +}; + +// 获取状态文本 +const getStatusText = (status?: string) => { + switch (status) { + case 'SUCCESS': + return '成功'; + case 'FAILED': + return '失败'; + case 'RUNNING': + return '运行中'; + case 'CANCELLED': + return '已取消'; + default: + return '未知'; + } +}; + const Dashboard: React.FC = () => { const { toast } = useToast(); const [loading, setLoading] = useState(true); @@ -257,45 +319,214 @@ const Dashboard: React.FC = () => {
-

{app.applicationName}

- - {app.applicationCode} - + {app.applicationName ? ( +

{app.applicationName}

+ ) : ( + + )} + {app.applicationCode ? ( + + {app.applicationCode} + + ) : ( + + )}
+ {/* 分支 */}
- {app.branch} + {app.branch ? ( + {app.branch} + ) : ( + + )}
+ {/* 工作流 */}
- {app.workflowDefinitionName || '未配置'} + {app.workflowDefinitionName ? ( + {app.workflowDefinitionName} + ) : ( + + )}
- {app.deploySystemName && ( + {/* Jenkins */} + {app.deploySystemName ? (
{app.deploySystemName}
+ ) : ( +
+ + +
+ )} +
+ + {/* 部署统计信息 */} +
+
+ {/* 总次数 */} +
+ {app.deployStatistics ? ( + <> +
+ + {app.deployStatistics.totalCount ?? 0} +
+
总次数
+ + ) : ( + <> + + + + )} +
+ + {/* 成功次数 */} +
+ {app.deployStatistics ? ( + <> +
+ + {app.deployStatistics.successCount ?? 0} +
+
成功
+ + ) : ( + <> + + + + )} +
+ + {/* 失败次数 */} +
+ {app.deployStatistics ? ( + <> +
+ + {app.deployStatistics.failedCount ?? 0} +
+
失败
+ + ) : ( + <> + + + + )} +
+
+ + {/* 最近部署信息 */} + {app.deployStatistics ? ( +
+ + {app.deployStatistics.lastDeployTime ? ( + <> + 最近: {formatTime(app.deployStatistics.lastDeployTime)} + {app.deployStatistics.lastDeployBy ? ( + by {app.deployStatistics.lastDeployBy} + ) : ( + + )} + {app.deployStatistics.latestStatus ? (() => { + const { icon: StatusIcon, color } = getStatusIcon(app.deployStatistics.latestStatus); + return ( + + + {getStatusText(app.deployStatistics.latestStatus)} + + ); + })() : ( + + )} + + ) : ( + + )} +
+ ) : ( +
+ + +
+ )} + + {/* 最近部署记录 */} + {app.recentDeployRecords && app.recentDeployRecords.length > 0 ? ( +
+
+ + 最近记录 +
+ {app.recentDeployRecords.slice(0, 2).map((record) => { + const { icon: StatusIcon, color } = getStatusIcon(record.status); + return ( +
+
+ + {record.startTime ? ( + <> + {formatTime(record.startTime)} + {record.deployRemark && ( + - {record.deployRemark} + )} + + ) : ( + + )} +
+ {record.duration ? ( + + {formatDuration(record.duration)} + + ) : ( + + )} +
+ ); + })} +
+ ) : ( +
+
+ + 最近记录 +
+ {/* 显示2条骨架记录 */} + {[1, 2].map((i) => ( +
+ + +
+ ))} +
)}