학생 계정 관리 타일 크기/폰트를 실시간 출석 확인 목록과 통일

계정 추가/엑셀 등록 칸과 학생 목록 타일 모두 "실시간 출석 확인"
목록의 타일 규격(220x148, 이름15/상태11.5/칩11 폰트)에 맞춰
동일한 비율로 재조정.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-01 08:20:47 +09:00
co-authored by Claude Sonnet 5
parent eba23ecf9b
commit d9ab6adb51
+41 -31
View File
@@ -6,6 +6,10 @@ import 'package:flutter/material.dart';
import '../function/excel_file_picker.dart'; import '../function/excel_file_picker.dart';
import '../function/teacher_student_management_controller.dart'; import '../function/teacher_student_management_controller.dart';
// 📐 "실시간 출석 확인" 목록(teacher_attendance_page.dart)의 타일 규격과 동일하게 맞춘다.
const double kAttendanceTileWidth = 220;
const double kAttendanceTileHeight = 148;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// 👥 [서브 화면 2] 학생 계정 관리 란 (추가 양식 폼 + 강제 삭제 다이얼로그 완전 내장) // 👥 [서브 화면 2] 학생 계정 관리 란 (추가 양식 폼 + 강제 삭제 다이얼로그 완전 내장)
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -545,28 +549,37 @@ class _TeacherStudentManagementPageState
final bool needsReset = student['device'] == '초기화 필요'; final bool needsReset = student['device'] == '초기화 필요';
return Container( return Container(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(14),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(14), borderRadius: BorderRadius.circular(20),
boxShadow: [ boxShadow: [
BoxShadow(color: Colors.black.withValues(alpha: 0.04), blurRadius: 8), BoxShadow(
color: Colors.black.withValues(alpha: 0.03),
blurRadius: 12,
offset: const Offset(0, 4),
),
], ],
), ),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
CircleAvatar( Container(
radius: 20, padding: const EdgeInsets.all(8),
backgroundColor: needsReset ? Colors.red[50] : Colors.blue[50], decoration: BoxDecoration(
color: (needsReset ? Colors.red : Colors.blue).withValues(
alpha: 0.1,
),
shape: BoxShape.circle,
),
child: Icon( child: Icon(
needsReset ? Icons.lock_reset : Icons.person, needsReset ? Icons.lock_reset : Icons.person,
size: 20, size: 18,
color: needsReset ? Colors.red : Colors.blue, color: needsReset ? Colors.red : Colors.blue,
), ),
), ),
const SizedBox(height: 6), const SizedBox(height: 8),
Text( Text(
'$studentName ($studentId)', '$studentName ($studentId)',
textAlign: TextAlign.center, textAlign: TextAlign.center,
@@ -574,13 +587,13 @@ class _TeacherStudentManagementPageState
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15), style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15),
), ),
const SizedBox(height: 2), const SizedBox(height: 4),
Text( Text(
needsReset ? '초기화 대기중' : '정상 등록', needsReset ? '초기화 대기중' : '정상 등록',
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 11.5,
color: needsReset ? Colors.red : Colors.grey, color: needsReset ? Colors.red[700] : Colors.grey[600],
fontWeight: needsReset ? FontWeight.bold : FontWeight.normal, fontWeight: needsReset ? FontWeight.bold : FontWeight.normal,
), ),
), ),
@@ -597,7 +610,7 @@ class _TeacherStudentManagementPageState
labelPadding: const EdgeInsets.symmetric(horizontal: 6), labelPadding: const EdgeInsets.symmetric(horizontal: 6),
label: Text( label: Text(
grade != null ? '$grade학년' : '미배정', grade != null ? '$grade학년' : '미배정',
style: const TextStyle(fontSize: 12), style: const TextStyle(fontSize: 11),
), ),
onPressed: () => _showGradeMenu( onPressed: () => _showGradeMenu(
chipContext, chipContext,
@@ -611,22 +624,22 @@ class _TeacherStudentManagementPageState
icon: const Icon( icon: const Icon(
Icons.lock_reset, Icons.lock_reset,
color: Colors.purple, color: Colors.purple,
size: 20, size: 18,
), ),
tooltip: '기기 리셋', tooltip: '기기 리셋',
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
constraints: const BoxConstraints(minWidth: 30, minHeight: 30), constraints: const BoxConstraints(minWidth: 28, minHeight: 28),
onPressed: () => _confirmResetDevice(studentId, studentName), onPressed: () => _confirmResetDevice(studentId, studentName),
), ),
IconButton( IconButton(
icon: const Icon( icon: const Icon(
Icons.delete_forever_rounded, Icons.delete_forever_rounded,
color: Colors.redAccent, color: Colors.redAccent,
size: 20, size: 18,
), ),
tooltip: '계정 영구 삭제', tooltip: '계정 영구 삭제',
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
constraints: const BoxConstraints(minWidth: 30, minHeight: 30), constraints: const BoxConstraints(minWidth: 28, minHeight: 28),
onPressed: () => _confirmDeleteStudent(studentId, studentName), onPressed: () => _confirmDeleteStudent(studentId, studentName),
), ),
], ],
@@ -656,14 +669,10 @@ class _TeacherStudentManagementPageState
padding: const EdgeInsets.all(24.0), padding: const EdgeInsets.all(24.0),
child: LayoutBuilder( child: LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
// 🖥️ 웹(넓은 화면)은 계정 추가/엑셀 등록을 정사각형 2칸으로 나란히, 폰은 기존처럼 세로로 쌓는다. // 🖥️ 웹(넓은 화면)은 계정 추가/엑셀 등록을 나란히, 폰은 기존처럼 세로로 쌓는다.
// 📐 크기/폰트 비율은 "실시간 출석 확인" 목록의 타일(220x148)과 동일하게 맞춘다.
final bool isWide = constraints.maxWidth >= 800; final bool isWide = constraints.maxWidth >= 800;
final double listWidth = constraints.maxWidth; final double listWidth = constraints.maxWidth;
// 📐 학생 목록 타일과 동일한 크기를 계정 추가/엑셀 등록 칸에도 사용한다.
final double tileSize =
((listWidth - (isWide ? 7 : 3) * 10) / (isWide ? 8 : 4)) *
1.5;
final double formSquareSize = tileSize;
final Widget addBoxColumn = Column( final Widget addBoxColumn = Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -671,8 +680,8 @@ class _TeacherStudentManagementPageState
_sectionTitle('신규 학생 계정 추가'), _sectionTitle('신규 학생 계정 추가'),
const SizedBox(height: 16), const SizedBox(height: 16),
SizedBox( SizedBox(
width: isWide ? formSquareSize : double.infinity, width: isWide ? kAttendanceTileWidth : double.infinity,
height: isWide ? formSquareSize : null, height: isWide ? kAttendanceTileHeight : null,
child: _buildAddAccountBox(), child: _buildAddAccountBox(),
), ),
], ],
@@ -684,8 +693,8 @@ class _TeacherStudentManagementPageState
_sectionTitle('엑셀로 한번에 추가 (신입생 등)'), _sectionTitle('엑셀로 한번에 추가 (신입생 등)'),
const SizedBox(height: 16), const SizedBox(height: 16),
SizedBox( SizedBox(
width: isWide ? formSquareSize : double.infinity, width: isWide ? kAttendanceTileWidth : double.infinity,
height: isWide ? formSquareSize : 240, height: isWide ? kAttendanceTileHeight : 240,
child: _buildExcelBox(), child: _buildExcelBox(),
), ),
], ],
@@ -762,11 +771,12 @@ class _TeacherStudentManagementPageState
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
gridDelegate: gridDelegate:
SliverGridDelegateWithMaxCrossAxisExtent( const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: tileSize, maxCrossAxisExtent:
crossAxisSpacing: 10, kAttendanceTileWidth,
mainAxisSpacing: 10, mainAxisExtent: kAttendanceTileHeight,
childAspectRatio: 1, crossAxisSpacing: 12,
mainAxisSpacing: 12,
), ),
itemCount: _controller.students.length, itemCount: _controller.students.length,
itemBuilder: (context, index) => itemBuilder: (context, index) =>