From 53c8c27ee772794c4b27b76256198c0b1d1fc6cd Mon Sep 17 00:00:00 2001 From: lintsinghua Date: Thu, 27 Nov 2025 21:33:51 +0800 Subject: [PATCH] feat: Implement retro-futuristic UI design across frontend pages and components. --- frontend/src/assets/styles/globals.css | 133 ++- .../src/components/audit/CreateTaskDialog.tsx | 389 ++++---- .../audit/TerminalProgressDialog.tsx | 208 ++-- frontend/src/components/layout/Sidebar.tsx | 85 +- .../components/reports/ExportReportDialog.tsx | 77 +- .../src/components/system/SystemConfig.tsx | 370 +++---- frontend/src/pages/AdminDashboard.tsx | 304 +++--- frontend/src/pages/AuditTasks.tsx | 417 ++++---- frontend/src/pages/Dashboard.tsx | 505 +++++----- frontend/src/pages/InstantAnalysis.tsx | 394 ++++---- frontend/src/pages/Login.tsx | 126 ++- frontend/src/pages/ProjectDetail.tsx | 797 ++++++++------- frontend/src/pages/Projects.tsx | 940 +++++++++--------- frontend/src/pages/RecycleBin.tsx | 170 ++-- frontend/src/pages/TaskDetail.tsx | 406 ++++---- frontend/src/shared/api/database.ts | 22 +- frontend/tailwind.config.js | 139 +-- 17 files changed, 2787 insertions(+), 2695 deletions(-) diff --git a/frontend/src/assets/styles/globals.css b/frontend/src/assets/styles/globals.css index 88890ba..b168702 100644 --- a/frontend/src/assets/styles/globals.css +++ b/frontend/src/assets/styles/globals.css @@ -4,48 +4,65 @@ @layer base { :root { - --background: 0 0% 100%; - --foreground: 222.2 84% 4.9%; + --background: 210 20% 98%; + --foreground: 220 10% 10%; + --card: 0 0% 100%; - --card-foreground: 222.2 84% 4.9%; + --card-foreground: 220 10% 10%; + --popover: 0 0% 100%; - --popover-foreground: 222.2 84% 4.9%; - --primary: 222.2 47.4% 11.2%; - --primary-foreground: 210 40% 98%; - --secondary: 210 40% 96.1%; - --secondary-foreground: 222.2 47.4% 11.2%; - --muted: 210 40% 96.1%; - --muted-foreground: 215.4 16.3% 46.9%; - --accent: 210 40% 96.1%; - --accent-foreground: 222.2 47.4% 11.2%; - --destructive: 0 84.2% 60.2%; - --destructive-foreground: 210 40% 98%; - --border: 214.3 31.8% 91.4%; - --input: 214.3 31.8% 91.4%; - --ring: 222.2 84% 4.9%; - --radius: 0.5rem; + --popover-foreground: 220 10% 10%; + + --primary: 220 100% 50%; + --primary-foreground: 0 0% 100%; + + --secondary: 15 100% 50%; + --secondary-foreground: 0 0% 100%; + + --muted: 210 20% 90%; + --muted-foreground: 220 10% 40%; + + --accent: 180 100% 40%; + --accent-foreground: 0 0% 100%; + + --destructive: 0 100% 50%; + --destructive-foreground: 0 0% 100%; + + --border: 0 0% 0%; + --input: 0 0% 0%; + --ring: 220 100% 50%; + + --radius: 0rem; } .dark { - --background: 222.2 84% 4.9%; - --foreground: 210 40% 98%; - --card: 222.2 84% 4.9%; - --card-foreground: 210 40% 98%; - --popover: 222.2 84% 4.9%; - --popover-foreground: 210 40% 98%; - --primary: 210 40% 98%; - --primary-foreground: 222.2 47.4% 11.2%; - --secondary: 217.2 32.6% 17.5%; - --secondary-foreground: 210 40% 98%; - --muted: 217.2 32.6% 17.5%; - --muted-foreground: 215 20.2% 65.1%; - --accent: 217.2 32.6% 17.5%; - --accent-foreground: 210 40% 98%; - --destructive: 0 62.8% 30.6%; - --destructive-foreground: 210 40% 98%; - --border: 217.2 32.6% 17.5%; - --input: 217.2 32.6% 17.5%; - --ring: 212.7 26.8% 83.9%; + --background: 220 10% 10%; + --foreground: 210 20% 98%; + + --card: 220 10% 15%; + --card-foreground: 210 20% 98%; + + --popover: 220 10% 15%; + --popover-foreground: 210 20% 98%; + + --primary: 220 100% 50%; + --primary-foreground: 0 0% 100%; + + --secondary: 15 100% 50%; + --secondary-foreground: 0 0% 100%; + + --muted: 220 10% 20%; + --muted-foreground: 210 20% 60%; + + --accent: 180 100% 40%; + --accent-foreground: 0 0% 100%; + + --destructive: 0 100% 50%; + --destructive-foreground: 0 0% 100%; + + --border: 0 0% 100%; + --input: 0 0% 100%; + --ring: 220 100% 50%; } } @@ -53,8 +70,48 @@ * { @apply border-border; } + body { - @apply bg-background text-foreground; + @apply bg-background text-foreground font-mono antialiased; + } + + h1, + h2, + h3, + h4, + h5, + h6 { + @apply font-display font-bold tracking-tight; } } +@layer utilities { + .retro-border { + @apply border-2 border-black; + box-shadow: 4px 4px 0px 0px rgba(0, 0, 0, 1); + } + + .retro-card { + @apply bg-white border-2 border-black p-4; + box-shadow: 4px 4px 0px 0px rgba(0, 0, 0, 1); + } + + .retro-btn { + @apply bg-primary text-white font-bold py-2 px-4 border-2 border-black transition-all; + box-shadow: 4px 4px 0px 0px rgba(0, 0, 0, 1); + } + + .retro-btn:hover { + box-shadow: 2px 2px 0px 0px rgba(0, 0, 0, 1); + transform: translate(2px, 2px); + } + + .retro-btn:active { + box-shadow: none; + transform: translate(4px, 4px); + } + + .retro-input { + @apply bg-white border-2 border-black p-2 focus:outline-none focus:ring-2 focus:ring-primary shadow-none; + } +} \ No newline at end of file diff --git a/frontend/src/components/audit/CreateTaskDialog.tsx b/frontend/src/components/audit/CreateTaskDialog.tsx index 4d6d70a..dde9778 100644 --- a/frontend/src/components/audit/CreateTaskDialog.tsx +++ b/frontend/src/components/audit/CreateTaskDialog.tsx @@ -6,7 +6,6 @@ import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Checkbox } from "@/components/ui/checkbox"; import { Badge } from "@/components/ui/badge"; -import { Card, CardContent } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { GitBranch, @@ -208,7 +207,7 @@ export default function CreateTaskDialog({ open, onOpenChange, onTaskCreated, pr console.log('✅ 任务创建成功:', taskId); // 记录用户操作 - import('@/shared/utils/logger').then(({ logger, LogCategory }) => { + import('@/shared/utils/logger').then(({ logger }) => { logger.logUserAction('创建审计任务', { taskId, projectId: project.id, @@ -299,76 +298,74 @@ export default function CreateTaskDialog({ open, onOpenChange, onTaskCreated, pr return ( - - - - + + + + 新建审计任务 -
+
{/* 项目选择 */}
- - + + {filteredProjects.length} 个可用项目
{/* 项目搜索 */}
- + setSearchTerm(e.target.value)} - className="pl-10" + className="pl-10 retro-input h-10" />
{/* 项目列表 */} -
+
{loading ? (
-
+
) : filteredProjects.length > 0 ? ( filteredProjects.map((project) => ( - setTaskForm({ ...taskForm, project_id: project.id })} > - -
-
-

{project.name}

- {project.description && ( -

- {project.description} -

- )} -
- {project.repository_type?.toUpperCase() || 'OTHER'} - {project.default_branch} -
-
- {taskForm.project_id === project.id && ( -
-
-
+
+
+

{project.name}

+ {project.description && ( +

+ {project.description} +

)} +
+ {project.repository_type?.toUpperCase() || 'OTHER'} + {project.default_branch} +
- - + {taskForm.project_id === project.id && ( +
+
+
+ )} +
+
)) ) : ( -
+

{searchTerm ? '未找到匹配的项目' : '暂无可用项目'} @@ -381,133 +378,141 @@ export default function CreateTaskDialog({ open, onOpenChange, onTaskCreated, pr {/* 任务配置 */} {selectedProject && ( - - + + 基础配置 - + 排除规则 - + 高级选项 - + {/* ZIP项目文件上传 */} {(!selectedProject.repository_url || selectedProject.repository_url.trim() === '') && ( - - -

- {loadingZipFile ? ( -
-
-

正在加载保存的ZIP文件...

+
+
+ {loadingZipFile ? ( +
+
+

正在加载保存的ZIP文件...

+
+ ) : zipFile ? ( +
+ +
+

已准备就绪

+

+ 使用保存的ZIP文件: {zipFile.name} ( + {zipFile.size >= 1024 * 1024 + ? `${(zipFile.size / 1024 / 1024).toFixed(2)} MB` + : zipFile.size >= 1024 + ? `${(zipFile.size / 1024).toFixed(2)} KB` + : `${zipFile.size} B` + }) +

- ) : zipFile ? ( -
- -
-

已准备就绪

-

- 使用保存的ZIP文件: {zipFile.name} ( - {zipFile.size >= 1024 * 1024 - ? `${(zipFile.size / 1024 / 1024).toFixed(2)} MB` - : zipFile.size >= 1024 - ? `${(zipFile.size / 1024).toFixed(2)} KB` - : `${zipFile.size} B` - }) + +

+ ) : ( + <> +
+ +
+

需要上传ZIP文件

+

+ 未找到保存的ZIP文件,请上传文件进行扫描

-
- ) : ( - <> -
- -
-

需要上传ZIP文件

-

- 未找到保存的ZIP文件,请上传文件进行扫描 -

-
-
-
- - { - const file = e.target.files?.[0]; - if (file) { - console.log('📁 选择的文件:', { - name: file.name, - size: file.size, - type: file.type, - sizeMB: (file.size / 1024 / 1024).toFixed(2) - }); +
+ + { + const file = e.target.files?.[0]; + if (file) { + console.log('📁 选择的文件:', { + name: file.name, + size: file.size, + type: file.type, + sizeMB: (file.size / 1024 / 1024).toFixed(2) + }); - const validation = validateZipFile(file); - if (!validation.valid) { - toast.error(validation.error || "文件无效"); - e.target.value = ''; - return; - } - setZipFile(file); - setHasLoadedZip(true); - - const sizeMB = (file.size / 1024 / 1024).toFixed(2); - const sizeKB = (file.size / 1024).toFixed(2); - const sizeText = file.size >= 1024 * 1024 ? `${sizeMB} MB` : `${sizeKB} KB`; - - toast.success(`已选择文件: ${file.name} (${sizeText})`); + const validation = validateZipFile(file); + if (!validation.valid) { + toast.error(validation.error || "文件无效"); + e.target.value = ''; + return; } - }} - className="cursor-pointer" - /> -
- - )} -
- - + setZipFile(file); + setHasLoadedZip(true); + + const sizeMB = (file.size / 1024 / 1024).toFixed(2); + const sizeKB = (file.size / 1024).toFixed(2); + const sizeText = file.size >= 1024 * 1024 ? `${sizeMB} MB` : `${sizeKB} KB`; + + toast.success(`已选择文件: ${file.name} (${sizeText})`); + } + }} + className="cursor-pointer retro-input pt-1.5" + /> +
+ + )} +
+
)}
- + setTaskForm({ ...taskForm, branch_name: e.target.value })} placeholder={selectedProject.default_branch || "main"} + className="retro-input h-10" />
)}
{/* 项目信息展示 */} - - -
- -
-

选中项目:{selectedProject.name}

-
- {selectedProject.description && ( -

描述:{selectedProject.description}

- )} -

默认分支:{selectedProject.default_branch}

- {selectedProject.programming_languages && ( -

编程语言:{JSON.parse(selectedProject.programming_languages).join(', ')}

- )} -
+
+
+ +
+

选中项目:{selectedProject.name}

+
+ {selectedProject.description && ( +

描述:{selectedProject.description}

+ )} +

默认分支:{selectedProject.default_branch}

+ {selectedProject.programming_languages && ( +

编程语言:{JSON.parse(selectedProject.programming_languages).join(', ')}

+ )}
- - +
+
- +
- -

+ +

选择要从审计中排除的文件和目录模式

@@ -561,14 +565,15 @@ export default function CreateTaskDialog({ open, onOpenChange, onTaskCreated, pr {/* 常用排除模式 */}
{commonExcludePatterns.map((pattern) => ( -
+
toggleExcludePattern(pattern.value)} + className="rounded-none border-2 border-black data-[state=checked]:bg-primary data-[state=checked]:text-white" />
-

{pattern.label}

-

{pattern.description}

+

{pattern.label}

+

{pattern.description}

))} @@ -576,7 +581,7 @@ export default function CreateTaskDialog({ open, onOpenChange, onTaskCreated, pr {/* 自定义排除模式 */}
- +
@@ -604,13 +611,13 @@ export default function CreateTaskDialog({ open, onOpenChange, onTaskCreated, pr {/* 已选择的排除模式 */} {taskForm.exclude_patterns.length > 0 && (
- +
{taskForm.exclude_patterns.map((pattern) => ( removeExcludePattern(pattern)} > {pattern} × @@ -622,18 +629,18 @@ export default function CreateTaskDialog({ open, onOpenChange, onTaskCreated, pr
- +
- -

+ +

配置代码扫描的详细参数

-
+
@@ -642,14 +649,15 @@ export default function CreateTaskDialog({ open, onOpenChange, onTaskCreated, pr scan_config: { ...taskForm.scan_config, include_tests: !!checked } }) } + className="rounded-none border-2 border-black data-[state=checked]:bg-primary data-[state=checked]:text-white" />
-

包含测试文件

-

扫描 *test*, *spec* 等测试文件

+

包含测试文件

+

扫描 *test*, *spec* 等测试文件

-
+
@@ -658,17 +666,18 @@ export default function CreateTaskDialog({ open, onOpenChange, onTaskCreated, pr scan_config: { ...taskForm.scan_config, include_docs: !!checked } }) } + className="rounded-none border-2 border-black data-[state=checked]:bg-primary data-[state=checked]:text-white" />
-

包含文档文件

-

扫描 README, docs 等文档文件

+

包含文档文件

+

扫描 README, docs 等文档文件

- +
- +
@@ -712,39 +722,42 @@ export default function CreateTaskDialog({ open, onOpenChange, onTaskCreated, pr
{/* 分析深度说明 */} - - -
- -
-

分析深度说明:

-
    -
  • 基础扫描:快速检查语法错误和基本问题
  • -
  • 标准扫描:包含代码质量、安全性和性能分析
  • -
  • 深度扫描:全面分析,包含复杂度、可维护性等高级指标
  • -
-
+
+
+ +
+

分析深度说明:

+
    +
  • 基础扫描:快速检查语法错误和基本问题
  • +
  • 标准扫描:包含代码质量、安全性和性能分析
  • +
  • 深度扫描:全面分析,包含复杂度、可维护性等高级指标
  • +
- - +
+
)} {/* 操作按钮 */} -
-
{/* 终端内容 */} -
-
+
+ {/* 扫描线效果 */} +
+ +
{logs.map((log, index) => ( -
- +
+ [{log.timestamp}] - + + {log.type === 'info' && '> '} + {log.type === 'success' && '✓ '} + {log.type === 'error' && '✗ '} + {log.type === 'warning' && '! '} {log.message}
@@ -466,107 +468,63 @@ export default function TerminalProgressDialog({ {/* 光标旋转闪烁效果 */} {!isCompleted && !isFailed && ( -
- [{currentTime}] - +
+ [{currentTime}] + _
)} - {/* 添加自定义动画 */} - -
{/* 底部控制和提示 */} -
-
- - {isCancelled ? "🛑 任务已取消,已分析的结果已保存" : - isCompleted ? "✅ 任务已完成,可以关闭此窗口" : - isFailed ? "❌ 任务失败,请检查配置后重试" : - "⏳ 审计进行中,请勿关闭窗口,过程可能较慢,请耐心等待......"} +
+
+
+ + {isCancelled ? "STATUS: CANCELLED // 任务已取消" : + isCompleted ? "STATUS: COMPLETED // 任务已完成" : + isFailed ? "STATUS: FAILED // 任务失败" : + "STATUS: RUNNING // 审计进行中..."} +
-
- {/* 运行中显示取消按钮 */} - {!isCompleted && !isFailed && !isCancelled && ( - - )} +
+ {/* 运行中显示取消按钮 */} + {!isCompleted && !isFailed && !isCancelled && ( + + )} - {/* 失败时显示查看日志按钮 */} - {isFailed && ( - - )} + {/* 失败时显示查看日志按钮 */} + {isFailed && ( + + )} - {/* 已完成/失败/取消显示关闭按钮 */} - {(isCompleted || isFailed || isCancelled) && ( - - )} -
+ {/* 已完成/失败/取消显示关闭按钮 */} + {(isCompleted || isFailed || isCancelled) && ( + + )}
diff --git a/frontend/src/components/layout/Sidebar.tsx b/frontend/src/components/layout/Sidebar.tsx index eb9b469..b58c583 100644 --- a/frontend/src/components/layout/Sidebar.tsx +++ b/frontend/src/components/layout/Sidebar.tsx @@ -13,7 +13,8 @@ import { FileText, ChevronLeft, ChevronRight, - Github + Github, + Terminal } from "lucide-react"; import routes from "@/app/routes"; @@ -45,7 +46,7 @@ export default function Sidebar({ collapsed, setCollapsed }: SidebarProps) { +
{/* Navigation */} -