refactor: 회사 폼 UI 개선 및 코드 정리
- 담당자 연락처 필드를 드롭다운 + 입력 방식으로 분리 - 사용자 폼과 동일한 전화번호 UI 패턴 적용 - 미사용 위젯 파일 4개 정리 (branch_card, contact_info_* 등) - 파일명 통일성 확보 (branch_edit_screen → branch_form, company_form_simplified → company_form) - 네이밍 일관성 개선으로 유지보수성 향상
This commit is contained in:
223
lib/models/company_item_model.dart
Normal file
223
lib/models/company_item_model.dart
Normal file
@@ -0,0 +1,223 @@
|
||||
import 'package:superport/models/company_model.dart';
|
||||
|
||||
/// Company와 Branch를 통합 관리하기 위한 래퍼 모델
|
||||
/// 리스트에서 본사와 지점을 동일한 구조로 표시하기 위해 사용
|
||||
class CompanyItem {
|
||||
final bool isBranch;
|
||||
final Company? company; // 본사인 경우에만 값 존재
|
||||
final Branch? branch; // 지점인 경우에만 값 존재
|
||||
final String? parentCompanyName; // 지점인 경우 본사명
|
||||
final int? parentCompanyId; // 지점인 경우 본사 ID
|
||||
|
||||
CompanyItem({
|
||||
required this.isBranch,
|
||||
this.company,
|
||||
this.branch,
|
||||
this.parentCompanyName,
|
||||
this.parentCompanyId,
|
||||
}) : assert(
|
||||
(isBranch && branch != null && parentCompanyName != null) ||
|
||||
(!isBranch && company != null),
|
||||
'CompanyItem must have either company (for headquarters) or branch+parentCompanyName (for branch)'
|
||||
);
|
||||
|
||||
/// 본사 생성자
|
||||
CompanyItem.headquarters(Company company)
|
||||
: isBranch = false,
|
||||
company = company,
|
||||
branch = null,
|
||||
parentCompanyName = null,
|
||||
parentCompanyId = null;
|
||||
|
||||
/// 지점 생성자
|
||||
CompanyItem.branch(Branch branch, String parentCompanyName, int parentCompanyId)
|
||||
: isBranch = true,
|
||||
company = null,
|
||||
branch = branch,
|
||||
parentCompanyName = parentCompanyName,
|
||||
parentCompanyId = parentCompanyId;
|
||||
|
||||
/// 표시용 이름 (계층적 구조)
|
||||
String get displayName {
|
||||
if (isBranch) {
|
||||
return '$parentCompanyName > ${branch!.name}';
|
||||
} else {
|
||||
return company!.name;
|
||||
}
|
||||
}
|
||||
|
||||
/// 실제 이름 (본사명 또는 지점명)
|
||||
String get name {
|
||||
return isBranch ? branch!.name : company!.name;
|
||||
}
|
||||
|
||||
/// ID (본사 ID 또는 지점 ID)
|
||||
int? get id {
|
||||
return isBranch ? branch!.id : company!.id;
|
||||
}
|
||||
|
||||
/// 주소
|
||||
String get address {
|
||||
if (isBranch) {
|
||||
return branch!.address.toString();
|
||||
} else {
|
||||
return company!.address.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/// 담당자명
|
||||
String? get contactName {
|
||||
if (isBranch) {
|
||||
return branch!.contactName;
|
||||
} else {
|
||||
return company!.contactName;
|
||||
}
|
||||
}
|
||||
|
||||
/// 담당자 직급 (지점은 null)
|
||||
String? get contactPosition {
|
||||
if (isBranch) {
|
||||
return null; // 지점은 직급 정보 없음
|
||||
} else {
|
||||
return company!.contactPosition;
|
||||
}
|
||||
}
|
||||
|
||||
/// 연락처
|
||||
String? get contactPhone {
|
||||
if (isBranch) {
|
||||
return branch!.contactPhone;
|
||||
} else {
|
||||
return company!.contactPhone;
|
||||
}
|
||||
}
|
||||
|
||||
/// 이메일 (지점은 null)
|
||||
String? get contactEmail {
|
||||
if (isBranch) {
|
||||
return null; // 지점은 이메일 정보 없음
|
||||
} else {
|
||||
return company!.contactEmail;
|
||||
}
|
||||
}
|
||||
|
||||
/// 회사 유형 (본사만, 지점은 빈 리스트)
|
||||
List<CompanyType> get companyTypes {
|
||||
if (isBranch) {
|
||||
return []; // 지점은 회사 유형 없음
|
||||
} else {
|
||||
return company!.companyTypes;
|
||||
}
|
||||
}
|
||||
|
||||
/// 비고
|
||||
String? get remark {
|
||||
if (isBranch) {
|
||||
return branch!.remark;
|
||||
} else {
|
||||
return company!.remark;
|
||||
}
|
||||
}
|
||||
|
||||
/// 생성일
|
||||
DateTime? get createdAt {
|
||||
if (isBranch) {
|
||||
return null; // 지점은 생성일 정보 없음
|
||||
} else {
|
||||
return company!.createdAt;
|
||||
}
|
||||
}
|
||||
|
||||
/// 수정일
|
||||
DateTime? get updatedAt {
|
||||
if (isBranch) {
|
||||
return null; // 지점은 수정일 정보 없음
|
||||
} else {
|
||||
return company!.updatedAt;
|
||||
}
|
||||
}
|
||||
|
||||
/// 활성 상태
|
||||
bool get isActive {
|
||||
if (isBranch) {
|
||||
return true; // 지점은 기본적으로 활성
|
||||
} else {
|
||||
return company!.isActive;
|
||||
}
|
||||
}
|
||||
|
||||
/// 파트너사 플래그
|
||||
bool get isPartner {
|
||||
if (isBranch) {
|
||||
return false; // 지점은 파트너 플래그 없음
|
||||
} else {
|
||||
return company!.isPartner;
|
||||
}
|
||||
}
|
||||
|
||||
/// 고객사 플래그
|
||||
bool get isCustomer {
|
||||
if (isBranch) {
|
||||
return false; // 지점은 고객 플래그 없음
|
||||
} else {
|
||||
return company!.isCustomer;
|
||||
}
|
||||
}
|
||||
|
||||
/// JSON 직렬화
|
||||
Map<String, dynamic> toJson() {
|
||||
if (isBranch) {
|
||||
return {
|
||||
'isBranch': true,
|
||||
'branch': branch!.toJson(),
|
||||
'parentCompanyName': parentCompanyName,
|
||||
'parentCompanyId': parentCompanyId,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
'isBranch': false,
|
||||
'company': company!.toJson(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// JSON 역직렬화
|
||||
factory CompanyItem.fromJson(Map<String, dynamic> json) {
|
||||
final isBranch = json['isBranch'] as bool;
|
||||
|
||||
if (isBranch) {
|
||||
return CompanyItem.branch(
|
||||
Branch.fromJson(json['branch']),
|
||||
json['parentCompanyName'] as String,
|
||||
json['parentCompanyId'] as int,
|
||||
);
|
||||
} else {
|
||||
return CompanyItem.headquarters(
|
||||
Company.fromJson(json['company']),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is CompanyItem &&
|
||||
other.isBranch == isBranch &&
|
||||
other.id == id;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return Object.hash(isBranch, id);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
if (isBranch) {
|
||||
return 'CompanyItem.branch(${branch!.name} of $parentCompanyName)';
|
||||
} else {
|
||||
return 'CompanyItem.headquarters(${company!.name})';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,15 +32,31 @@ CompanyType stringToCompanyType(String type) {
|
||||
|
||||
/// 문자열 리스트에서 회사 유형 리스트로 변환
|
||||
List<CompanyType> stringListToCompanyTypeList(List<dynamic> types) {
|
||||
// 문자열 또는 enum 문자열이 섞여 있을 수 있음
|
||||
return types.map((e) {
|
||||
if (e is CompanyType) return e;
|
||||
if (e is String) {
|
||||
if (e.contains('partner')) return CompanyType.partner;
|
||||
return CompanyType.customer;
|
||||
// 중복 제거를 위한 Set 사용
|
||||
final Set<CompanyType> uniqueTypes = {};
|
||||
|
||||
for (final e in types) {
|
||||
if (e is CompanyType) {
|
||||
uniqueTypes.add(e);
|
||||
} else if (e is String) {
|
||||
final normalized = e.toLowerCase().trim();
|
||||
if (normalized == 'partner' || normalized.contains('partner')) {
|
||||
uniqueTypes.add(CompanyType.partner);
|
||||
} else if (normalized == 'customer' || normalized.contains('customer')) {
|
||||
uniqueTypes.add(CompanyType.customer);
|
||||
} else if (normalized == 'other') {
|
||||
// "Other" 케이스는 고객사로 기본 매핑
|
||||
uniqueTypes.add(CompanyType.customer);
|
||||
}
|
||||
}
|
||||
return CompanyType.customer;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
// 빈 경우 기본값 반환
|
||||
if (uniqueTypes.isEmpty) {
|
||||
return [CompanyType.customer];
|
||||
}
|
||||
|
||||
return uniqueTypes.toList();
|
||||
}
|
||||
|
||||
/// 회사 유형 리스트를 문자열 리스트로 변환
|
||||
@@ -148,6 +164,11 @@ class Company {
|
||||
final List<Branch>? branches;
|
||||
final List<CompanyType> companyTypes; // 회사 유형 (복수 가능)
|
||||
final String? remark; // 비고
|
||||
final bool isActive; // 활성 상태
|
||||
final bool isPartner; // 파트너사 플래그
|
||||
final bool isCustomer; // 고객사 플래그
|
||||
final DateTime? createdAt; // 생성일
|
||||
final DateTime? updatedAt; // 수정일
|
||||
|
||||
Company({
|
||||
this.id,
|
||||
@@ -160,6 +181,11 @@ class Company {
|
||||
this.branches,
|
||||
this.companyTypes = const [CompanyType.customer], // 기본값은 고객사
|
||||
this.remark,
|
||||
this.isActive = true, // 기본값은 활성
|
||||
this.isPartner = false, // 기본값은 파트너 아님
|
||||
this.isCustomer = true, // 기본값은 고객사
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
}) : address = address ?? const Address(); // 기본값 제공
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
@@ -176,6 +202,11 @@ class Company {
|
||||
// 회사 유형을 문자열 리스트로 저장
|
||||
'companyTypes': companyTypes.map((e) => e.toString()).toList(),
|
||||
'remark': remark,
|
||||
'isActive': isActive,
|
||||
'isPartner': isPartner,
|
||||
'isCustomer': isCustomer,
|
||||
'createdAt': createdAt?.toIso8601String(),
|
||||
'updatedAt': updatedAt?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -199,9 +230,14 @@ class Company {
|
||||
addressData = const Address();
|
||||
}
|
||||
|
||||
// 회사 유형 파싱 (복수)
|
||||
// 회사 유형 파싱 (복수) - 서버 응답 우선
|
||||
List<CompanyType> types = [CompanyType.customer]; // 기본값
|
||||
if (json.containsKey('companyTypes')) {
|
||||
if (json.containsKey('company_types')) {
|
||||
final raw = json['company_types'];
|
||||
if (raw is List) {
|
||||
types = stringListToCompanyTypeList(raw);
|
||||
}
|
||||
} else if (json.containsKey('companyTypes')) {
|
||||
final raw = json['companyTypes'];
|
||||
if (raw is List) {
|
||||
types = stringListToCompanyTypeList(raw);
|
||||
@@ -220,13 +256,22 @@ class Company {
|
||||
id: json['id'],
|
||||
name: json['name'],
|
||||
address: addressData,
|
||||
contactName: json['contactName'],
|
||||
contactPosition: json['contactPosition'],
|
||||
contactPhone: json['contactPhone'],
|
||||
contactEmail: json['contactEmail'],
|
||||
contactName: json['contact_name'] ?? json['contactName'],
|
||||
contactPosition: json['contact_position'] ?? json['contactPosition'],
|
||||
contactPhone: json['contact_phone'] ?? json['contactPhone'],
|
||||
contactEmail: json['contact_email'] ?? json['contactEmail'],
|
||||
branches: branchList,
|
||||
companyTypes: types,
|
||||
remark: json['remark'],
|
||||
isActive: json['is_active'] ?? json['isActive'] ?? true,
|
||||
isPartner: json['is_partner'] ?? json['isPartner'] ?? false,
|
||||
isCustomer: json['is_customer'] ?? json['isCustomer'] ?? true,
|
||||
createdAt: json['created_at'] != null
|
||||
? DateTime.parse(json['created_at'])
|
||||
: (json['createdAt'] != null ? DateTime.parse(json['createdAt']) : null),
|
||||
updatedAt: json['updated_at'] != null
|
||||
? DateTime.parse(json['updated_at'])
|
||||
: (json['updatedAt'] != null ? DateTime.parse(json['updatedAt']) : null),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -242,6 +287,11 @@ class Company {
|
||||
List<Branch>? branches,
|
||||
List<CompanyType>? companyTypes,
|
||||
String? remark,
|
||||
bool? isActive,
|
||||
bool? isPartner,
|
||||
bool? isCustomer,
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
}) {
|
||||
return Company(
|
||||
id: id ?? this.id,
|
||||
@@ -254,6 +304,11 @@ class Company {
|
||||
branches: branches ?? this.branches,
|
||||
companyTypes: companyTypes ?? this.companyTypes,
|
||||
remark: remark ?? this.remark,
|
||||
isActive: isActive ?? this.isActive,
|
||||
isPartner: isPartner ?? this.isPartner,
|
||||
isCustomer: isCustomer ?? this.isCustomer,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,13 @@ class Equipment {
|
||||
final String? warrantyLicense; // 워런티 라이센스 명
|
||||
DateTime? warrantyStartDate; // 워런티 시작일(수정 가능)
|
||||
DateTime? warrantyEndDate; // 워런티 종료일(수정 가능)
|
||||
|
||||
// 백엔드 API 구조 변경으로 추가된 필드들
|
||||
final int? currentCompanyId; // 현재 배치된 회사 ID
|
||||
final int? currentBranchId; // 현재 배치된 지점 ID
|
||||
final DateTime? lastInspectionDate; // 최근 점검일
|
||||
final DateTime? nextInspectionDate; // 다음 점검일
|
||||
final String? equipmentStatus; // 장비 상태
|
||||
|
||||
Equipment({
|
||||
this.id,
|
||||
@@ -32,6 +39,12 @@ class Equipment {
|
||||
this.warrantyLicense,
|
||||
this.warrantyStartDate,
|
||||
this.warrantyEndDate,
|
||||
// 새로운 필드들
|
||||
this.currentCompanyId,
|
||||
this.currentBranchId,
|
||||
this.lastInspectionDate,
|
||||
this.nextInspectionDate,
|
||||
this.equipmentStatus,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
@@ -50,6 +63,12 @@ class Equipment {
|
||||
'warrantyLicense': warrantyLicense,
|
||||
'warrantyStartDate': warrantyStartDate?.toIso8601String(),
|
||||
'warrantyEndDate': warrantyEndDate?.toIso8601String(),
|
||||
// 새로운 필드들
|
||||
'currentCompanyId': currentCompanyId,
|
||||
'currentBranchId': currentBranchId,
|
||||
'lastInspectionDate': lastInspectionDate?.toIso8601String(),
|
||||
'nextInspectionDate': nextInspectionDate?.toIso8601String(),
|
||||
'equipmentStatus': equipmentStatus,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,6 +94,16 @@ class Equipment {
|
||||
json['warrantyEndDate'] != null
|
||||
? DateTime.parse(json['warrantyEndDate'])
|
||||
: null,
|
||||
// 새로운 필드들
|
||||
currentCompanyId: json['currentCompanyId'],
|
||||
currentBranchId: json['currentBranchId'],
|
||||
lastInspectionDate: json['lastInspectionDate'] != null
|
||||
? DateTime.parse(json['lastInspectionDate'])
|
||||
: null,
|
||||
nextInspectionDate: json['nextInspectionDate'] != null
|
||||
? DateTime.parse(json['nextInspectionDate'])
|
||||
: null,
|
||||
equipmentStatus: json['equipmentStatus'],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -194,6 +223,13 @@ class UnifiedEquipment {
|
||||
status; // 상태 코드: 'I'(입고), 'O'(출고), 'R'(수리중), 'D'(손상), 'L'(분실), 'E'(기타)
|
||||
final String? notes; // 추가 비고
|
||||
final String? _type; // 내부용: 입고 장비 유형
|
||||
|
||||
// 백엔드 API 구조 변경으로 추가된 필드들 (리스트 화면용)
|
||||
final String? currentCompany; // 현재 회사명
|
||||
final String? currentBranch; // 현재 지점명
|
||||
final String? warehouseLocation; // 창고 위치
|
||||
final DateTime? lastInspectionDate; // 최근 점검일
|
||||
final DateTime? nextInspectionDate; // 다음 점검일
|
||||
|
||||
UnifiedEquipment({
|
||||
this.id,
|
||||
@@ -202,6 +238,12 @@ class UnifiedEquipment {
|
||||
required this.status,
|
||||
this.notes,
|
||||
String? type,
|
||||
// 새로운 필드들
|
||||
this.currentCompany,
|
||||
this.currentBranch,
|
||||
this.warehouseLocation,
|
||||
this.lastInspectionDate,
|
||||
this.nextInspectionDate,
|
||||
}) : _type = type;
|
||||
|
||||
// 장비 유형 반환 (입고 장비만)
|
||||
@@ -263,6 +305,12 @@ class UnifiedEquipment {
|
||||
'date': date.toIso8601String(),
|
||||
'status': status,
|
||||
'notes': notes,
|
||||
// 새로운 필드들
|
||||
'currentCompany': currentCompany,
|
||||
'currentBranch': currentBranch,
|
||||
'warehouseLocation': warehouseLocation,
|
||||
'lastInspectionDate': lastInspectionDate?.toIso8601String(),
|
||||
'nextInspectionDate': nextInspectionDate?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -273,6 +321,16 @@ class UnifiedEquipment {
|
||||
date: DateTime.parse(json['date']),
|
||||
status: json['status'],
|
||||
notes: json['notes'],
|
||||
// 새로운 필드들
|
||||
currentCompany: json['currentCompany'],
|
||||
currentBranch: json['currentBranch'],
|
||||
warehouseLocation: json['warehouseLocation'],
|
||||
lastInspectionDate: json['lastInspectionDate'] != null
|
||||
? DateTime.parse(json['lastInspectionDate'])
|
||||
: null,
|
||||
nextInspectionDate: json['nextInspectionDate'] != null
|
||||
? DateTime.parse(json['nextInspectionDate'])
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import 'address_model.dart';
|
||||
|
||||
/// 입고지 정보를 나타내는 모델 클래스
|
||||
/// 입고지 정보를 나타내는 모델 클래스 (백엔드 API 호환)
|
||||
class WarehouseLocation {
|
||||
/// 입고지 고유 번호
|
||||
final int id;
|
||||
@@ -8,31 +6,61 @@ class WarehouseLocation {
|
||||
/// 입고지명
|
||||
final String name;
|
||||
|
||||
/// 입고지 주소
|
||||
final Address address;
|
||||
/// 주소 (단일 문자열)
|
||||
final String? address;
|
||||
|
||||
/// 담당자명
|
||||
final String? managerName;
|
||||
|
||||
/// 담당자 연락처
|
||||
final String? managerPhone;
|
||||
|
||||
/// 수용량
|
||||
final int? capacity;
|
||||
|
||||
/// 비고
|
||||
final String? remark;
|
||||
|
||||
/// 활성 상태
|
||||
final bool isActive;
|
||||
|
||||
/// 생성일
|
||||
final DateTime createdAt;
|
||||
|
||||
WarehouseLocation({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.address,
|
||||
this.address,
|
||||
this.managerName,
|
||||
this.managerPhone,
|
||||
this.capacity,
|
||||
this.remark,
|
||||
});
|
||||
this.isActive = true,
|
||||
DateTime? createdAt,
|
||||
}) : createdAt = createdAt ?? DateTime.now();
|
||||
|
||||
/// 복사본 생성 (불변성 유지)
|
||||
WarehouseLocation copyWith({
|
||||
int? id,
|
||||
String? name,
|
||||
Address? address,
|
||||
String? address,
|
||||
String? managerName,
|
||||
String? managerPhone,
|
||||
int? capacity,
|
||||
String? remark,
|
||||
bool? isActive,
|
||||
DateTime? createdAt,
|
||||
}) {
|
||||
return WarehouseLocation(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
address: address ?? this.address,
|
||||
managerName: managerName ?? this.managerName,
|
||||
managerPhone: managerPhone ?? this.managerPhone,
|
||||
capacity: capacity ?? this.capacity,
|
||||
remark: remark ?? this.remark,
|
||||
isActive: isActive ?? this.isActive,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user