import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; import 'package:superport/models/equipment_unified_model.dart'; import 'package:superport/screens/equipment/controllers/equipment_history_controller.dart'; import 'package:superport/data/models/equipment_history_dto.dart'; import 'package:intl/intl.dart'; /// Equipment의 입출고 이력을 표시하는 패널 위젯 class EquipmentHistoryPanel extends StatefulWidget { final Equipment equipment; final bool isExpanded; final VoidCallback? onToggleExpand; const EquipmentHistoryPanel({ super.key, required this.equipment, this.isExpanded = false, this.onToggleExpand, }); @override State createState() => _EquipmentHistoryPanelState(); } class _EquipmentHistoryPanelState extends State { late EquipmentHistoryController _controller; bool _isLoading = false; List _histories = []; @override void initState() { super.initState(); _controller = GetIt.instance(); if (widget.equipment.id != null) { _loadHistory(); } } Future _loadHistory() async { if (widget.equipment.id == null) return; setState(() { _isLoading = true; }); try { // Equipment ID로 이력 조회 await _controller.searchEquipmentHistories( equipmentId: widget.equipment.id, ); setState(() { _histories = _controller.historyList; _isLoading = false; }); } catch (e) { setState(() { _isLoading = false; }); } } @override Widget build(BuildContext context) { return Card( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 헤더 InkWell( onTap: widget.onToggleExpand, child: Padding( padding: const EdgeInsets.all(16.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Icon( Icons.history, size: 20, color: Theme.of(context).primaryColor, ), const SizedBox(width: 8), Text( '장비 이력', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(width: 8), if (_histories.isNotEmpty) Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: Colors.green.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(12), ), child: Text( '${_histories.length}건', style: const TextStyle( fontSize: 12, fontWeight: FontWeight.w500, color: Colors.green, ), ), ), ], ), Icon( widget.isExpanded ? Icons.expand_less : Icons.expand_more, color: Colors.grey[600], ), ], ), ), ), // 확장된 내용 if (widget.isExpanded) ...[ const Divider(height: 1), Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 현재 상태 요약 _buildCurrentStatusSummary(), const SizedBox(height: 16), // 이력 표시 if (_isLoading) const Center( child: Padding( padding: EdgeInsets.all(32.0), child: CircularProgressIndicator(), ), ) else if (_histories.isEmpty) Container( width: double.infinity, padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: Colors.grey[50], borderRadius: BorderRadius.circular(8), border: Border.all( color: Colors.grey[300]!, style: BorderStyle.solid, ), ), child: Column( children: [ Icon( Icons.history, size: 48, color: Colors.grey[400], ), const SizedBox(height: 12), Text( '입출고 이력이 없습니다', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Colors.grey[700], ), ), ], ), ) else _buildHistoryList(), ], ), ), ], ], ), ); } Widget _buildCurrentStatusSummary() { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.blue[50], borderRadius: BorderRadius.circular(8), border: Border.all( color: Colors.blue[200]!, ), ), child: Row( children: [ Icon( Icons.info_outline, size: 20, color: Colors.blue[700], ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '현재 장비 정보', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Colors.blue[900], ), ), const SizedBox(height: 4), Text( '장비번호: ${widget.equipment.serialNumber}', style: TextStyle( fontSize: 13, color: Colors.blue[700], ), ), if (widget.equipment.model != null) ...[ Text( '제조사: ${widget.equipment.model?.vendor?.name ?? 'N/A'}', style: TextStyle( fontSize: 13, color: Colors.blue[700], ), ), Text( '모델: ${widget.equipment.model?.name ?? 'N/A'}', style: TextStyle( fontSize: 13, color: Colors.blue[700], ), ), ], if (widget.equipment.serialNumber != null) Text( '시리얼: ${widget.equipment.serialNumber}', style: TextStyle( fontSize: 13, color: Colors.blue[700], ), ), ], ), ), ], ), ); } Widget _buildHistoryList() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '입출고 이력', style: Theme.of(context).textTheme.titleSmall?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 12), Container( decoration: BoxDecoration( border: Border.all(color: Colors.grey[300]!), borderRadius: BorderRadius.circular(8), ), child: Column( children: [ // 테이블 헤더 Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: const BorderRadius.only( topLeft: Radius.circular(7), topRight: Radius.circular(7), ), ), child: Row( children: [ Expanded( flex: 2, child: Text('거래유형', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 13, color: Colors.grey[700])), ), Expanded( flex: 2, child: Text('날짜', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 13, color: Colors.grey[700])), ), Expanded( flex: 1, child: Text('수량', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 13, color: Colors.grey[700])), ), Expanded( flex: 2, child: Text('창고', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 13, color: Colors.grey[700])), ), Expanded( flex: 3, child: Text('비고', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 13, color: Colors.grey[700])), ), ], ), ), // 테이블 바디 ..._histories.map((history) => _buildHistoryRow(history)), ], ), ), ], ); } Widget _buildHistoryRow(EquipmentHistoryDto history) { final dateFormat = DateFormat('yyyy-MM-dd'); final isIn = history.transactionType == 'I'; return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( border: Border( top: BorderSide(color: Colors.grey[200]!), ), ), child: Row( children: [ Expanded( flex: 2, child: Row( children: [ Icon( isIn ? Icons.arrow_downward : Icons.arrow_upward, size: 16, color: isIn ? Colors.green : Colors.red, ), const SizedBox(width: 4), Text( isIn ? '입고' : '출고', style: TextStyle( fontSize: 13, color: isIn ? Colors.green[700] : Colors.red[700], fontWeight: FontWeight.w500, ), ), ], ), ), Expanded( flex: 2, child: Text( dateFormat.format(history.transactedAt), style: const TextStyle(fontSize: 13), ), ), Expanded( flex: 1, child: Text( history.quantity.toString(), style: const TextStyle(fontSize: 13), ), ), Expanded( flex: 2, child: Text( '-', // 창고 정보는 백엔드에서 제공하지 않음 style: const TextStyle(fontSize: 13), overflow: TextOverflow.ellipsis, ), ), Expanded( flex: 3, child: Text( history.remark ?? '-', style: TextStyle(fontSize: 13, color: Colors.grey[600]), overflow: TextOverflow.ellipsis, ), ), ], ), ); } }