From 976b2a3e4e2093abf67158ade603aed0c6c9d470 Mon Sep 17 00:00:00 2001 From: huangzhuang_3rd Date: Wed, 12 Aug 2026 13:31:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20AI=20Worker=20=E5=B9=B3=E5=8F=B0=20MVP?= =?UTF-8?q?=20v1.0.0=20-=20=E5=A4=9A=E7=A7=9F=E6=88=B7/=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E7=AE=A1=E7=90=86/AI=20Worker/=E4=BB=BB=E5=8A=A1=E7=BC=96?= =?UTF-8?q?=E6=8E=92/HITL=E5=AE=A1=E6=A0=B8/=E6=88=90=E6=9C=AC=E6=B2=BB?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/Dashboard.tsx | 186 +++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 frontend/src/pages/Dashboard.tsx diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx new file mode 100644 index 0000000..9359cb8 --- /dev/null +++ b/frontend/src/pages/Dashboard.tsx @@ -0,0 +1,186 @@ +import { useEffect, useState } from 'react'; +import { Row, Col, Card, Statistic, Table, Tag, Space, Spin, Typography } from 'antd'; +import { + ProjectOutlined, + CheckCircleOutlined, + RobotOutlined, + AuditOutlined, + DollarOutlined, + ClockCircleOutlined, +} from '@ant-design/icons'; +import { dashboardApi } from '@/api'; +import type { DashboardStats, Task } from '@/types'; +import { TaskStatusTag } from '@/components/constants'; +import { useNavigate } from 'react-router-dom'; +import dayjs from 'dayjs'; + +const { Title } = Typography; + +export default function Dashboard() { + const navigate = useNavigate(); + const [loading, setLoading] = useState(true); + const [stats, setStats] = useState(null); + + useEffect(() => { + setLoading(true); + dashboardApi + .stats() + .then(setStats) + .finally(() => setLoading(false)); + }, []); + + if (loading) { + return ( +
+ +
+ ); + } + + if (!stats) { + return
暂无数据
; + } + + const taskStatusCols = Object.entries(stats.tasks_by_status || {}); + + const recentTaskColumns = [ + { + title: '任务名称', + dataIndex: 'title', + key: 'title', + render: (text: string, record: Task) => ( + navigate('/tasks')}>{text || record.id.slice(0, 8)} + ), + }, + { + title: '状态', + dataIndex: 'status', + key: 'status', + render: (status: Task['status']) => , + }, + { + title: '创建时间', + dataIndex: 'created_at', + key: 'created_at', + render: (t: string) => dayjs(t).format('YYYY-MM-DD HH:mm'), + }, + ]; + + return ( +
+ + 仪表盘 + + + + + + } + /> + + + + + } + valueStyle={{ color: '#1677ff' }} + /> + + + + + } + valueStyle={{ color: '#722ed1' }} + /> + + + + + } + valueStyle={{ color: '#fa8c16' }} + suffix="元" + /> + + + + + + + + + {taskStatusCols.length > 0 ? ( + taskStatusCols.map(([status, count]) => ( +
+ + {count} +
+ )) + ) : ( + 暂无任务数据 + )} +
+
+ + + + +
+ + + 已完成任务 + + {stats.tasks_by_status?.done || 0} +
+
+ + + 进行中任务 + + {stats.tasks_by_status?.in_progress || 0} +
+
+ + + 项目总数 + + {stats.projects || 0} +
+
+
+ +
+ + {stats.recent_tasks && stats.recent_tasks.length > 0 && ( + + + + )} + + ); +}