t1
This commit is contained in:
137
management/src/components/DashboardTab.tsx
Normal file
137
management/src/components/DashboardTab.tsx
Normal file
@@ -0,0 +1,137 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { api } from '../api';
|
||||
import type { StatsResponse } from '../api';
|
||||
|
||||
interface DashboardTabProps {
|
||||
onNavigate: (tab: string) => void;
|
||||
}
|
||||
|
||||
export const DashboardTab: React.FC<DashboardTabProps> = ({ onNavigate }) => {
|
||||
const [stats, setStats] = useState<StatsResponse | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchStats = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const data = await api.getStats();
|
||||
setStats(data);
|
||||
} catch (err: any) {
|
||||
setError(err.message || 'Không thể tải dữ liệu thống kê');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
fetchStats();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '2rem' }}>
|
||||
<div className="page-header">
|
||||
<div className="page-title">
|
||||
<h1>Tổng Quan Hệ Thống</h1>
|
||||
<p>Giám sát đồng bộ và quản lý lớp học, sinh viên từ hệ thống chính</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{loading && (
|
||||
<div className="empty-state">
|
||||
<div className="sync-spinner" style={{ width: '40px', height: '40px', borderWidth: '3px' }}></div>
|
||||
<p style={{ marginTop: '1rem' }}>Đang tải thông số hệ thống...</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<div className="empty-state" style={{ border: '1px solid rgba(239, 68, 68, 0.2)', backgroundColor: 'rgba(239, 68, 68, 0.05)' }}>
|
||||
<div className="empty-state-icon" style={{ color: 'var(--danger)' }}>⚠️</div>
|
||||
<p style={{ color: 'var(--danger)', fontWeight: 600 }}>Lỗi: {error}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!loading && !error && stats && (
|
||||
<>
|
||||
<div className="stats-grid">
|
||||
<div className="stat-card" onClick={() => onNavigate('classes')} style={{ cursor: 'pointer' }}>
|
||||
<div>
|
||||
<div className="stat-label">Tổng lớp học đã đồng bộ</div>
|
||||
<div className="stat-value">{stats.totalClasses}</div>
|
||||
</div>
|
||||
<div className="stat-icon">🏫</div>
|
||||
</div>
|
||||
|
||||
<div className="stat-card" onClick={() => onNavigate('classes')} style={{ cursor: 'pointer' }}>
|
||||
<div>
|
||||
<div className="stat-label">Lớp đang giảng dạy</div>
|
||||
<div className="stat-value" style={{ color: 'var(--success)' }}>{stats.activeClasses}</div>
|
||||
</div>
|
||||
<div className="stat-icon" style={{ color: 'var(--success)' }}>🟢</div>
|
||||
</div>
|
||||
|
||||
<div className="stat-card" onClick={() => onNavigate('students')} style={{ cursor: 'pointer' }}>
|
||||
<div>
|
||||
<div className="stat-label">Tổng sinh viên đã đồng bộ</div>
|
||||
<div className="stat-value" style={{ color: 'var(--accent-hover)' }}>{stats.totalStudents}</div>
|
||||
</div>
|
||||
<div className="stat-icon">🎓</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fit, minmax(360px, 1fr))',
|
||||
gap: '1.5rem',
|
||||
marginTop: '1rem'
|
||||
}}>
|
||||
<div style={{
|
||||
backgroundColor: 'var(--bg-card)',
|
||||
border: '1px solid var(--border-color)',
|
||||
padding: '2rem',
|
||||
borderRadius: '18px',
|
||||
backdropFilter: 'blur(10px)'
|
||||
}}>
|
||||
<h2 style={{ marginBottom: '1rem', color: 'white', display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
|
||||
🚀 Khởi động nhanh
|
||||
</h2>
|
||||
<p style={{ color: 'var(--text-secondary)', fontSize: '0.95rem', lineHeight: '1.6', marginBottom: '1.5rem' }}>
|
||||
Chào mừng bạn đến với trang quản trị <b>Simple Care</b>.
|
||||
Hệ thống hỗ trợ đồng bộ hóa thông tin tự động từ cổng đào tạo chính (QLĐT), giúp lưu trữ, cập nhật trạng thái lớp học và danh sách sinh viên nội bộ mà không lo ảnh hưởng đến dữ liệu hiện có.
|
||||
</p>
|
||||
<div style={{ display: 'flex', gap: '1rem' }}>
|
||||
<button className="btn btn-primary" onClick={() => onNavigate('classes')}>
|
||||
Quản lý Lớp học
|
||||
</button>
|
||||
<button className="btn btn-secondary" onClick={() => onNavigate('students')}>
|
||||
Danh sách Sinh viên
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
backgroundColor: 'var(--bg-card)',
|
||||
border: '1px solid var(--border-color)',
|
||||
padding: '2rem',
|
||||
borderRadius: '18px',
|
||||
backdropFilter: 'blur(10px)'
|
||||
}}>
|
||||
<h2 style={{ marginBottom: '1rem', color: 'white' }}>📋 Quy trình hoạt động</h2>
|
||||
<ul style={{
|
||||
color: 'var(--text-secondary)',
|
||||
fontSize: '0.95rem',
|
||||
lineHeight: '1.8',
|
||||
paddingLeft: '1.25rem',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '0.5rem'
|
||||
}}>
|
||||
<li><b>Đồng bộ Lớp học:</b> Tải toàn bộ danh sách lớp học và các môn học tương ứng. Đồng thời kéo thông tin sinh viên thuộc từng lớp thông qua bảng kết quả lớp học.</li>
|
||||
<li><b>Quản lý Lớp:</b> Lọc danh sách lớp theo Phân hệ (System ID), Tìm kiếm tên hoặc mã lớp và Bật/Tắt cờ <b>Đang học</b>.</li>
|
||||
<li><b>Đồng bộ Sinh viên:</b> Thực hiện kéo toàn bộ sinh viên trên hệ thống chính (kèm thông tin liên hệ, hệ học) lưu trữ vào Database phục vụ cho học tập và thi cử.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user