기존 프로젝트 최초 업로드
This commit is contained in:
@@ -0,0 +1,267 @@
|
||||
// 👨🏫 교사 대시보드. 실시간 출석 확인, 학생 계정 관리 화면으로 가는 메뉴만 담당한다.
|
||||
import 'package:flutter/material.dart';
|
||||
import 'login_screen.dart';
|
||||
import 'teacher_attendance_page.dart';
|
||||
import 'teacher_student_management_page.dart';
|
||||
|
||||
// ==========================================
|
||||
// 👨🏫 4. 선생님 대시보드 (기존 3초 타이머 완벽 유지)
|
||||
// ==========================================
|
||||
class TeacherDashboard extends StatefulWidget {
|
||||
final String? teacherId;
|
||||
final String? teacherName;
|
||||
|
||||
const TeacherDashboard({super.key, this.teacherId, this.teacherName});
|
||||
|
||||
@override
|
||||
State<TeacherDashboard> createState() => _TeacherDashboardState();
|
||||
}
|
||||
|
||||
class _TeacherDashboardState extends State<TeacherDashboard> {
|
||||
// 🧼 [수정] 사용하지 않던 _isLoading 변수를 삭제하여 경고를 완벽히 해결했습니다!
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// 다른 화면에서 null이 넘어왔을 때를 대비한 안전망 방탄 코드
|
||||
final String displayName = widget.teacherName ?? "간편인증 선생";
|
||||
final String displayId = widget.teacherId ?? "간편인증";
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.grey[100],
|
||||
appBar: AppBar(
|
||||
title: const Text(
|
||||
'👨🏫 TEACHER PORTAL',
|
||||
style: TextStyle(fontWeight: FontWeight.bold, letterSpacing: 1.2),
|
||||
),
|
||||
centerTitle: true,
|
||||
backgroundColor: Colors.green[700], // 교사 전용 그린 테마 컬러
|
||||
foregroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.logout_rounded),
|
||||
onPressed: () => Navigator.pushReplacement(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => const LoginScreen()),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 💳 [상단 배너 가이드] StudentDashboard와 100% 일치하는 프로필 카드 레이아웃
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 28),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.green[700],
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(32),
|
||||
bottomRight: Radius.circular(32),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(4),
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: CircleAvatar(
|
||||
radius: 30,
|
||||
backgroundColor: Colors.green[50],
|
||||
child: Icon(
|
||||
Icons.admin_panel_settings_rounded,
|
||||
size: 32,
|
||||
color: Colors.green[700],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 18),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'$displayName 님',
|
||||
style: const TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'교직원 번호: $displayId | 교사 권한 활성화됨',
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: 0.8),
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
|
||||
// 🏷️ [세로 바 타이틀 인디케이터] 구조 일치화
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 4,
|
||||
height: 18,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.green[700],
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
const Text(
|
||||
'스마트 교사용 관리 메뉴',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 📊 [그리드 레이아웃 메뉴] 시후의 카드 컴포넌트 스타일 적용
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
child: GridView.count(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
crossAxisCount: 2,
|
||||
crossAxisSpacing: 16,
|
||||
mainAxisSpacing: 16,
|
||||
childAspectRatio: 0.95,
|
||||
children: [
|
||||
_buildModernCard(
|
||||
icon: Icons.assignment_turned_in_rounded,
|
||||
title: '실시간 출석 확인',
|
||||
subtitle: '학생 제출 로그 모니터링',
|
||||
color: Colors.blue,
|
||||
onTap: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const TeacherAttendancePage(),
|
||||
),
|
||||
),
|
||||
),
|
||||
_buildModernCard(
|
||||
icon: Icons.manage_accounts_rounded,
|
||||
title: '학생 계정 관리',
|
||||
subtitle: '계정 추가 및 강제 리셋',
|
||||
color: Colors.orange,
|
||||
onTap: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
const TeacherStudentManagementPage(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// 💎 [시후 대시보드 전용 카드 위젯 이식 완료]
|
||||
Widget _buildModernCard({
|
||||
required IconData icon,
|
||||
required String title,
|
||||
required String subtitle,
|
||||
required Color color,
|
||||
required VoidCallback onTap,
|
||||
bool isActionButton = false,
|
||||
bool isLoading = false,
|
||||
}) {
|
||||
return InkWell(
|
||||
onTap: isLoading ? null : onTap,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
child: Ink(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.04),
|
||||
blurRadius: 16,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Icon(icon, color: color, size: 28),
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isLoading)
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
height: 16,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
else if (isActionButton)
|
||||
Icon(
|
||||
Icons.touch_app_rounded,
|
||||
size: 16,
|
||||
color: color.withValues(alpha: 0.5),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
subtitle,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[500],
|
||||
height: 1.2,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user