backup: 사용하지 않는 파일 삭제 전 복구 지점
- 전체 371개 파일 중 82개 미사용 파일 식별 - Phase 1: 33개 파일 삭제 예정 (100% 안전) - Phase 2: 30개 파일 삭제 검토 예정 - Phase 3: 19개 파일 수동 검토 예정 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,7 @@ class EquipmentInFormScreen extends StatefulWidget {
|
||||
class _EquipmentInFormScreenState extends State<EquipmentInFormScreen> {
|
||||
late EquipmentInFormController _controller;
|
||||
late TextEditingController _serialNumberController;
|
||||
late TextEditingController _barcodeController;
|
||||
late TextEditingController _initialStockController;
|
||||
late TextEditingController _purchasePriceController;
|
||||
Future<void>? _initFuture;
|
||||
@@ -49,6 +50,7 @@ class _EquipmentInFormScreenState extends State<EquipmentInFormScreen> {
|
||||
|
||||
// TextEditingController 초기화
|
||||
_serialNumberController = TextEditingController(text: _controller.serialNumber);
|
||||
_barcodeController = TextEditingController(text: _controller.barcode);
|
||||
_initialStockController = TextEditingController(text: _controller.initialStock.toString());
|
||||
_purchasePriceController = TextEditingController(
|
||||
text: _controller.purchasePrice != null
|
||||
@@ -62,6 +64,7 @@ class _EquipmentInFormScreenState extends State<EquipmentInFormScreen> {
|
||||
// 데이터 로드 후 컨트롤러 업데이트
|
||||
setState(() {
|
||||
_serialNumberController.text = _controller.serialNumber;
|
||||
_barcodeController.text = _controller.barcode;
|
||||
_purchasePriceController.text = _controller.purchasePrice != null
|
||||
? CurrencyFormatter.formatKRW(_controller.purchasePrice)
|
||||
: '';
|
||||
@@ -73,7 +76,7 @@ class _EquipmentInFormScreenState extends State<EquipmentInFormScreen> {
|
||||
_controller.removeListener(_onControllerUpdated);
|
||||
_controller.dispose();
|
||||
_serialNumberController.dispose();
|
||||
_serialNumberController.dispose();
|
||||
_barcodeController.dispose();
|
||||
_initialStockController.dispose();
|
||||
_purchasePriceController.dispose();
|
||||
super.dispose();
|
||||
@@ -167,6 +170,8 @@ class _EquipmentInFormScreenState extends State<EquipmentInFormScreen> {
|
||||
const SizedBox(height: 24),
|
||||
_buildPurchaseSection(),
|
||||
const SizedBox(height: 24),
|
||||
_buildWarrantySection(),
|
||||
const SizedBox(height: 24),
|
||||
_buildRemarkSection(),
|
||||
],
|
||||
),
|
||||
@@ -183,6 +188,7 @@ class _EquipmentInFormScreenState extends State<EquipmentInFormScreen> {
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'기본 정보',
|
||||
@@ -192,7 +198,22 @@ class _EquipmentInFormScreenState extends State<EquipmentInFormScreen> {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 장비 번호 (필수)
|
||||
// 1. 제조사/모델 정보 (수정 모드: 읽기 전용, 생성 모드: 선택)
|
||||
if (_controller.isEditMode)
|
||||
..._buildReadOnlyVendorModel()
|
||||
else
|
||||
Container(
|
||||
width: double.infinity,
|
||||
child: EquipmentVendorModelSelector(
|
||||
initialVendorId: _controller.vendorId,
|
||||
initialModelId: _controller.modelsId,
|
||||
onChanged: _controller.onVendorModelChanged,
|
||||
isReadOnly: false,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 2. 장비 번호 (필수)
|
||||
ShadInputFormField(
|
||||
controller: _serialNumberController,
|
||||
readOnly: _controller.isFieldReadOnly('serialNumber'),
|
||||
@@ -202,40 +223,27 @@ class _EquipmentInFormScreenState extends State<EquipmentInFormScreen> {
|
||||
label: Text(_controller.isFieldReadOnly('serialNumber')
|
||||
? '장비 번호 * 🔒' : '장비 번호 *'),
|
||||
validator: (value) {
|
||||
if (value.trim().isEmpty ?? true) {
|
||||
if (value?.trim().isEmpty ?? true) {
|
||||
return '장비 번호는 필수입니다';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onChanged: _controller.isFieldReadOnly('serialNumber') ? null : (value) {
|
||||
_controller.serialNumber = value.trim() ?? '';
|
||||
_controller.serialNumber = value?.trim() ?? '';
|
||||
setState(() {});
|
||||
print('DEBUG [장비번호 입력] value: "$value", controller.serialNumber: "${_controller.serialNumber}"');
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Vendor→Model cascade 선택기
|
||||
EquipmentVendorModelSelector(
|
||||
initialVendorId: _controller.vendorId,
|
||||
initialModelId: _controller.modelsId,
|
||||
onChanged: _controller.onVendorModelChanged,
|
||||
isReadOnly: _controller.isFieldReadOnly('modelsId'),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 시리얼 번호 (선택)
|
||||
// 3. 바코드 (선택사항)
|
||||
ShadInputFormField(
|
||||
controller: _serialNumberController,
|
||||
readOnly: _controller.isFieldReadOnly('serialNumber'),
|
||||
placeholder: Text(_controller.isFieldReadOnly('serialNumber')
|
||||
? '수정불가' : '시리얼 번호를 입력하세요'),
|
||||
label: Text(_controller.isFieldReadOnly('serialNumber')
|
||||
? '시리얼 번호 🔒' : '시리얼 번호'),
|
||||
onChanged: _controller.isFieldReadOnly('serialNumber') ? null : (value) {
|
||||
_controller.serialNumber = value.trim() ?? '';
|
||||
setState(() {});
|
||||
print('DEBUG [시리얼번호 입력] value: "$value", controller.serialNumber: "${_controller.serialNumber}"');
|
||||
controller: _barcodeController,
|
||||
placeholder: const Text('바코드를 입력하세요'),
|
||||
label: const Text('바코드'),
|
||||
onChanged: (value) {
|
||||
_controller.barcode = value?.trim() ?? '';
|
||||
print('DEBUG [바코드 입력] value: "$value", controller.barcode: "${_controller.barcode}"');
|
||||
},
|
||||
),
|
||||
],
|
||||
@@ -260,30 +268,32 @@ class _EquipmentInFormScreenState extends State<EquipmentInFormScreen> {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 구매처 (드롭다운 전용)
|
||||
ShadSelect<int>(
|
||||
initialValue: _getValidCompanyId(),
|
||||
placeholder: const Text('구매처를 선택하세요'),
|
||||
options: _controller.companies.entries.map((entry) =>
|
||||
ShadOption(
|
||||
value: entry.key,
|
||||
child: Text(entry.value),
|
||||
)
|
||||
).toList(),
|
||||
selectedOptionBuilder: (context, value) {
|
||||
// companies가 비어있거나 해당 value가 없는 경우 처리
|
||||
if (_controller.companies.isEmpty) {
|
||||
return const Text('로딩중...');
|
||||
}
|
||||
return Text(_controller.companies[value] ?? '선택하세요');
|
||||
},
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_controller.selectedCompanyId = value;
|
||||
});
|
||||
print('DEBUG [구매처 선택] value: $value, companies: ${_controller.companies.length}');
|
||||
},
|
||||
),
|
||||
// 구매처 (수정 모드: 읽기 전용, 생성 모드: 선택)
|
||||
if (_controller.isEditMode)
|
||||
_buildReadOnlyCompany()
|
||||
else
|
||||
ShadSelect<int>(
|
||||
initialValue: _getValidCompanyId(),
|
||||
placeholder: const Text('구매처를 선택하세요'),
|
||||
options: _controller.companies.entries.map((entry) =>
|
||||
ShadOption(
|
||||
value: entry.key,
|
||||
child: Text(entry.value),
|
||||
)
|
||||
).toList(),
|
||||
selectedOptionBuilder: (context, value) {
|
||||
if (_controller.companies.isEmpty) {
|
||||
return const Text('로딩중...');
|
||||
}
|
||||
return Text(_controller.companies[value] ?? '선택하세요');
|
||||
},
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_controller.selectedCompanyId = value;
|
||||
});
|
||||
print('DEBUG [구매처 선택] value: $value, companies: ${_controller.companies.length}');
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 입고지 (드롭다운 전용)
|
||||
@@ -396,7 +406,7 @@ class _EquipmentInFormScreenState extends State<EquipmentInFormScreen> {
|
||||
Text(
|
||||
_controller.purchaseDate != null
|
||||
? '${_controller.purchaseDate!.year}-${_controller.purchaseDate!.month.toString().padLeft(2, '0')}-${_controller.purchaseDate!.day.toString().padLeft(2, '0')}'
|
||||
: _controller.isFieldReadOnly('purchaseDate') ? '구매일 미설정' : '날짜 선택',
|
||||
: _controller.isFieldReadOnly('purchaseDate') ? '구매일 미설정' : '현재 날짜',
|
||||
style: TextStyle(
|
||||
color: _controller.isFieldReadOnly('purchaseDate')
|
||||
? Colors.grey[600]
|
||||
@@ -444,6 +454,140 @@ class _EquipmentInFormScreenState extends State<EquipmentInFormScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildWarrantySection() {
|
||||
return ShadCard(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'워런티 정보 *',
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 워런티 번호 (필수)
|
||||
ShadInputFormField(
|
||||
controller: _controller.warrantyNumberController,
|
||||
label: const Text('워런티 번호 *'),
|
||||
placeholder: const Text('워런티 번호를 입력하세요'),
|
||||
validator: (value) {
|
||||
if (value.trim().isEmpty ?? true) {
|
||||
return '워런티 번호는 필수입니다';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
Row(
|
||||
children: [
|
||||
// 워런티 시작일 (필수)
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
final date = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: _controller.warrantyStartDate,
|
||||
firstDate: DateTime(2000),
|
||||
lastDate: DateTime(2100),
|
||||
);
|
||||
if (date != null) {
|
||||
setState(() {
|
||||
_controller.warrantyStartDate = date;
|
||||
});
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Theme.of(context).dividerColor),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${_controller.warrantyStartDate.year}-${_controller.warrantyStartDate.month.toString().padLeft(2, '0')}-${_controller.warrantyStartDate.day.toString().padLeft(2, '0')}',
|
||||
),
|
||||
const Icon(Icons.calendar_today, size: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
|
||||
// 워런티 만료일 (필수)
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
final date = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: _controller.warrantyEndDate,
|
||||
firstDate: _controller.warrantyStartDate,
|
||||
lastDate: DateTime(2100),
|
||||
);
|
||||
if (date != null) {
|
||||
setState(() {
|
||||
_controller.warrantyEndDate = date;
|
||||
});
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Theme.of(context).dividerColor),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${_controller.warrantyEndDate.year}-${_controller.warrantyEndDate.month.toString().padLeft(2, '0')}-${_controller.warrantyEndDate.day.toString().padLeft(2, '0')}',
|
||||
),
|
||||
const Icon(Icons.calendar_today, size: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 워런티 기간 표시
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border: Border.all(color: Theme.of(context).dividerColor),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.info_outline,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'워런티 기간: ${_controller.getWarrantyPeriodSummary()}',
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRemarkSection() {
|
||||
return ShadCard(
|
||||
child: Padding(
|
||||
@@ -471,4 +615,43 @@ class _EquipmentInFormScreenState extends State<EquipmentInFormScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
/// 읽기 전용 구매처 정보 표시 (백엔드 JOIN 데이터 활용)
|
||||
Widget _buildReadOnlyCompany() {
|
||||
// preloadedEquipment가 있으면 companyName 사용, 없으면 기본값
|
||||
final companyName = _controller.preloadedEquipment?.companyName ??
|
||||
(_controller.companies.isNotEmpty && _controller.selectedCompanyId != null
|
||||
? _controller.companies[_controller.selectedCompanyId]
|
||||
: '구매처 정보 없음');
|
||||
|
||||
return ShadInputFormField(
|
||||
readOnly: true,
|
||||
label: const Text('구매처 🔒'),
|
||||
initialValue: companyName,
|
||||
);
|
||||
}
|
||||
|
||||
/// 읽기 전용 제조사/모델 정보 표시 (백엔드 JOIN 데이터 활용)
|
||||
List<Widget> _buildReadOnlyVendorModel() {
|
||||
return [
|
||||
// 제조사 (읽기 전용)
|
||||
ShadInputFormField(
|
||||
readOnly: true,
|
||||
label: const Text('제조사 * 🔒'),
|
||||
initialValue: _controller.manufacturer.isNotEmpty
|
||||
? _controller.manufacturer
|
||||
: '제조사 정보 없음',
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 모델 (읽기 전용)
|
||||
ShadInputFormField(
|
||||
readOnly: true,
|
||||
label: const Text('모델 * 🔒'),
|
||||
initialValue: _controller.name.isNotEmpty
|
||||
? _controller.name
|
||||
: '모델 정보 없음',
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user