하교 처리 시 출석 현황 표시도 함께 초기화
하교 버튼을 누르면 반출 허용뿐 아니라, 그 시각을 기준선으로 삼아 대시보드의 "출석 완료" 표시도 미제출로 초기화되도록 함. 실제 출석 기록(attendance 테이블)은 삭제하지 않고, 대시보드가 "오늘 출석"으로 인정하는 기준 시각만 옮기는 방식이라 데이터 손실 없이 표시만 리셋된다. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@ class _TeacherAttendancePageState extends State<TeacherAttendancePage> {
|
||||
List<dynamic> _roster = []; // 전체 학생 명단 (/api/users)
|
||||
List<dynamic> _logs = []; // 출석 로그 (/api/logs)
|
||||
Map<String, dynamic> _activeViolationsByStudentId = {}; // 무단반출 중인 학생 (/api/violations/active)
|
||||
String? _dismissedAt; // 오늘 가장 최근 하교 처리 시각 (/api/dismissal/latest). 이 시각 이후 기록만 "오늘 출석"으로 표시.
|
||||
Timer? _timer;
|
||||
bool _isLoading = true;
|
||||
bool _isRefreshing = false; // 새로고침 버튼 클릭 시 잠깐 도는 표시용
|
||||
@@ -54,11 +55,13 @@ class _TeacherAttendancePageState extends State<TeacherAttendancePage> {
|
||||
http.get(Uri.parse('$baseUrl/api/users')),
|
||||
http.get(Uri.parse('$baseUrl/api/logs')),
|
||||
http.get(Uri.parse('$baseUrl/api/violations/active')),
|
||||
http.get(Uri.parse('$baseUrl/api/dismissal/latest')),
|
||||
]);
|
||||
|
||||
final usersRes = results[0];
|
||||
final logsRes = results[1];
|
||||
final violationsRes = results[2];
|
||||
final dismissalRes = results[3];
|
||||
|
||||
if (usersRes.statusCode == 200 && logsRes.statusCode == 200) {
|
||||
final usersData = jsonDecode(utf8.decode(usersRes.bodyBytes));
|
||||
@@ -72,10 +75,17 @@ class _TeacherAttendancePageState extends State<TeacherAttendancePage> {
|
||||
}
|
||||
}
|
||||
|
||||
String? dismissedAt;
|
||||
if (dismissalRes.statusCode == 200) {
|
||||
final dismissalData = jsonDecode(utf8.decode(dismissalRes.bodyBytes));
|
||||
dismissedAt = dismissalData['dismissedAt'];
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_roster = usersData['users'] ?? [];
|
||||
_logs = logsData['logs'] ?? [];
|
||||
_activeViolationsByStudentId = activeViolations;
|
||||
_dismissedAt = dismissedAt;
|
||||
_isLoading = false;
|
||||
});
|
||||
} else {
|
||||
@@ -86,6 +96,24 @@ class _TeacherAttendancePageState extends State<TeacherAttendancePage> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 🏫 하교 처리: 전체 반출 허용 + 오늘 출석 표시 기준선을 지금 시각으로 옮긴다.
|
||||
Future<void> _dismissAll() async {
|
||||
try {
|
||||
final response = await http.post(Uri.parse('$baseUrl/api/dismiss'));
|
||||
final result = jsonDecode(utf8.decode(response.bodyBytes));
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(result['message'] ?? '하교 처리되었습니다.')),
|
||||
);
|
||||
_fetchAll();
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('❌ 하교 처리 실패: $e')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 🚨 선생님이 특정 학생에게 지금부터 N분간 반출을 허용한다.
|
||||
Future<void> _allowRemoval(String studentId, int minutes) async {
|
||||
try {
|
||||
@@ -222,7 +250,7 @@ class _TeacherAttendancePageState extends State<TeacherAttendancePage> {
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
_setPermissionWindow(720); // 12시간 (사실상 하교~다음날까지 허용)
|
||||
_dismissAll();
|
||||
},
|
||||
child: const Text('하교 처리'),
|
||||
),
|
||||
@@ -231,17 +259,19 @@ class _TeacherAttendancePageState extends State<TeacherAttendancePage> {
|
||||
);
|
||||
}
|
||||
|
||||
/// 오늘 날짜 기준으로 학번별 "가장 최근 출석 기록"만 남긴 맵을 만든다.
|
||||
/// "오늘 출석"의 기준선. 하교 처리를 했다면 그 시각 이후, 안 했다면 오늘 자정부터.
|
||||
Map<String, Map<String, String>> get _todaysCheckInsByStudentId {
|
||||
final String todayPrefix = DateTime.now().toIso8601String().substring(
|
||||
0,
|
||||
10,
|
||||
); // "YYYY-MM-DD"
|
||||
// "YYYY-MM-DD HH:MM:SS" 형태의 문자열끼리는 그대로 비교해도 시간 순서가 맞는다.
|
||||
final String cutoff =
|
||||
_dismissedAt ??
|
||||
'${DateTime.now().toIso8601String().substring(0, 10)} 00:00:00';
|
||||
final Map<String, Map<String, String>> result = {};
|
||||
|
||||
for (final log in _logs) {
|
||||
final String time = log['time']?.toString() ?? '';
|
||||
if (!time.startsWith(todayPrefix)) continue; // 오늘 기록이 아니면 무시
|
||||
if (time.isEmpty || time.compareTo(cutoff) <= 0) {
|
||||
continue; // 하교 처리 시각(또는 오늘 자정) 이전 기록이면 무시
|
||||
}
|
||||
|
||||
final String studentId = log['student_id']?.toString() ?? '';
|
||||
if (studentId.isEmpty) continue;
|
||||
|
||||
Reference in New Issue
Block a user