import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:superport/data/models/model_dto.dart'; import 'package:superport/screens/model/controllers/model_controller.dart'; import 'package:superport/screens/model/model_form_dialog.dart'; import 'package:superport/screens/common/layouts/base_list_screen.dart'; import 'package:superport/screens/common/widgets/standard_data_table.dart'; import 'package:superport/screens/common/widgets/standard_action_bar.dart'; import 'package:superport/screens/common/theme_shadcn.dart'; import 'package:superport/injection_container.dart' as di; class ModelListScreen extends StatefulWidget { const ModelListScreen({super.key}); @override State createState() => _ModelListScreenState(); } class _ModelListScreenState extends State { late final ModelController _controller; @override void initState() { super.initState(); _controller = di.sl(); WidgetsBinding.instance.addPostFrameCallback((_) { _controller.loadInitialData(); }); } @override Widget build(BuildContext context) { return ChangeNotifierProvider.value( value: _controller, child: Scaffold( backgroundColor: ShadcnTheme.background, appBar: AppBar( title: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '모델 관리', style: ShadcnTheme.headingH4, ), Text( '장비 모델 정보를 관리합니다', style: ShadcnTheme.bodySmall, ), ], ), backgroundColor: ShadcnTheme.background, elevation: 0, ), body: Consumer( builder: (context, controller, child) { return BaseListScreen( headerSection: _buildStatisticsCards(controller), searchBar: _buildSearchBar(controller), actionBar: _buildActionBar(), dataTable: _buildDataTable(controller), pagination: _buildPagination(controller), isLoading: controller.isLoading, error: controller.errorMessage, onRefresh: () => controller.loadInitialData(), ); }, ), ), ); } Widget _buildStatisticsCards(ModelController controller) { if (controller.isLoading) return const SizedBox(); return Row( children: [ _buildStatCard( '전체 모델', controller.models.length.toString(), Icons.category, ShadcnTheme.primary, ), const SizedBox(width: ShadcnTheme.spacing4), _buildStatCard( '제조사', controller.vendors.length.toString(), Icons.business, ShadcnTheme.success, ), const SizedBox(width: ShadcnTheme.spacing4), _buildStatCard( '활성 모델', controller.models.where((m) => !m.isDeleted).length.toString(), Icons.check_circle, ShadcnTheme.info, ), ], ); } Widget _buildSearchBar(ModelController controller) { return Row( children: [ Expanded( flex: 2, child: ShadInput( placeholder: const Text('모델명 검색...'), onChanged: controller.setSearchQuery, ), ), const SizedBox(width: ShadcnTheme.spacing4), Expanded( child: ShadSelect( placeholder: const Text('제조사 선택'), options: [ const ShadOption( value: null, child: Text('전체'), ), ...controller.vendors.map( (vendor) => ShadOption( value: vendor.id, child: Text(vendor.name), ), ), ], selectedOptionBuilder: (context, value) { if (value == null) { return const Text('전체'); } final vendor = controller.vendors.firstWhere((v) => v.id == value); return Text(vendor.name); }, onChanged: controller.setVendorFilter, ), ), ], ); } Widget _buildActionBar() { return StandardActionBar( totalCount: _controller.totalCount, leftActions: const [ Text('모델 목록', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), ], rightActions: [ ShadButton.outline( onPressed: () => _controller.refreshModels(), child: const Icon(Icons.refresh, size: 16), ), const SizedBox(width: ShadcnTheme.spacing2), ShadButton( onPressed: _showCreateDialog, child: const Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.add, size: 16), SizedBox(width: ShadcnTheme.spacing1), Text('새 모델 등록'), ], ), ), ], ); } Widget _buildDataTable(ModelController controller) { if (controller.models.isEmpty && !controller.isLoading) { return StandardDataTable( columns: _getColumns(), rows: const [], emptyMessage: '등록된 모델이 없습니다', emptyIcon: Icons.category_outlined, ); } return StandardDataTable( columns: _getColumns(), rows: _buildRows(controller), fixedHeader: true, maxHeight: 600, ); } List _getColumns() { return [ StandardDataColumn(label: 'ID', width: 60), StandardDataColumn(label: '제조사', flex: 1), StandardDataColumn(label: '모델명', flex: 2), StandardDataColumn(label: '등록일', flex: 1), StandardDataColumn(label: '상태', width: 80), StandardDataColumn(label: '작업', width: 100), ]; } List _buildRows(ModelController controller) { return controller.models.map((model) { final index = controller.models.indexOf(model); final vendor = controller.getVendorById(model.vendorsId); return StandardDataRow( index: index, columns: _getColumns(), cells: [ Text( model.id.toString(), style: ShadcnTheme.bodyMedium, ), Text( vendor?.name ?? '알 수 없음', style: ShadcnTheme.bodyMedium, ), Text( model.name, style: ShadcnTheme.bodyMedium.copyWith( fontWeight: FontWeight.w500, ), ), Text( model.registeredAt != null ? DateFormat('yyyy-MM-dd').format(model.registeredAt!) : '-', style: ShadcnTheme.bodySmall, ), _buildStatusChip(model.isDeleted), Row( mainAxisSize: MainAxisSize.min, children: [ ShadButton.ghost( onPressed: () => _showEditDialog(model), child: const Icon(Icons.edit, size: 16), ), const SizedBox(width: ShadcnTheme.spacing1), ShadButton.ghost( onPressed: () => _showDeleteConfirmDialog(model), child: const Icon(Icons.delete, size: 16), ), ], ), ], ); }).toList(); } Widget _buildPagination(ModelController controller) { // 모델 목록은 현재 페이지네이션이 없는 것 같으니 빈 위젯 반환 return const SizedBox(); } Widget _buildStatCard( String title, String value, IconData icon, Color color, ) { return Expanded( child: ShadCard( child: Padding( padding: const EdgeInsets.all(ShadcnTheme.spacing4), child: Row( children: [ Container( padding: const EdgeInsets.all(ShadcnTheme.spacing3), decoration: BoxDecoration( color: color.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(ShadcnTheme.radiusLg), ), child: Icon( icon, color: color, size: 20, ), ), const SizedBox(width: ShadcnTheme.spacing3), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: ShadcnTheme.bodySmall, ), Text( value, style: ShadcnTheme.headingH6.copyWith( color: color, ), ), ], ), ), ], ), ), ), ); } Widget _buildStatusChip(bool isDeleted) { if (isDeleted) { return ShadBadge.destructive( child: const Text('비활성'), ); } else { return ShadBadge.secondary( child: const Text('활성'), ); } } void _showCreateDialog() { showDialog( context: context, builder: (context) => ModelFormDialog( controller: _controller, ), ); } void _showEditDialog(ModelDto model) { showDialog( context: context, builder: (context) => ModelFormDialog( controller: _controller, model: model, ), ); } void _showDeleteConfirmDialog(ModelDto model) { showDialog( context: context, builder: (context) => ShadDialog( title: const Text('모델 삭제'), description: Text('${model.name} 모델을 삭제하시겠습니까?'), actions: [ ShadButton.outline( onPressed: () => Navigator.of(context).pop(), child: const Text('취소'), ), ShadButton.destructive( onPressed: () async { Navigator.of(context).pop(); await _controller.deleteModel(model.id!); }, child: const Text('삭제'), ), ], ), ); } }