Files
superport/lib/screens/license/controllers/license_form_controller.dart
JiWoong Sul ef059d50ea feat: 라이선스 관리 기능 개선 및 폼 검증 강화
- LicenseDto 모델 업데이트
- 라이선스 폼 UI 개선 및 검증 로직 강화
- 라이선스 리스트 화면 필터링 기능 추가
- 만료일 관리 기능 개선

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-09 02:17:30 +09:00

335 lines
11 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:superport/models/license_model.dart';
import 'package:superport/services/license_service.dart';
import 'package:superport/services/mock_data_service.dart';
// 라이센스 폼의 상태 및 비즈니스 로직을 담당하는 컨트롤러
class LicenseFormController extends ChangeNotifier {
final bool useApi;
final MockDataService? mockDataService;
late final LicenseService _licenseService;
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
bool _isEditMode = false;
int? _licenseId;
License? _originalLicense;
bool _isLoading = false;
String? _error;
bool _isSaving = false;
// 폼 필드 값
String _name = '';
int _companyId = 1;
int _durationMonths = 12; // 기본값: 12개월
String _visitCycle = '미방문'; // 기본값: 미방문
// 추가 필드 컨트롤러
final TextEditingController productNameController = TextEditingController();
final TextEditingController licenseKeyController = TextEditingController();
final TextEditingController vendorController = TextEditingController();
final TextEditingController locationController = TextEditingController();
final TextEditingController assignedUserController = TextEditingController();
String status = '활성';
DateTime? purchaseDate;
DateTime? expiryDate;
// 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 = false,
MockDataService? dataService,
int? licenseId,
bool isExtension = false,
}) : mockDataService = dataService ?? MockDataService() {
if (useApi && GetIt.instance.isRegistered<LicenseService>()) {
_licenseService = GetIt.instance<LicenseService>();
}
if (licenseId != null && !isExtension) {
_licenseId = licenseId;
_isEditMode = true;
// loadLicense()는 별도로 호출됨
} else if (licenseId != null && isExtension) {
_licenseId = licenseId;
_isEditMode = false; // 연장 모드는 새로운 라이선스 생성
}
}
// Getters
bool get isEditMode => _isEditMode;
int? get licenseId => _licenseId;
License? get originalLicense => _originalLicense;
bool get isLoading => _isLoading;
String? get error => _error;
bool get isSaving => _isSaving;
String get name => _name;
int get companyId => _companyId;
int get durationMonths => _durationMonths;
String get visitCycle => _visitCycle;
// Setters
void setName(String value) {
_name = value;
notifyListeners();
}
void setCompanyId(int value) {
_companyId = value;
notifyListeners();
}
void setDurationMonths(int value) {
_durationMonths = value;
notifyListeners();
}
void setVisitCycle(String value) {
_visitCycle = value;
notifyListeners();
}
// 라이센스 정보 로드 (수정 모드)
Future<void> loadLicense() async {
if (_licenseId == null) return;
debugPrint('📝 loadLicense 시작 - ID: $_licenseId');
_isLoading = true;
_error = null;
notifyListeners();
try {
if (useApi && GetIt.instance.isRegistered<LicenseService>()) {
debugPrint('📝 API에서 라이센스 로드 중...');
_originalLicense = await _licenseService.getLicenseById(_licenseId!);
} else {
debugPrint('📝 Mock에서 라이센스 로드 중...');
_originalLicense = mockDataService?.getLicenseById(_licenseId!);
}
debugPrint('📝 로드된 라이센스: $_originalLicense');
if (_originalLicense != null) {
// 폼 필드에 데이터 설정
productNameController.text = _originalLicense!.productName ?? '';
licenseKeyController.text = _originalLicense!.licenseKey;
vendorController.text = _originalLicense!.vendor ?? '';
locationController.text = _originalLicense!.companyName ?? '';
assignedUserController.text = _originalLicense!.assignedUserName ?? '';
debugPrint('📝 폼 필드 설정 완료:');
debugPrint(' - 제품명: ${productNameController.text}');
debugPrint(' - 라이선스 키: ${licenseKeyController.text}');
debugPrint(' - 벤더: ${vendorController.text}');
debugPrint(' - 현위치: ${locationController.text}');
debugPrint(' - 할당 사용자: ${assignedUserController.text}');
status = _originalLicense!.isActive ? '활성' : '비활성';
purchaseDate = _originalLicense!.purchaseDate;
expiryDate = _originalLicense!.expiryDate;
_name = _originalLicense!.productName ?? '';
_companyId = _originalLicense!.companyId ?? 1;
// remark에서 방문주기 정보 추출 (있는 경우)
if (_originalLicense!.remark != null && _originalLicense!.remark!.contains('방문주기:')) {
final remarkParts = _originalLicense!.remark!.split('방문주기:');
if (remarkParts.length > 1) {
_visitCycle = remarkParts[1].trim();
}
}
}
} catch (e) {
_error = e.toString();
debugPrint('❌ 라이센스 로드 실패: $e');
} finally {
_isLoading = false;
notifyListeners();
debugPrint('📝 loadLicense 완료 - isLoading: false');
}
}
// 라이센스 정보 로드 (연장 모드 - 기존 데이터로 새 라이선스 생성)
Future<void> loadLicenseForExtension() async {
if (_licenseId == null) return;
debugPrint('📝 loadLicenseForExtension 시작 - ID: $_licenseId');
_isLoading = true;
_error = null;
notifyListeners();
try {
License? sourceLicense;
if (useApi && GetIt.instance.isRegistered<LicenseService>()) {
debugPrint('📝 API에서 라이센스 로드 중 (연장용)...');
sourceLicense = await _licenseService.getLicenseById(_licenseId!);
} else {
debugPrint('📝 Mock에서 라이센스 로드 중 (연장용)...');
sourceLicense = mockDataService?.getLicenseById(_licenseId!);
}
debugPrint('📝 로드된 소스 라이센스: $sourceLicense');
if (sourceLicense != null) {
// 연장용으로 기존 데이터 복사 (ID는 null로 새 라이선스 생성)
productNameController.text = sourceLicense.productName ?? '';
licenseKeyController.text = '${sourceLicense.licenseKey}-EXT-${DateTime.now().millisecondsSinceEpoch}';
vendorController.text = sourceLicense.vendor ?? '';
locationController.text = sourceLicense.companyName ?? '';
assignedUserController.text = sourceLicense.assignedUserName ?? '';
debugPrint('📝 연장용 폼 필드 설정 완료:');
debugPrint(' - 제품명: ${productNameController.text}');
debugPrint(' - 라이선스 키: ${licenseKeyController.text}');
debugPrint(' - 벤더: ${vendorController.text}');
debugPrint(' - 현위치: ${locationController.text}');
debugPrint(' - 할당 사용자: ${assignedUserController.text}');
status = '활성'; // 연장은 항상 활성으로 시작
purchaseDate = DateTime.now(); // 구매일은 오늘
// 만료일은 기존 만료일에서 연장 (기본 12개월)
expiryDate = sourceLicense.expiryDate?.add(Duration(days: _durationMonths * 30))
?? DateTime.now().add(Duration(days: _durationMonths * 30));
_name = sourceLicense.productName ?? '';
_companyId = sourceLicense.companyId ?? 1;
// remark에서 방문주기 정보 추출 (있는 경우)
if (sourceLicense.remark != null && sourceLicense.remark!.contains('방문주기:')) {
final remarkParts = sourceLicense.remark!.split('방문주기:');
if (remarkParts.length > 1) {
_visitCycle = remarkParts[1].trim();
}
}
}
} catch (e) {
_error = e.toString();
debugPrint('❌ 라이센스 연장 로드 실패: $e');
} finally {
_isLoading = false;
notifyListeners();
debugPrint('📝 loadLicenseForExtension 완료 - isLoading: false');
}
}
// 라이센스 저장
Future<bool> saveLicense() async {
if (formKey.currentState?.validate() != true) return false;
formKey.currentState?.save();
_isSaving = true;
_error = null;
notifyListeners();
try {
final license = License(
id: _isEditMode ? _licenseId : null,
licenseKey: licenseKeyController.text.isNotEmpty
? licenseKeyController.text
: 'LIC-${DateTime.now().millisecondsSinceEpoch}',
productName: productNameController.text,
vendor: vendorController.text,
companyName: locationController.text,
assignedUserName: assignedUserController.text.isNotEmpty
? assignedUserController.text
: null,
companyId: _companyId,
isActive: status == '활성',
purchaseDate: purchaseDate ?? DateTime.now(),
expiryDate: expiryDate ?? DateTime.now().add(Duration(days: _durationMonths * 30)),
remark: '${_durationMonths}개월,${_visitCycle},방문',
);
if (useApi && GetIt.instance.isRegistered<LicenseService>()) {
if (_isEditMode) {
await _licenseService.updateLicense(license);
} else {
await _licenseService.createLicense(license);
}
} else {
if (_isEditMode) {
mockDataService?.updateLicense(license);
} else {
mockDataService?.addLicense(license);
}
}
return true;
} catch (e) {
_error = e.toString();
notifyListeners();
return false;
} finally {
_isSaving = false;
notifyListeners();
}
}
// 폼 초기화
void resetForm() {
_name = '';
_companyId = 1;
_durationMonths = 12;
_visitCycle = '미방문';
_error = null;
formKey.currentState?.reset();
notifyListeners();
}
// 유효성 검사
String? validateName(String? value) {
if (value == null || value.isEmpty) {
return '라이선스명을 입력해주세요';
}
if (value.length < 2) {
return '라이선스명은 2자 이상이어야 합니다';
}
return null;
}
String? validateDuration(String? value) {
if (value == null || value.isEmpty) {
return '계약 기간을 입력해주세요';
}
final duration = int.tryParse(value);
if (duration == null || duration < 1) {
return '유효한 계약 기간을 입력해주세요';
}
return null;
}
@override
void dispose() {
// TextEditingController들 정리
productNameController.dispose();
licenseKeyController.dispose();
vendorController.dispose();
locationController.dispose();
assignedUserController.dispose();
super.dispose();
}
}