feat: API 연동 개선 및 라이선스 모델 확장
- 라이선스 모델 전면 개편 (상세 필드 추가, 계산 필드 구현) - API 응답 처리 개선 (HTTP 상태 코드 기반) - 장비 출고 폼 컨트롤러 추가 - 회사 지점 정보 모델 추가 - 공통 데이터 모델 구조 추가 - 전체 서비스 레이어 API 호출 방식 통일 - UI 컴포넌트 마이너 개선
This commit is contained in:
@@ -24,11 +24,35 @@ class LicenseFormController extends ChangeNotifier {
|
||||
int _durationMonths = 12; // 기본값: 12개월
|
||||
String _visitCycle = '미방문'; // 기본값: 미방문
|
||||
|
||||
// isEditMode setter
|
||||
set isEditMode(bool value) {
|
||||
_isEditMode = value;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// name setter
|
||||
set name(String value) {
|
||||
_name = value;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// durationMonths setter
|
||||
set durationMonths(int value) {
|
||||
_durationMonths = value;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// visitCycle setter
|
||||
set visitCycle(String value) {
|
||||
_visitCycle = value;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
LicenseFormController({
|
||||
this.useApi = true,
|
||||
this.mockDataService,
|
||||
this.useApi = false,
|
||||
MockDataService? dataService,
|
||||
int? licenseId,
|
||||
}) {
|
||||
}) : mockDataService = dataService ?? MockDataService() {
|
||||
if (useApi && GetIt.instance.isRegistered<LicenseService>()) {
|
||||
_licenseService = GetIt.instance<LicenseService>();
|
||||
}
|
||||
@@ -89,10 +113,11 @@ class LicenseFormController extends ChangeNotifier {
|
||||
}
|
||||
|
||||
if (_originalLicense != null) {
|
||||
_name = _originalLicense!.name;
|
||||
_companyId = _originalLicense!.companyId;
|
||||
_durationMonths = _originalLicense!.durationMonths;
|
||||
_visitCycle = _originalLicense!.visitCycle;
|
||||
_name = _originalLicense!.productName ?? '';
|
||||
_companyId = _originalLicense!.companyId ?? 1;
|
||||
// durationMonths와 visitCycle은 License 모델에 없으므로 기본값 유지
|
||||
// _durationMonths = _originalLicense!.durationMonths;
|
||||
// _visitCycle = _originalLicense!.visitCycle;
|
||||
}
|
||||
} catch (e) {
|
||||
_error = e.toString();
|
||||
@@ -115,10 +140,14 @@ class LicenseFormController extends ChangeNotifier {
|
||||
try {
|
||||
final license = License(
|
||||
id: _isEditMode ? _licenseId : null,
|
||||
licenseKey: 'LIC-${DateTime.now().millisecondsSinceEpoch}',
|
||||
productName: _name,
|
||||
companyId: _companyId,
|
||||
name: _name,
|
||||
durationMonths: _durationMonths,
|
||||
visitCycle: _visitCycle,
|
||||
// durationMonths와 visitCycle은 License 모델에 없음
|
||||
// 대신 expiryDate를 설정
|
||||
purchaseDate: DateTime.now(),
|
||||
expiryDate: DateTime.now().add(Duration(days: _durationMonths * 30)),
|
||||
remark: '방문주기: $_visitCycle',
|
||||
);
|
||||
|
||||
if (useApi && GetIt.instance.isRegistered<LicenseService>()) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:superport/core/errors/failures.dart';
|
||||
import 'package:superport/models/license_model.dart';
|
||||
import 'package:superport/services/license_service.dart';
|
||||
import 'package:superport/services/mock_data_service.dart';
|
||||
@@ -24,8 +26,13 @@ class LicenseListController extends ChangeNotifier {
|
||||
int? _selectedCompanyId;
|
||||
bool? _isActive;
|
||||
String? _licenseType;
|
||||
String _sortBy = 'expiry_date';
|
||||
String _sortOrder = 'asc';
|
||||
|
||||
// 검색 디바운스를 위한 타이머
|
||||
Timer? _debounceTimer;
|
||||
|
||||
LicenseListController({this.useApi = true, this.mockDataService}) {
|
||||
LicenseListController({this.useApi = false, this.mockDataService}) {
|
||||
if (useApi && GetIt.instance.isRegistered<LicenseService>()) {
|
||||
_licenseService = GetIt.instance<LicenseService>();
|
||||
}
|
||||
@@ -137,11 +144,24 @@ class LicenseListController extends ChangeNotifier {
|
||||
await loadData(isInitialLoad: false);
|
||||
}
|
||||
|
||||
// 검색
|
||||
// 검색 (디바운싱 적용)
|
||||
void search(String query) {
|
||||
_searchQuery = query;
|
||||
_applySearchFilter();
|
||||
notifyListeners();
|
||||
|
||||
// 기존 타이머 취소
|
||||
_debounceTimer?.cancel();
|
||||
|
||||
// Mock 데이터는 즉시 검색
|
||||
if (!useApi) {
|
||||
_applySearchFilter();
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
|
||||
// API 검색은 디바운싱 적용 (300ms)
|
||||
_debounceTimer = Timer(const Duration(milliseconds: 300), () {
|
||||
loadData();
|
||||
});
|
||||
}
|
||||
|
||||
// 검색 필터 적용
|
||||
@@ -212,10 +232,12 @@ class LicenseListController extends ChangeNotifier {
|
||||
final allLicenses = mockDataService?.getAllLicenses() ?? [];
|
||||
|
||||
return allLicenses.where((license) {
|
||||
// Mock 데이터는 만료일이 없으므로 임의로 계산
|
||||
final expiryDate = now.add(Duration(days: license.durationMonths * 30));
|
||||
final daysUntilExpiry = expiryDate.difference(now).inDays;
|
||||
return daysUntilExpiry > 0 && daysUntilExpiry <= days;
|
||||
// 실제 License 모델에서 만료일 확인
|
||||
if (license.expiryDate != null) {
|
||||
final daysUntilExpiry = license.expiryDate!.difference(now).inDays;
|
||||
return daysUntilExpiry > 0 && daysUntilExpiry <= days;
|
||||
}
|
||||
return false;
|
||||
}).toList();
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -224,4 +246,69 @@ class LicenseListController extends ChangeNotifier {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// 상태별 라이선스 개수 조회
|
||||
Future<Map<String, int>> getLicenseStatusCounts() async {
|
||||
if (useApi && GetIt.instance.isRegistered<LicenseService>()) {
|
||||
try {
|
||||
// API에서 상태별 개수 조회 (실제로는 별도 엔드포인트가 있다면 사용)
|
||||
final activeCount = await _licenseService.getTotalLicenses(isActive: true);
|
||||
final inactiveCount = await _licenseService.getTotalLicenses(isActive: false);
|
||||
final expiringLicenses = await getExpiringLicenses(days: 30);
|
||||
|
||||
return {
|
||||
'active': activeCount,
|
||||
'inactive': inactiveCount,
|
||||
'expiring': expiringLicenses.length,
|
||||
'total': activeCount + inactiveCount,
|
||||
};
|
||||
} catch (e) {
|
||||
return {'active': 0, 'inactive': 0, 'expiring': 0, 'total': 0};
|
||||
}
|
||||
} else {
|
||||
// Mock 데이터에서 계산
|
||||
final allLicenses = mockDataService?.getAllLicenses() ?? [];
|
||||
final now = DateTime.now();
|
||||
|
||||
int activeCount = 0;
|
||||
int expiredCount = 0;
|
||||
int expiringCount = 0;
|
||||
|
||||
for (var license in allLicenses) {
|
||||
if (license.isActive) {
|
||||
activeCount++;
|
||||
|
||||
if (license.expiryDate != null) {
|
||||
final daysUntilExpiry = license.expiryDate!.difference(now).inDays;
|
||||
if (daysUntilExpiry <= 0) {
|
||||
expiredCount++;
|
||||
} else if (daysUntilExpiry <= 30) {
|
||||
expiringCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
'active': activeCount,
|
||||
'inactive': allLicenses.length - activeCount,
|
||||
'expiring': expiringCount,
|
||||
'expired': expiredCount,
|
||||
'total': allLicenses.length,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 정렬 변경
|
||||
void sortBy(String field, String order) {
|
||||
_sortBy = field;
|
||||
_sortOrder = order;
|
||||
loadData();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_debounceTimer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,9 @@ class _MaintenanceFormScreenState extends State<MaintenanceFormScreen> {
|
||||
dataService: MockDataService(),
|
||||
licenseId: widget.maintenanceId,
|
||||
);
|
||||
_controller.isEditMode = widget.maintenanceId != null;
|
||||
if (widget.maintenanceId != null) {
|
||||
_controller.isEditMode = true;
|
||||
}
|
||||
if (_controller.isEditMode) {
|
||||
_controller.loadLicense();
|
||||
// TODO: 기존 데이터 로딩 시 _selectedVisitCycle, _selectedInspectionType, _durationMonths 값 세팅 필요
|
||||
@@ -201,10 +203,10 @@ class _MaintenanceFormScreenState extends State<MaintenanceFormScreen> {
|
||||
_controller.durationMonths = _durationMonths;
|
||||
_controller.visitCycle = _selectedVisitCycle;
|
||||
// 점검형태 저장 로직 필요 시 추가
|
||||
setState(() {
|
||||
_controller.saveLicense(() {
|
||||
_controller.saveLicense().then((success) {
|
||||
if (success) {
|
||||
Navigator.pop(context, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -23,7 +23,7 @@ class _LicenseListRedesignState extends State<LicenseListRedesign> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = LicenseListController(dataService: _dataService);
|
||||
_controller = LicenseListController(mockDataService: _dataService);
|
||||
_controller.loadData();
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ class _LicenseListRedesignState extends State<LicenseListRedesign> {
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
_getCompanyName(license.companyId),
|
||||
_getCompanyName(license.companyId ?? 0),
|
||||
style: ShadcnTheme.bodySmall,
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user