Files
superport/lib/screens/zipcode/controllers/zipcode_controller.dart
JiWoong Sul df7dd8dacb
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
feat: 대규모 코드베이스 개선 - 백엔드 통합성 강화 및 UI 일관성 완성
- CLAUDE.md 대폭 개선: 개발 가이드라인 및 프로젝트 상태 문서화
- 백엔드 API 통합: 모든 엔티티 간 Foreign Key 관계 완벽 구현
- UI 일관성 강화: shadcn_ui 컴포넌트 표준화 적용
- 데이터 모델 개선: DTO 및 모델 클래스 백엔드 스키마와 100% 일치
- 사용자 관리: 회사 연결, 중복 검사, 입력 검증 기능 추가
- 창고 관리: 우편번호 연결, 중복 검사 기능 강화
- 회사 관리: 우편번호 연결, 중복 검사 로직 구현
- 장비 관리: 불필요한 카테고리 필드 제거, 벤더-모델 관계 정리
- 우편번호 시스템: 검색 다이얼로그 Provider 버그 수정

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-31 15:49:05 +09:00

276 lines
6.8 KiB
Dart

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:injectable/injectable.dart';
import 'package:superport/data/models/zipcode_dto.dart';
import 'package:superport/domain/usecases/zipcode_usecase.dart';
import 'package:superport/utils/constants.dart';
@injectable
class ZipcodeController extends ChangeNotifier {
final ZipcodeUseCase _zipcodeUseCase;
ZipcodeController(this._zipcodeUseCase);
// 상태 변수들
List<ZipcodeDto> _zipcodes = [];
ZipcodeDto? _selectedZipcode;
bool _isLoading = false;
String? _errorMessage;
// 페이지네이션
int _currentPage = 1;
int _totalPages = 1;
int _totalCount = 0;
final int _pageSize = PaginationConstants.defaultPageSize;
// 검색 및 필터
String _searchQuery = '';
String? _selectedSido;
String? _selectedGu;
// 시도/구 목록 캐시
List<String> _sidoList = [];
List<String> _guList = [];
// 디바운스를 위한 타이머
Timer? _debounceTimer;
// Getters
List<ZipcodeDto> get zipcodes => _zipcodes;
ZipcodeDto? get selectedZipcode => _selectedZipcode;
bool get isLoading => _isLoading;
String? get errorMessage => _errorMessage;
int get currentPage => _currentPage;
int get totalPages => _totalPages;
int get totalCount => _totalCount;
String get searchQuery => _searchQuery;
String? get selectedSido => _selectedSido;
String? get selectedGu => _selectedGu;
List<String> get sidoList => _sidoList;
List<String> get guList => _guList;
bool get hasNextPage => _currentPage < _totalPages;
bool get hasPreviousPage => _currentPage > 1;
// 초기 데이터 로드
Future<void> initialize() async {
try {
_isLoading = true;
_zipcodes = [];
_selectedZipcode = null;
_errorMessage = null;
notifyListeners();
// 시도 목록 로드
await _loadSidoList();
// 초기 우편번호 목록 로드 (첫 페이지)
await searchZipcodes();
} catch (e) {
_errorMessage = '초기화 중 오류가 발생했습니다.';
_isLoading = false;
notifyListeners();
}
}
// 우편번호 검색
Future<void> searchZipcodes({bool refresh = false}) async {
if (refresh) {
_currentPage = 1;
}
_setLoading(true);
_clearError();
try {
final response = await _zipcodeUseCase.searchZipcodes(
page: _currentPage,
limit: _pageSize,
search: _searchQuery.isNotEmpty ? _searchQuery : null,
sido: _selectedSido,
gu: _selectedGu,
);
_zipcodes = response.items;
_totalCount = response.totalCount;
_totalPages = response.totalPages;
_currentPage = response.currentPage;
notifyListeners();
} catch (e) {
_setError('우편번호 검색에 실패했습니다: ${e.toString()}');
} finally {
_setLoading(false);
}
}
// 특정 우편번호로 정확한 주소 조회
Future<void> getZipcodeByNumber(int zipcode) async {
_setLoading(true);
_clearError();
try {
_selectedZipcode = await _zipcodeUseCase.getZipcodeByNumber(zipcode);
notifyListeners();
} catch (e) {
_setError('우편번호 조회에 실패했습니다: ${e.toString()}');
} finally {
_setLoading(false);
}
}
// 주소로 우편번호 빠른 검색
Future<List<ZipcodeDto>> quickSearchByAddress(String address) async {
if (address.trim().isEmpty) return [];
try {
return await _zipcodeUseCase.searchByAddress(address);
} catch (e) {
return [];
}
}
// 검색어 설정 (디바운스 적용)
void setSearchQuery(String query) {
_searchQuery = query;
notifyListeners();
// 디바운스 처리 (500ms 대기 후 검색 실행)
_debounceTimer?.cancel();
_debounceTimer = Timer(const Duration(milliseconds: 500), () {
searchZipcodes(refresh: true);
});
}
// 즉시 검색 실행 (디바운스 무시)
Future<void> executeSearch() async {
_debounceTimer?.cancel();
_currentPage = 1;
await searchZipcodes();
}
// 시도 선택
Future<void> setSido(String? sido) async {
try {
_selectedSido = sido;
_selectedGu = null; // 시도 변경 시 구 초기화
_guList = []; // 구 목록 초기화
notifyListeners();
// 선택된 시도에 따른 구 목록 로드
if (sido != null && sido.isNotEmpty) {
await _loadGuListBySido(sido);
}
// 검색 새로고침
await searchZipcodes(refresh: true);
} catch (e) {
debugPrint('시도 선택 오류: $e');
}
}
// 구 선택
Future<void> setGu(String? gu) async {
try {
_selectedGu = gu;
notifyListeners();
// 검색 새로고침
await searchZipcodes(refresh: true);
} catch (e) {
debugPrint('구 선택 오류: $e');
}
}
// 필터 초기화
Future<void> clearFilters() async {
_searchQuery = '';
_selectedSido = null;
_selectedGu = null;
_guList = [];
_currentPage = 1;
notifyListeners();
await searchZipcodes();
}
// 페이지 이동
Future<void> goToPage(int page) async {
if (page < 1 || page > _totalPages) return;
_currentPage = page;
await searchZipcodes();
}
// 다음 페이지
Future<void> nextPage() async {
if (hasNextPage) {
await goToPage(_currentPage + 1);
}
}
// 이전 페이지
Future<void> previousPage() async {
if (hasPreviousPage) {
await goToPage(_currentPage - 1);
}
}
// 시도 목록 로드 (캐시)
Future<void> _loadSidoList() async {
try {
_sidoList = await _zipcodeUseCase.getAllSidoList();
debugPrint('=== 시도 목록 로드 완료 ===');
debugPrint('총 시도 개수: ${_sidoList.length}');
debugPrint('시도 목록: $_sidoList');
} catch (e) {
debugPrint('시도 목록 로드 실패: $e');
_sidoList = [];
}
}
// 선택된 시도의 구 목록 로드
Future<void> _loadGuListBySido(String sido) async {
try {
_guList = await _zipcodeUseCase.getGuListBySido(sido);
notifyListeners();
} catch (e) {
debugPrint('구 목록 로드 실패: $e');
_guList = [];
}
}
// 우편번호 선택
void selectZipcode(ZipcodeDto zipcode) {
_selectedZipcode = zipcode;
notifyListeners();
}
// 선택 초기화
void clearSelection() {
_selectedZipcode = null;
notifyListeners();
}
// 내부 헬퍼 메서드
void _setLoading(bool loading) {
_isLoading = loading;
notifyListeners();
}
void _setError(String message) {
_errorMessage = message;
notifyListeners();
}
void _clearError() {
_errorMessage = null;
}
@override
void dispose() {
_debounceTimer?.cancel();
_zipcodes = [];
_selectedZipcode = null;
super.dispose();
}
}