import 'package:flutter/material.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:superport/data/models/model_dto.dart'; import 'package:superport/data/models/vendor_dto.dart'; import 'package:superport/screens/model/controllers/model_controller.dart'; /// Vendor별로 그룹화된 Model 테이블 class ModelGroupedTable extends StatelessWidget { final ModelController controller; final Function(ModelDto) onEdit; final Function(ModelDto) onDelete; const ModelGroupedTable({ super.key, required this.controller, required this.onEdit, required this.onDelete, }); @override Widget build(BuildContext context) { final modelsByVendor = controller.modelsByVendor; if (modelsByVendor.isEmpty) { return const Center( child: Text('등록된 모델이 없습니다.'), ); } return ListView.builder( itemCount: modelsByVendor.length, itemBuilder: (context, index) { final vendorId = modelsByVendor.keys.elementAt(index); final vendor = controller.getVendorById(vendorId); final models = modelsByVendor[vendorId] ?? []; return _buildVendorGroup(context, vendor, models); }, ); } Widget _buildVendorGroup( BuildContext context, VendorDto? vendor, List models, ) { return ShadCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Vendor 헤더 Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.grey.shade100, borderRadius: const BorderRadius.only( topLeft: Radius.circular(8), topRight: Radius.circular(8), ), ), child: Row( children: [ Icon( Icons.business, size: 20, color: Colors.grey.shade700, ), const SizedBox(width: 8), Expanded( child: Text( vendor?.name ?? 'Unknown Vendor', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), ), ShadBadge( child: Text('${models.length}개 모델'), ), ], ), ), // Model 목록 ...models.map((model) => _buildModelRow(context, model)), ], ), ); } Widget _buildModelRow(BuildContext context, ModelDto model) { return Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( border: Border( bottom: BorderSide( color: Colors.grey.shade200, width: 1, ), ), ), child: Row( children: [ // Model ID SizedBox( width: 60, child: Text( '#${model.id}', style: TextStyle( color: Colors.grey.shade600, fontSize: 12, ), ), ), // Model Name Expanded( flex: 2, child: Text( model.name, style: const TextStyle( fontWeight: FontWeight.w500, ), ), ), // Description Expanded( flex: 3, child: Text( '-', // 백엔드에 description 필드 없음 style: TextStyle( color: Colors.grey.shade600, fontSize: 14, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), // Status SizedBox( width: 80, child: ShadBadge( backgroundColor: model.isActive ? Colors.green.shade100 : Colors.grey.shade200, child: Text( model.isActive ? '활성' : '비활성', style: TextStyle( fontSize: 12, color: model.isActive ? Colors.green.shade700 : Colors.grey.shade700, ), ), ), ), // Actions SizedBox( width: 100, child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ IconButton( icon: const Icon(Icons.edit, size: 18), onPressed: () => onEdit(model), tooltip: '수정', padding: const EdgeInsets.all(4), constraints: const BoxConstraints(), ), const SizedBox(width: 8), IconButton( icon: const Icon(Icons.delete, size: 18), onPressed: () => onDelete(model), tooltip: '삭제', padding: const EdgeInsets.all(4), constraints: const BoxConstraints(), color: Colors.red, ), ], ), ), ], ), ); } }