# Equipment List 마이그레이션 상세 구현 계획 ## 아키텍처 통합 전략 ### 상태 관리 패턴 - **기존 패턴 유지**: `EquipmentListController` 사용 - **선택 상태 관리**: `selectedEquipmentIds` Map 구조 유지 - **데이터 로딩**: `MockDataService` 싱글톤 패턴 유지 - **라이프사이클**: initState, dispose 패턴 준수 ### 의존성 구조 ```dart equipment_list_redesign.dart ├── EquipmentListController (기존 컨트롤러 재사용) ├── MockDataService (기존 서비스 재사용) ├── UnifiedEquipment 모델 (기존 모델 재사용) ├── ShadcnTheme (새로운 테마 시스템) └── ShadcnComponents (새로운 UI 컴포넌트) ``` ### 이벤트 처리 - **선택 이벤트**: 기존 `_onEquipmentSelected` 메서드 구조 유지 - **액션 이벤트**: 기존 핸들러 메서드 구조 유지 - **네비게이션**: Named Route 방식 유지 ## 기능별 마이그레이션 계획 ### 우선순위 1: 핵심 기능 (Days 1-3) #### 1.1 체크박스 선택 기능 **수용 기준**: - 각 행에 체크박스 표시 - 선택된 항목 개수 실시간 표시 - 상태별 선택 개수 구분 표시 **구현 방법**: ```dart // 테이블 헤더에 체크박스 컬럼 추가 Expanded( flex: 1, child: Checkbox( value: _isAllSelected(), onChanged: _onSelectAll, ), ), // 각 행에 체크박스 추가 Checkbox( value: _controller.selectedEquipmentIds.containsKey('${equipment.status}_${equipment.id}'), onChanged: (value) => _onEquipmentSelected(equipment.id, equipment.status, value), ), ``` #### 1.2 편집/삭제 버튼 **수용 기준**: - 각 행 끝에 편집/삭제 아이콘 버튼 - 삭제 시 확인 다이얼로그 - 편집 시 해당 폼으로 네비게이션 **구현 방법**: ```dart // 액션 버튼 컬럼 추가 Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: Icon(Icons.edit_outlined, size: 16), onPressed: () => _handleEdit(equipment), ), IconButton( icon: Icon(Icons.delete_outline, size: 16), onPressed: () => _handleDelete(equipment), ), ], ), ``` #### 1.3 상세 정보 표시 **수용 기준**: - 시리얼번호, 바코드 컬럼 추가 - 출고/대여 상태일 때 회사, 담당자, 라이센스 정보 표시 - 간소화 모드에서는 주요 정보만 표시 **구현 방법**: ```dart // 상세 정보 컬럼 조건부 표시 if (_showDetailedColumns) ...[ Expanded( flex: 2, child: Text(equipment.equipment.serialNumber ?? '-'), ), Expanded( flex: 2, child: Text(equipment.equipment.barcode ?? '-'), ), ], // 출고 정보 표시 if (equipment.status == EquipmentStatus.out) ...[ Expanded( flex: 2, child: Text(_controller.getOutEquipmentInfo(equipment.id, 'company')), ), ], ``` ### 우선순위 2: 라우트별 기능 (Days 4-6) #### 2.1 라우트별 액션 버튼 **수용 기준**: - 입고 목록: 입고/출고/대여/폐기 버튼 - 출고 목록: 재입고/수리요청 버튼 - 대여 목록: 반납/연장 버튼 **구현 방법**: ```dart Widget _buildRouteSpecificActions() { switch (widget.currentRoute) { case Routes.equipmentInList: return Row( children: [ ShadcnButton( text: '출고', onPressed: _selectedInCount > 0 ? _handleOutEquipment : null, icon: Icon(Icons.exit_to_app, size: 16), ), // ... 다른 버튼들 ], ); case Routes.equipmentOutList: // ... 출고 목록 전용 버튼들 default: return SizedBox.shrink(); } } ``` #### 2.2 검색 기능 확장 **수용 기준**: - 시리얼번호, 바코드, 비고 필드 검색 - Enter 키로 검색 실행 - 검색어 하이라이트 (선택사항) **구현 방법**: ```dart // 확장된 검색 로직 equipments.where((e) { final keyword = _appliedSearchKeyword.toLowerCase(); return [ e.equipment.manufacturer, e.equipment.name, e.equipment.category, e.equipment.subCategory, e.equipment.subSubCategory, e.equipment.serialNumber ?? '', e.equipment.barcode ?? '', e.equipment.remark ?? '', e.notes ?? '', ].any((field) => field.toLowerCase().contains(keyword)); }).toList(); ``` ### 우선순위 3: UX 개선 (Days 7-10) #### 3.1 상세/간소화 뷰 전환 **수용 기준**: - 토글 버튼으로 뷰 모드 전환 - 화면 크기에 따른 자동 조정 - 사용자 선택 기억 **구현 방법**: ```dart // 헤더에 토글 버튼 추가 IconButton( icon: Icon(_showDetailedColumns ? Icons.view_column : Icons.view_compact), onPressed: () => setState(() => _showDetailedColumns = !_showDetailedColumns), ), // 화면 크기 감지 @override void didChangeDependencies() { super.didChangeDependencies(); final width = MediaQuery.of(context).size.width; _showDetailedColumns = width > 900; } ``` #### 3.2 가로 스크롤 지원 **수용 기준**: - 좁은 화면에서 테이블 가로 스크롤 - 스크롤바 표시 - 최소 너비 보장 **구현 방법**: ```dart SingleChildScrollView( scrollDirection: Axis.horizontal, child: ConstrainedBox( constraints: BoxConstraints(minWidth: 1200), child: _buildTable(), ), ), ``` ## 성능 최적화 전략 ### 렌더링 최적화 ```dart // const 생성자 활용 const SizedBox(width: 8), const Icon(Icons.edit), // 조건부 렌더링 최적화 if (_showDetailedColumns) _buildDetailedColumns(), // ListView.builder 사용 검토 (대량 데이터) ``` ### 상태 관리 최적화 ```dart // 불필요한 setState 방지 if (_selectedStatus != newStatus) { setState(() => _selectedStatus = newStatus); } // 컨트롤러 재사용 late final EquipmentListController _controller; ``` ## 테스트 전략 ### 단위 테스트 ```dart // 선택 기능 테스트 test('equipment selection works correctly', () { controller.selectEquipment(1, 'I', true); expect(controller.getSelectedInStockCount(), 1); }); // 검색 기능 테스트 test('search filters equipment correctly', () { final filtered = controller.searchEquipments('Dell'); expect(filtered.length, greaterThan(0)); }); ``` ### 위젯 테스트 ```dart // UI 렌더링 테스트 testWidgets('equipment table renders correctly', (tester) async { await tester.pumpWidget(EquipmentListRedesign()); expect(find.byType(DataTable), findsOneWidget); }); // 상호작용 테스트 testWidgets('checkbox selection updates UI', (tester) async { await tester.tap(find.byType(Checkbox).first); await tester.pump(); expect(find.text('1개 선택됨'), findsOneWidget); }); ``` ## 마이그레이션 체크리스트 ### Phase 1 완료 기준 - [ ] 체크박스 선택 기능 구현 및 테스트 - [ ] 편집/삭제 버튼 구현 및 테스트 - [ ] 상세 정보 표시 구현 및 테스트 - [ ] 기존 equipment_list와 기능 동일성 확인 ### Phase 2 완료 기준 - [ ] 라우트별 액션 버튼 구현 - [ ] 검색 기능 확장 구현 - [ ] 출고 정보 표시 구현 - [ ] 모든 액션 핸들러 작동 확인 ### Phase 3 완료 기준 - [ ] 상세/간소화 뷰 전환 구현 - [ ] 반응형 레이아웃 구현 - [ ] 성능 최적화 완료 - [ ] 전체 기능 통합 테스트 통과 ## 리스크 및 대응 방안 ### 잠재 리스크 1. **상태 관리 복잡도**: 선택 상태와 필터 상태의 동기화 - 대응: 명확한 상태 플로우 문서화 2. **UI 일관성**: shadcn 스타일과 기존 기능의 조화 - 대응: 디자인 시스템 엄격 준수 3. **성능 이슈**: 대량 데이터 처리 시 렌더링 지연 - 대응: 가상 스크롤링 도입 검토 --- *작성일: 2025-07-07*