From 99162168b1d4b03765a785e762942e7f1c0159cd Mon Sep 17 00:00:00 2001 From: wangziqi Date: Sun, 5 Jul 2026 19:53:34 +0800 Subject: [PATCH] feat(dashboard): add classroom/attendance/income stat cards and trend charts - Add second row of stat cards: classroom count, occupancy rate, attendance rate, monthly income - Add ECharts line charts for attendance trend (30-day) and income trend (6-month) - All fields sourced from existing GET /dashboard/stats response (Task 7.1 contract) --- apps/admin/src/pages/Dashboard/index.tsx | 104 ++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/apps/admin/src/pages/Dashboard/index.tsx b/apps/admin/src/pages/Dashboard/index.tsx index 7aecbbf..ce97939 100644 --- a/apps/admin/src/pages/Dashboard/index.tsx +++ b/apps/admin/src/pages/Dashboard/index.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; import { Row, Col, Card, Statistic, DatePicker, Spin, Grid } from 'antd'; -import { TeamOutlined, HomeOutlined, DollarOutlined, CheckCircleOutlined } from '@ant-design/icons'; +import { TeamOutlined, HomeOutlined, DollarOutlined, CheckCircleOutlined, BankOutlined, PercentageOutlined, UserSwitchOutlined } from '@ant-design/icons'; import ReactECharts from 'echarts-for-react'; import dayjs from 'dayjs'; import api from '../../api'; @@ -156,6 +156,49 @@ const DashboardPage: React.FC = () => { ], }; + // 考勤趋势折线图 + const attendanceLineOption = { + tooltip: { trigger: 'axis' }, + grid: { left: 50, right: 20, bottom: 30, top: 10 }, + xAxis: { + type: 'category', + data: (stats?.attendanceTrend || []).map((d: { date: string }) => d.date), + axisLabel: { rotate: 45, fontSize: 10 }, + }, + yAxis: { type: 'value', min: 0, max: 100, axisLabel: { formatter: '{value}%' } }, + series: [ + { + type: 'line', + data: (stats?.attendanceTrend || []).map((d: { rate: string }) => parseFloat(d.rate) || 0), + smooth: true, + lineStyle: { color: '#007AFF', width: 2 }, + itemStyle: { color: '#007AFF' }, + areaStyle: { color: 'rgba(0,122,255,0.1)' }, + }, + ], + }; + + // 收入趋势折线图 + const incomeLineOption = { + tooltip: { trigger: 'axis', valueFormatter: (v: number) => `¥${v.toLocaleString()}` }, + grid: { left: 70, right: 20, bottom: 30, top: 10 }, + xAxis: { + type: 'category', + data: (stats?.incomeTrend || []).map((d: { month: string }) => d.month), + }, + yAxis: { type: 'value', axisLabel: { formatter: (v: number) => `¥${(v / 10000).toFixed(0)}万` } }, + series: [ + { + type: 'line', + data: (stats?.incomeTrend || []).map((d: { amount: number }) => d.amount), + smooth: true, + lineStyle: { color: '#34C759', width: 2 }, + itemStyle: { color: '#34C759' }, + areaStyle: { color: 'rgba(52,199,89,0.1)' }, + }, + ], + }; + if (loading && !stats) return ; @@ -217,6 +260,44 @@ const DashboardPage: React.FC = () => { + + + + } /> + + + + + } + /> + + + + + } + /> + + + + + + + + + {ganttData.length > 0 ? ( { )} + + + + {(stats?.attendanceTrend || []).length > 0 ? ( + + ) : ( +
暂无考勤数据
+ )} +
+ + + + {(stats?.incomeTrend || []).length > 0 ? ( + + ) : ( +
暂无收入数据
+ )} +
+ +
+