프로젝트 최초 커밋
This commit is contained in:
172
lib/screens/equipment/widgets/autocomplete_text_field.dart
Normal file
172
lib/screens/equipment/widgets/autocomplete_text_field.dart
Normal file
@@ -0,0 +1,172 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 자동완성 텍스트 필드 위젯
|
||||
///
|
||||
/// 입력, 드롭다운, 포커스, 필터링, 선택 기능을 모두 포함한다.
|
||||
class AutocompleteTextField extends StatefulWidget {
|
||||
final String label;
|
||||
final String value;
|
||||
final List<String> items;
|
||||
final bool isRequired;
|
||||
final String hintText;
|
||||
final void Function(String) onChanged;
|
||||
final void Function(String) onSelected;
|
||||
final FocusNode? focusNode;
|
||||
|
||||
const AutocompleteTextField({
|
||||
Key? key,
|
||||
required this.label,
|
||||
required this.value,
|
||||
required this.items,
|
||||
required this.onChanged,
|
||||
required this.onSelected,
|
||||
this.isRequired = false,
|
||||
this.hintText = '',
|
||||
this.focusNode,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<AutocompleteTextField> createState() => _AutocompleteTextFieldState();
|
||||
}
|
||||
|
||||
class _AutocompleteTextFieldState extends State<AutocompleteTextField> {
|
||||
late final TextEditingController _controller;
|
||||
late final FocusNode _focusNode;
|
||||
late List<String> _filteredItems;
|
||||
bool _showDropdown = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = TextEditingController(text: widget.value);
|
||||
_focusNode = widget.focusNode ?? FocusNode();
|
||||
_filteredItems = List.from(widget.items);
|
||||
_controller.addListener(_onTextChanged);
|
||||
_focusNode.addListener(() {
|
||||
setState(() {
|
||||
if (_focusNode.hasFocus) {
|
||||
_showDropdown = _filteredItems.isNotEmpty;
|
||||
} else {
|
||||
_showDropdown = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant AutocompleteTextField oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.value != _controller.text) {
|
||||
_controller.text = widget.value;
|
||||
}
|
||||
if (widget.items != oldWidget.items) {
|
||||
_filteredItems = List.from(widget.items);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
if (widget.focusNode == null) {
|
||||
_focusNode.dispose();
|
||||
}
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// 입력값 변경 시 필터링
|
||||
void _onTextChanged() {
|
||||
final text = _controller.text;
|
||||
setState(() {
|
||||
if (text.isEmpty) {
|
||||
_filteredItems = List.from(widget.items);
|
||||
} else {
|
||||
_filteredItems =
|
||||
widget.items
|
||||
.where(
|
||||
(item) => item.toLowerCase().contains(text.toLowerCase()),
|
||||
)
|
||||
.toList();
|
||||
// 시작 부분이 일치하는 항목 우선 정렬
|
||||
_filteredItems.sort((a, b) {
|
||||
bool aStartsWith = a.toLowerCase().startsWith(text.toLowerCase());
|
||||
bool bStartsWith = b.toLowerCase().startsWith(text.toLowerCase());
|
||||
if (aStartsWith && !bStartsWith) return -1;
|
||||
if (!aStartsWith && bStartsWith) return 1;
|
||||
return a.compareTo(b);
|
||||
});
|
||||
}
|
||||
_showDropdown = _filteredItems.isNotEmpty && _focusNode.hasFocus;
|
||||
widget.onChanged(text);
|
||||
});
|
||||
}
|
||||
|
||||
void _handleSelect(String value) {
|
||||
setState(() {
|
||||
_controller.text = value;
|
||||
_showDropdown = false;
|
||||
});
|
||||
widget.onSelected(value);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: _controller,
|
||||
focusNode: _focusNode,
|
||||
decoration: InputDecoration(
|
||||
labelText: widget.label,
|
||||
hintText: widget.hintText,
|
||||
),
|
||||
validator: (value) {
|
||||
if (widget.isRequired && (value == null || value.isEmpty)) {
|
||||
return '${widget.label}을(를) 입력해주세요';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onSaved: (value) {
|
||||
widget.onSelected(value ?? '');
|
||||
},
|
||||
),
|
||||
if (_showDropdown)
|
||||
Positioned(
|
||||
top: 50,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
border: Border.all(color: Colors.grey.shade300),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.3),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
constraints: const BoxConstraints(maxHeight: 200),
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: _filteredItems.length,
|
||||
itemBuilder: (context, index) {
|
||||
return InkWell(
|
||||
onTap: () => _handleSelect(_filteredItems[index]),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 8,
|
||||
),
|
||||
child: Text(_filteredItems[index]),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
48
lib/screens/equipment/widgets/equipment_out_info.dart
Normal file
48
lib/screens/equipment/widgets/equipment_out_info.dart
Normal file
@@ -0,0 +1,48 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
// 출고 정보(회사, 담당자, 라이센스 등)를 아이콘과 함께 표시하는 위젯
|
||||
class EquipmentOutInfoIcon extends StatelessWidget {
|
||||
final String infoType; // company, manager, license 등
|
||||
final String text;
|
||||
|
||||
const EquipmentOutInfoIcon({
|
||||
super.key,
|
||||
required this.infoType,
|
||||
required this.text,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// infoType에 따라 아이콘 결정
|
||||
IconData iconData;
|
||||
switch (infoType) {
|
||||
case 'company':
|
||||
iconData = Icons.business;
|
||||
break;
|
||||
case 'manager':
|
||||
iconData = Icons.person;
|
||||
break;
|
||||
case 'license':
|
||||
iconData = Icons.book;
|
||||
break;
|
||||
default:
|
||||
iconData = Icons.info;
|
||||
}
|
||||
|
||||
// 아이콘과 텍스트를 Row로 표시
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(iconData, size: 14, color: Colors.grey[700]),
|
||||
const SizedBox(width: 4),
|
||||
Flexible(
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(fontSize: 13, color: Colors.grey[800]),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
61
lib/screens/equipment/widgets/equipment_status_chip.dart
Normal file
61
lib/screens/equipment/widgets/equipment_status_chip.dart
Normal file
@@ -0,0 +1,61 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:superport/utils/constants.dart';
|
||||
|
||||
// 장비 상태에 따라 칩(Chip) 위젯을 반환하는 함수형 위젯
|
||||
class EquipmentStatusChip extends StatelessWidget {
|
||||
final String status;
|
||||
|
||||
const EquipmentStatusChip({super.key, required this.status});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// 상태별 칩 색상 및 텍스트 지정
|
||||
Color backgroundColor;
|
||||
String statusText;
|
||||
|
||||
switch (status) {
|
||||
case EquipmentStatus.in_:
|
||||
backgroundColor = Colors.green;
|
||||
statusText = '입고';
|
||||
break;
|
||||
case EquipmentStatus.out:
|
||||
backgroundColor = Colors.orange;
|
||||
statusText = '출고';
|
||||
break;
|
||||
case EquipmentStatus.rent:
|
||||
backgroundColor = Colors.blue;
|
||||
statusText = '대여';
|
||||
break;
|
||||
case EquipmentStatus.repair:
|
||||
backgroundColor = Colors.blue;
|
||||
statusText = '수리중';
|
||||
break;
|
||||
case EquipmentStatus.damaged:
|
||||
backgroundColor = Colors.red;
|
||||
statusText = '손상';
|
||||
break;
|
||||
case EquipmentStatus.lost:
|
||||
backgroundColor = Colors.purple;
|
||||
statusText = '분실';
|
||||
break;
|
||||
case EquipmentStatus.etc:
|
||||
backgroundColor = Colors.grey;
|
||||
statusText = '기타';
|
||||
break;
|
||||
default:
|
||||
backgroundColor = Colors.grey;
|
||||
statusText = '알 수 없음';
|
||||
}
|
||||
|
||||
// 칩 위젯 반환
|
||||
return Chip(
|
||||
label: Text(
|
||||
statusText,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 12),
|
||||
),
|
||||
backgroundColor: backgroundColor,
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 5),
|
||||
);
|
||||
}
|
||||
}
|
||||
155
lib/screens/equipment/widgets/equipment_summary_card.dart
Normal file
155
lib/screens/equipment/widgets/equipment_summary_card.dart
Normal file
@@ -0,0 +1,155 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:superport/models/equipment_unified_model.dart';
|
||||
import 'package:superport/screens/equipment/widgets/equipment_summary_row.dart';
|
||||
|
||||
// 다중 선택 장비 요약 카드
|
||||
class EquipmentMultiSummaryCard extends StatelessWidget {
|
||||
final List<Map<String, dynamic>> selectedEquipments;
|
||||
const EquipmentMultiSummaryCard({
|
||||
super.key,
|
||||
required this.selectedEquipments,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Text(
|
||||
'선택된 장비 목록 (${selectedEquipments.length}개)',
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
...selectedEquipments.map((equipmentData) {
|
||||
final equipment = equipmentData['equipment'] as Equipment;
|
||||
return EquipmentSingleSummaryCard(equipment: equipment);
|
||||
}).toList(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 단일 장비 요약 카드
|
||||
class EquipmentSingleSummaryCard extends StatelessWidget {
|
||||
final Equipment equipment;
|
||||
const EquipmentSingleSummaryCard({super.key, required this.equipment});
|
||||
|
||||
// 날짜 포맷 유틸리티
|
||||
String _formatDate(DateTime? date) {
|
||||
if (date == null) return '정보 없음';
|
||||
return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}';
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
elevation: 3,
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.inventory,
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
equipment.name.isNotEmpty ? equipment.name : '이름 없음',
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.shade100,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: Colors.blue.shade300),
|
||||
),
|
||||
child: Text(
|
||||
'수량: ${equipment.quantity}',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 12,
|
||||
color: Colors.blue.shade800,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(thickness: 1.5),
|
||||
EquipmentSummaryRow(
|
||||
label: '제조사',
|
||||
value:
|
||||
equipment.manufacturer.isNotEmpty
|
||||
? equipment.manufacturer
|
||||
: '정보 없음',
|
||||
),
|
||||
EquipmentSummaryRow(
|
||||
label: '카테고리',
|
||||
value:
|
||||
equipment.category.isNotEmpty
|
||||
? '${equipment.category} > ${equipment.subCategory} > ${equipment.subSubCategory}'
|
||||
: '정보 없음',
|
||||
),
|
||||
EquipmentSummaryRow(
|
||||
label: '시리얼 번호',
|
||||
value:
|
||||
(equipment.serialNumber != null &&
|
||||
equipment.serialNumber!.isNotEmpty)
|
||||
? equipment.serialNumber!
|
||||
: '정보 없음',
|
||||
),
|
||||
EquipmentSummaryRow(
|
||||
label: '출고 수량',
|
||||
value: equipment.quantity.toString(),
|
||||
),
|
||||
EquipmentSummaryRow(
|
||||
label: '입고일',
|
||||
value: _formatDate(equipment.inDate),
|
||||
),
|
||||
// 워런티 정보 추가
|
||||
if (equipment.warrantyLicense != null &&
|
||||
equipment.warrantyLicense!.isNotEmpty)
|
||||
EquipmentSummaryRow(
|
||||
label: '워런티 라이센스',
|
||||
value: equipment.warrantyLicense!,
|
||||
),
|
||||
EquipmentSummaryRow(
|
||||
label: '워런티 시작일',
|
||||
value: _formatDate(equipment.warrantyStartDate),
|
||||
),
|
||||
EquipmentSummaryRow(
|
||||
label: '워런티 종료일',
|
||||
value: _formatDate(equipment.warrantyEndDate),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
41
lib/screens/equipment/widgets/equipment_summary_row.dart
Normal file
41
lib/screens/equipment/widgets/equipment_summary_row.dart
Normal file
@@ -0,0 +1,41 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
// 장비 요약 정보 행 위젯 (SRP, 재사용성)
|
||||
class EquipmentSummaryRow extends StatelessWidget {
|
||||
final String label;
|
||||
final String value;
|
||||
|
||||
const EquipmentSummaryRow({
|
||||
super.key,
|
||||
required this.label,
|
||||
required this.value,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 6.0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 110,
|
||||
child: Text(
|
||||
'$label:',
|
||||
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
color: value == '정보 없음' ? Colors.grey.shade600 : Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
236
lib/screens/equipment/widgets/equipment_table.dart
Normal file
236
lib/screens/equipment/widgets/equipment_table.dart
Normal file
@@ -0,0 +1,236 @@
|
||||
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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user