feat: V/R 유지보수 시스템 전환 및 대시보드 테이블 형태 완성
Some checks failed
Flutter Test & Quality Check / Test on macos-latest (push) Has been cancelled
Flutter Test & Quality Check / Test on ubuntu-latest (push) Has been cancelled
Flutter Test & Quality Check / Build APK (push) Has been cancelled

- V/R 시스템 완전 전환: WARRANTY/CONTRACT/INSPECTION → V(방문)/R(원격)
- 유지보수 대시보드 카드 → StandardDataTable 테이블 형태 전환
- "조회중..." 문제 해결: 백엔드 직접 필드 사용 (equipment_model, company_name)
- MaintenanceDto 신규 필드 추가: company_id, company_name, equipment_serial, equipment_model
- preloadEquipmentData 비활성화로 불필요한 equipment-history API 호출 제거
- CO-STAR 프레임워크 적용 및 CLAUDE.md v3.0 업데이트
- Flutter Analyze ERROR: 0 유지, 100% shadcn_ui 컴플라이언스

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
JiWoong Sul
2025-09-05 14:33:20 +09:00
parent 2c20999025
commit 519e1883a3
46 changed files with 7804 additions and 1034 deletions

View File

@@ -102,10 +102,20 @@ class _EquipmentInFormScreenState extends State<EquipmentInFormScreen> {
int? _getValidWarehouseId() {
if (_controller.selectedWarehouseId == null) return null;
// 데이터 로딩 중이면 선택한 값을 유지 (validation 스킵)
if (_controller.warehouses.isEmpty) {
print('DEBUG [_getValidWarehouseId] 데이터 로딩 중 - 선택한 값 유지: ${_controller.selectedWarehouseId}');
return _controller.selectedWarehouseId;
}
final isValid = _controller.warehouses.containsKey(_controller.selectedWarehouseId);
print('DEBUG [_getValidWarehouseId] selectedWarehouseId: ${_controller.selectedWarehouseId}, isValid: $isValid, available warehouses: ${_controller.warehouses.length}');
return isValid ? _controller.selectedWarehouseId : null;
// 유효하지 않더라도 선택한 값을 유지 (사용자 선택 존중)
if (!isValid) {
print('WARNING [_getValidWarehouseId] 선택한 창고가 목록에 없음 - 그래도 사용자 선택 유지');
}
return _controller.selectedWarehouseId;
}
Future<void> _onSave() async {
@@ -296,30 +306,49 @@ class _EquipmentInFormScreenState extends State<EquipmentInFormScreen> {
),
const SizedBox(height: 16),
// 입고지 (드롭다운 전용)
ShadSelect<int>(
initialValue: _getValidWarehouseId(),
placeholder: const Text('입고지를 선택하세요'),
options: _controller.warehouses.entries.map((entry) =>
ShadOption(
value: entry.key,
child: Text(entry.value),
)
).toList(),
selectedOptionBuilder: (context, value) {
// warehouses가 비어있거나 해당 value가 없는 경우 처리
if (_controller.warehouses.isEmpty) {
return const Text('로딩중...');
}
return Text(_controller.warehouses[value] ?? '선택하세요');
},
onChanged: (value) {
setState(() {
_controller.selectedWarehouseId = value;
});
print('DEBUG [입고지 선택] value: $value, warehouses: ${_controller.warehouses.length}');
},
),
// 입고지 (수정 모드: 읽기 전용, 생성 모드: 선택 가능)
if (_controller.isEditMode)
// 수정 모드: 현재 창고 정보만 표시 (변경 불가)
ShadInputFormField(
readOnly: true,
placeholder: Text(_controller.warehouses.isNotEmpty && _controller.selectedWarehouseId != null
? '${_controller.warehouses[_controller.selectedWarehouseId!] ?? "창고 정보 없음"} 🔒'
: '창고 정보 로딩중... 🔒'),
label: const Text('입고지 * (수정 불가)'),
)
else
// 생성 모드: 창고 선택 가능
ShadSelect<int>(
initialValue: _getValidWarehouseId(),
placeholder: const Text('입고지를 선택하세요 *'),
options: _controller.warehouses.entries.map((entry) =>
ShadOption(
value: entry.key,
child: Text(entry.value),
)
).toList(),
selectedOptionBuilder: (context, value) {
// warehouses가 비어있거나 해당 value가 없는 경우 처리
if (_controller.warehouses.isEmpty) {
return const Text('로딩중...');
}
return Text(_controller.warehouses[value] ?? '선택하세요');
},
onChanged: (value) {
setState(() {
_controller.selectedWarehouseId = value;
});
print('✅ [입고지 선택] 선택한 값: $value');
print('📦 [입고지 선택] 사용 가능한 창고 수: ${_controller.warehouses.length}');
print('🔍 [입고지 선택] 최종 저장될 값: ${_controller.selectedWarehouseId}');
// 선택한 창고 이름도 출력
if (_controller.warehouses.isNotEmpty && value != null) {
final warehouseName = _controller.warehouses[value] ?? '알 수 없음';
print('🏪 [입고지 선택] 선택한 창고 이름: $warehouseName');
}
},
),
const SizedBox(height: 16),
// 초기 재고 수량 (신규 등록 시에만 표시)