Files
superport/lib/screens/equipment/widgets/equipment_table.dart
2025-07-02 17:45:44 +09:00

237 lines
9.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:superport/models/equipment_unified_model.dart';
import 'package:superport/screens/equipment/widgets/equipment_status_chip.dart';
import 'package:superport/screens/equipment/widgets/equipment_out_info.dart';
import 'package:superport/utils/equipment_display_helper.dart';
// 장비 목록 테이블 위젯 (SRP, 재사용성 강화)
class EquipmentTable extends StatelessWidget {
final List<UnifiedEquipment> equipments;
final Set<String> selectedEquipmentIds;
final bool showDetailedColumns;
final void Function(int? id, String status, bool? isSelected)
onEquipmentSelected;
final String Function(int equipmentId, String infoType) getOutEquipmentInfo;
final Widget Function(UnifiedEquipment equipment) buildCategoryWithTooltip;
final void Function(int id, String status) onEdit;
final void Function(int id, String status) onDelete;
final int Function() getSelectedInStockCount;
const EquipmentTable({
super.key,
required this.equipments,
required this.selectedEquipmentIds,
required this.showDetailedColumns,
required this.onEquipmentSelected,
required this.getOutEquipmentInfo,
required this.buildCategoryWithTooltip,
required this.onEdit,
required this.onDelete,
required this.getSelectedInStockCount,
});
// 출고 정보(간소화 모드) 위젯
Widget _buildCompactOutInfo(int equipmentId) {
final company = getOutEquipmentInfo(equipmentId, 'company');
final manager = getOutEquipmentInfo(equipmentId, 'manager');
final license = getOutEquipmentInfo(equipmentId, 'license');
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
EquipmentOutInfoIcon(infoType: 'company', text: company),
const SizedBox(height: 2),
EquipmentOutInfoIcon(infoType: 'manager', text: manager),
const SizedBox(height: 2),
EquipmentOutInfoIcon(infoType: 'license', text: license),
],
);
}
// 카테고리 툴팁 위젯 (UI만 담당, 축약 표기 적용)
Widget _buildCategoryWithTooltip(UnifiedEquipment equipment) {
// 한글 라벨로 표기
final fullCategory =
'대분류: ${equipment.equipment.category} / 중분류: ${equipment.equipment.subCategory} / 소분류: ${equipment.equipment.subSubCategory}';
final shortCategory = [
_shortenCategory(equipment.equipment.category),
_shortenCategory(equipment.equipment.subCategory),
_shortenCategory(equipment.equipment.subSubCategory),
].join(' > ');
return Tooltip(message: fullCategory, child: Text(shortCategory));
}
// 카테고리 축약 표기 함수 (예: 컴...)
String _shortenCategory(String category) {
if (category.length <= 2) return category;
return category.substring(0, 2) + '...';
}
@override
Widget build(BuildContext context) {
return DataTable(
headingRowHeight: 48,
dataRowMinHeight: 48,
dataRowMaxHeight: 60,
columnSpacing: 10,
horizontalMargin: 16,
columns: [
const DataColumn(label: SizedBox(width: 32, child: Text('선택'))),
const DataColumn(label: SizedBox(width: 32, child: Text('번호'))),
if (showDetailedColumns)
const DataColumn(label: SizedBox(width: 60, child: Text('제조사'))),
const DataColumn(label: SizedBox(width: 90, child: Text('장비명'))),
if (showDetailedColumns)
const DataColumn(label: SizedBox(width: 110, child: Text('분류'))),
if (showDetailedColumns)
const DataColumn(label: SizedBox(width: 60, child: Text('장비 유형'))),
if (showDetailedColumns)
const DataColumn(label: SizedBox(width: 70, child: Text('시리얼번호'))),
const DataColumn(label: SizedBox(width: 38, child: Text('수량'))),
const DataColumn(label: SizedBox(width: 80, child: Text('변경 일자'))),
const DataColumn(label: SizedBox(width: 44, child: Text('상태'))),
if (showDetailedColumns) ...[
const DataColumn(label: SizedBox(width: 90, child: Text('출고 회사'))),
const DataColumn(label: SizedBox(width: 60, child: Text('담당자'))),
const DataColumn(label: SizedBox(width: 60, child: Text('라이센스'))),
] else
const DataColumn(label: SizedBox(width: 110, child: Text('출고 정보'))),
const DataColumn(label: SizedBox(width: 60, child: Text('관리'))),
],
rows:
equipments.asMap().entries.map((entry) {
final index = entry.key;
final equipment = entry.value;
final bool isInStock = equipment.status == 'I';
final bool isOutStock = equipment.status == 'O';
return DataRow(
color: MaterialStateProperty.resolveWith<Color?>(
(Set<MaterialState> states) =>
index % 2 == 0 ? Colors.grey[50] : null,
),
cells: [
DataCell(
Checkbox(
value: selectedEquipmentIds.contains(
'${equipment.id}:${equipment.status}',
),
onChanged:
(isSelected) => onEquipmentSelected(
equipment.id,
equipment.status,
isSelected,
),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
),
DataCell(Text('${index + 1}')),
if (showDetailedColumns)
DataCell(
Text(
EquipmentDisplayHelper.formatManufacturer(
equipment.equipment.manufacturer,
),
),
),
DataCell(
Text(
EquipmentDisplayHelper.formatEquipmentName(
equipment.equipment.name,
),
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
if (showDetailedColumns)
DataCell(buildCategoryWithTooltip(equipment)),
if (showDetailedColumns)
DataCell(
Text(
equipment.status == 'I' &&
equipment is UnifiedEquipment &&
equipment.type != null
? equipment.type!
: '-',
),
),
if (showDetailedColumns)
DataCell(
Text(
EquipmentDisplayHelper.formatSerialNumber(
equipment.equipment.serialNumber,
),
),
),
DataCell(
Text(
'${equipment.equipment.quantity}',
textAlign: TextAlign.center,
),
),
DataCell(
Text(EquipmentDisplayHelper.formatDate(equipment.date)),
),
DataCell(EquipmentStatusChip(status: equipment.status)),
if (showDetailedColumns) ...[
DataCell(
Text(
isOutStock
? getOutEquipmentInfo(equipment.id!, 'company')
: '-',
),
),
DataCell(
Text(
isOutStock
? getOutEquipmentInfo(equipment.id!, 'manager')
: '-',
),
),
DataCell(
Text(
isOutStock
? getOutEquipmentInfo(equipment.id!, 'license')
: '-',
),
),
] else
DataCell(
isOutStock
? _buildCompactOutInfo(equipment.id!)
: const Text('-'),
),
DataCell(
Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(
Icons.edit,
color: Colors.blue,
size: 20,
),
constraints: const BoxConstraints(),
padding: const EdgeInsets.all(5),
onPressed:
() => onEdit(equipment.id!, equipment.status),
),
IconButton(
icon: const Icon(
Icons.delete,
color: Colors.red,
size: 20,
),
constraints: const BoxConstraints(),
padding: const EdgeInsets.all(5),
onPressed:
() => onDelete(equipment.id!, equipment.status),
),
],
),
),
],
);
}).toList(),
);
}
}