From 6b90ae3925ccd88783692d8bec534bacfa352b34 Mon Sep 17 00:00:00 2001 From: sihoo Date: Wed, 30 Sep 2026 05:36:33 +0000 Subject: [PATCH] =?UTF-8?q?=EC=A0=84=EC=B2=B4=20=ED=95=99=EC=83=9D=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=EC=97=90=20=ED=95=99=EB=B2=88=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20+=20=ED=95=99=EB=85=84=20=ED=95=84=ED=84=B0,=201?= =?UTF-8?q?=ED=95=99=EB=85=84=EB=B6=80=ED=84=B0=20=EC=A0=95=EB=A0=AC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 목록을 학년 오름차순(1→2→3, 미배정은 맨 뒤)으로 정렬하고, 학번으로 검색하는 입력창과 전체/1학년/2학년/3학년 필터 칩을 추가. Co-Authored-By: Claude Sonnet 5 --- ...teacher_student_management_controller.dart | 34 +++++++++ lib/ui/teacher_student_management_page.dart | 71 +++++++++++++++++-- 2 files changed, 98 insertions(+), 7 deletions(-) diff --git a/lib/function/teacher_student_management_controller.dart b/lib/function/teacher_student_management_controller.dart index 38cea7d..a9e61ce 100644 --- a/lib/function/teacher_student_management_controller.dart +++ b/lib/function/teacher_student_management_controller.dart @@ -38,8 +38,42 @@ class TeacherStudentManagementController extends ChangeNotifier { List _students = []; bool _isLoadingStudents = true; + String _searchQuery = ''; + int? _gradeFilter; // null = 전체 List get students => _students; bool get isLoadingStudents => _isLoadingStudents; + String get searchQuery => _searchQuery; + int? get gradeFilter => _gradeFilter; + + /// 🔍 학번 검색 + 학년 필터를 적용하고, 학년 오름차순(1→2→3, 미배정은 맨 뒤)으로 + /// 정렬한 목록. 화면에는 이 목록을 그린다. + List get filteredStudents { + final query = _searchQuery.trim(); + final filtered = _students.where((s) { + if (_gradeFilter != null && s['grade'] != _gradeFilter) return false; + if (query.isEmpty) return true; + return s['id'].toString().contains(query); + }).toList(); + filtered.sort((a, b) { + final ga = a['grade'] as int?; + final gb = b['grade'] as int?; + if (ga == null && gb == null) return 0; + if (ga == null) return 1; + if (gb == null) return -1; + return ga.compareTo(gb); + }); + return filtered; + } + + void setSearchQuery(String query) { + _searchQuery = query; + notifyListeners(); + } + + void setGradeFilter(int? grade) { + _gradeFilter = grade; + notifyListeners(); + } Future init() => fetchStudents(); diff --git a/lib/ui/teacher_student_management_page.dart b/lib/ui/teacher_student_management_page.dart index fab2a0d..4f49d60 100644 --- a/lib/ui/teacher_student_management_page.dart +++ b/lib/ui/teacher_student_management_page.dart @@ -358,6 +358,20 @@ class _TeacherStudentManagementPageState } // 🏷️ 섹션 제목 (색 인디케이터 바 + 텍스트). + Widget _gradeFilterChip(int? grade, String label) { + final bool selected = _controller.gradeFilter == grade; + return ChoiceChip( + label: Text(label), + selected: selected, + onSelected: (_) => _controller.setGradeFilter(grade), + selectedColor: AppPalette.ink, + labelStyle: TextStyle( + color: selected ? Colors.white : AppPalette.ink, + fontWeight: FontWeight.bold, + ), + ); + } + Widget _sectionTitle(String text, {Color color = AppPalette.ink}) { return Row( children: [ @@ -753,6 +767,42 @@ class _TeacherStudentManagementPageState ), ), const SizedBox(height: 12), + Row( + children: [ + Expanded( + child: TextField( + onChanged: _controller.setSearchQuery, + keyboardType: TextInputType.number, + decoration: InputDecoration( + hintText: '학번으로 검색', + prefixIcon: const Icon( + Icons.search_rounded, + ), + filled: true, + fillColor: AppPalette.paper, + contentPadding: const EdgeInsets.symmetric( + vertical: 0, + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: AppPalette.sage, + ), + ), + ), + ), + ), + const SizedBox(width: 12), + _gradeFilterChip(null, '전체'), + const SizedBox(width: 6), + _gradeFilterChip(1, '1학년'), + const SizedBox(width: 6), + _gradeFilterChip(2, '2학년'), + const SizedBox(width: 6), + _gradeFilterChip(3, '3학년'), + ], + ), + const SizedBox(height: 12), _controller.isLoadingStudents ? const Padding( padding: EdgeInsets.symmetric(vertical: 40), @@ -760,13 +810,19 @@ class _TeacherStudentManagementPageState child: CircularProgressIndicator(), ), ) - : _controller.students.isEmpty - ? const Padding( - padding: EdgeInsets.symmetric(vertical: 24), + : _controller.filteredStudents.isEmpty + ? Padding( + padding: const EdgeInsets.symmetric( + vertical: 24, + ), child: Center( child: Text( - '가입된 학생 계정이 없습니다.', - style: TextStyle(color: Colors.grey), + _controller.students.isEmpty + ? '가입된 학생 계정이 없습니다.' + : '검색/필터 조건에 맞는 학생이 없습니다.', + style: const TextStyle( + color: Colors.grey, + ), ), ), ) @@ -781,10 +837,11 @@ class _TeacherStudentManagementPageState crossAxisSpacing: 12, mainAxisSpacing: 12, ), - itemCount: _controller.students.length, + itemCount: + _controller.filteredStudents.length, itemBuilder: (context, index) => _buildStudentTile( - _controller.students[index], + _controller.filteredStudents[index], ), ), ],