146 lines
3.6 KiB
Dart
146 lines
3.6 KiB
Dart
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
|
|
part 'company_hierarchy.freezed.dart';
|
|
|
|
/// Company 계층 구조 도메인 엔티티
|
|
@freezed
|
|
class CompanyHierarchy with _$CompanyHierarchy {
|
|
const CompanyHierarchy._();
|
|
|
|
const factory CompanyHierarchy({
|
|
required String id,
|
|
required String name,
|
|
String? parentId,
|
|
String? parentName,
|
|
@Default([]) List<CompanyHierarchy> children,
|
|
@Default(0) int level,
|
|
@Default('') String fullPath,
|
|
@Default(false) bool isExpanded,
|
|
@Default(0) int totalDescendants,
|
|
}) = _CompanyHierarchy;
|
|
|
|
/// 계층 구조에서 특정 회사 찾기
|
|
CompanyHierarchy? findCompany(String companyId) {
|
|
if (id == companyId) {
|
|
return this;
|
|
}
|
|
|
|
for (final child in children) {
|
|
final found = child.findCompany(companyId);
|
|
if (found != null) {
|
|
return found;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// 모든 자손 회사 ID 목록 가져오기
|
|
List<String> getAllDescendantIds() {
|
|
final ids = <String>[];
|
|
|
|
for (final child in children) {
|
|
ids.add(child.id);
|
|
ids.addAll(child.getAllDescendantIds());
|
|
}
|
|
|
|
return ids;
|
|
}
|
|
|
|
/// 특정 회사가 자손인지 확인
|
|
bool hasDescendant(String companyId) {
|
|
return getAllDescendantIds().contains(companyId);
|
|
}
|
|
|
|
/// 계층 구조의 최대 깊이 계산
|
|
int getMaxDepth() {
|
|
if (children.isEmpty) {
|
|
return level;
|
|
}
|
|
|
|
return children
|
|
.map((child) => child.getMaxDepth())
|
|
.reduce((max, depth) => depth > max ? depth : max);
|
|
}
|
|
|
|
/// 순환 참조 검증
|
|
bool wouldCreateCycle(String newParentId) {
|
|
// 자기 자신을 부모로 설정하려는 경우
|
|
if (id == newParentId) {
|
|
return true;
|
|
}
|
|
|
|
// 자손을 부모로 설정하려는 경우
|
|
if (hasDescendant(newParentId)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// 계층 경로 생성
|
|
String buildPath(String separator) {
|
|
final parts = fullPath.split('/').where((p) => p.isNotEmpty).toList();
|
|
return parts.join(separator);
|
|
}
|
|
|
|
/// 평면 리스트로 변환 (트리 구조 → 플랫 리스트)
|
|
List<CompanyHierarchy> flatten() {
|
|
final flatList = <CompanyHierarchy>[this];
|
|
|
|
for (final child in children) {
|
|
flatList.addAll(child.flatten());
|
|
}
|
|
|
|
return flatList;
|
|
}
|
|
|
|
/// 계층 구조 통계
|
|
Map<String, dynamic> getStatistics() {
|
|
final flat = flatten();
|
|
return {
|
|
'totalCompanies': flat.length,
|
|
'maxDepth': getMaxDepth(),
|
|
'directChildren': children.length,
|
|
'totalDescendants': totalDescendants,
|
|
'levels': _getLevelDistribution(flat),
|
|
};
|
|
}
|
|
|
|
Map<int, int> _getLevelDistribution(List<CompanyHierarchy> companies) {
|
|
final distribution = <int, int>{};
|
|
|
|
for (final company in companies) {
|
|
distribution[company.level] = (distribution[company.level] ?? 0) + 1;
|
|
}
|
|
|
|
return distribution;
|
|
}
|
|
}
|
|
|
|
/// 계층 구조 검증 결과
|
|
@freezed
|
|
class HierarchyValidationResult with _$HierarchyValidationResult {
|
|
const factory HierarchyValidationResult({
|
|
required bool isValid,
|
|
@Default('') String message,
|
|
@Default([]) List<String> errors,
|
|
@Default([]) List<String> warnings,
|
|
}) = _HierarchyValidationResult;
|
|
|
|
factory HierarchyValidationResult.valid() => const HierarchyValidationResult(
|
|
isValid: true,
|
|
message: 'Hierarchy is valid',
|
|
);
|
|
|
|
factory HierarchyValidationResult.invalid({
|
|
required String message,
|
|
List<String> errors = const [],
|
|
List<String> warnings = const [],
|
|
}) => HierarchyValidationResult(
|
|
isValid: false,
|
|
message: message,
|
|
errors: errors,
|
|
warnings: warnings,
|
|
);
|
|
} |