Files
superport/lib/data/models/maintenance_stats_dto.dart
JiWoong Sul 519e1883a3
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: V/R 유지보수 시스템 전환 및 대시보드 테이블 형태 완성
- V/R 시스템 완전 전환: WARRANTY/CONTRACT/INSPECTION → V(방문)/R(원격)
- 유지보수 대시보드 카드 → StandardDataTable 테이블 형태 전환
- "조회중..." 문제 해결: 백엔드 직접 필드 사용 (equipment_model, company_name)
- MaintenanceDto 신규 필드 추가: company_id, company_name, equipment_serial, equipment_model
- preloadEquipmentData 비활성화로 불필요한 equipment-history API 호출 제거
- CO-STAR 프레임워크 적용 및 CLAUDE.md v3.0 업데이트
- Flutter Analyze ERROR: 0 유지, 100% shadcn_ui 컴플라이언스

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-05 14:33:20 +09:00

181 lines
5.8 KiB
Dart

import 'package:freezed_annotation/freezed_annotation.dart';
part 'maintenance_stats_dto.freezed.dart';
part 'maintenance_stats_dto.g.dart';
@freezed
class MaintenanceStatsDto with _$MaintenanceStatsDto {
const factory MaintenanceStatsDto({
// 기본 계약 통계
@JsonKey(name: 'active_contracts') @Default(0) int activeContracts,
@JsonKey(name: 'total_contracts') @Default(0) int totalContracts,
// 만료 기간별 통계 (사용자 요구사항)
@JsonKey(name: 'expiring_60_days') @Default(0) int expiring60Days,
@JsonKey(name: 'expiring_30_days') @Default(0) int expiring30Days,
@JsonKey(name: 'expiring_7_days') @Default(0) int expiring7Days,
@JsonKey(name: 'expired_contracts') @Default(0) int expiredContracts,
// 유지보수 타입별 통계 (V/R 시스템)
@JsonKey(name: 'visit_contracts') @Default(0) int visitContracts,
@JsonKey(name: 'remote_contracts') @Default(0) int remoteContracts,
// 예정된 작업 통계
@JsonKey(name: 'upcoming_visits') @Default(0) int upcomingVisits,
@JsonKey(name: 'overdue_maintenances') @Default(0) int overdueMaintenances,
// 추가 메트릭
@JsonKey(name: 'total_revenue_at_risk') @Default(0.0) double totalRevenueAtRisk,
@JsonKey(name: 'completion_rate') @Default(0.0) double completionRate,
// 마지막 업데이트 시간
@JsonKey(name: 'updated_at') DateTime? updatedAt,
}) = _MaintenanceStatsDto;
factory MaintenanceStatsDto.fromJson(Map<String, dynamic> json) =>
_$MaintenanceStatsDtoFromJson(json);
}
// 대시보드 상태별 카드 데이터
@freezed
class MaintenanceStatusCardData with _$MaintenanceStatusCardData {
const factory MaintenanceStatusCardData({
required String title,
required int count,
required String subtitle,
required MaintenanceCardStatus status,
String? actionLabel,
}) = _MaintenanceStatusCardData;
factory MaintenanceStatusCardData.fromJson(Map<String, dynamic> json) =>
_$MaintenanceStatusCardDataFromJson(json);
}
// 카드 상태 열거형
enum MaintenanceCardStatus {
@JsonValue('active')
active,
@JsonValue('warning')
warning,
@JsonValue('urgent')
urgent,
@JsonValue('critical')
critical,
@JsonValue('expired')
expired,
}
// 카드 상태별 정보 헬퍼
class MaintenanceCardHelper {
static Map<MaintenanceCardStatus, Map<String, dynamic>> get statusConfig => {
MaintenanceCardStatus.active: {
'color': '#059669', // Green
'icon': 'assignment',
'description': '정상 활성'
},
MaintenanceCardStatus.warning: {
'color': '#F59E0B', // Amber
'icon': 'warning',
'description': '주의 필요'
},
MaintenanceCardStatus.urgent: {
'color': '#EA580C', // Orange
'icon': 'schedule',
'description': '긴급 처리'
},
MaintenanceCardStatus.critical: {
'color': '#DC2626', // Red
'icon': 'alert_circle',
'description': '즉시 조치'
},
MaintenanceCardStatus.expired: {
'color': '#991B1B', // Dark Red
'icon': 'error',
'description': '만료됨'
},
};
static String getColorForStatus(MaintenanceCardStatus status) {
return statusConfig[status]?['color'] ?? '#6B7280';
}
static String getIconForStatus(MaintenanceCardStatus status) {
return statusConfig[status]?['icon'] ?? 'info';
}
static String getDescriptionForStatus(MaintenanceCardStatus status) {
return statusConfig[status]?['description'] ?? '상태 정보 없음';
}
}
// 대시보드 카드 생성 헬퍼
extension MaintenanceStatsDashboard on MaintenanceStatsDto {
List<MaintenanceStatusCardData> get dashboardCards => [
// 60일 내 만료 예정
MaintenanceStatusCardData(
title: '60일 내',
count: expiring60Days,
subtitle: '만료 예정',
status: expiring60Days > 0 ? MaintenanceCardStatus.warning : MaintenanceCardStatus.active,
actionLabel: '계획하기',
),
// 30일 내 만료 예정
MaintenanceStatusCardData(
title: '30일 내',
count: expiring30Days,
subtitle: '만료 예정',
status: expiring30Days > 0 ? MaintenanceCardStatus.urgent : MaintenanceCardStatus.active,
actionLabel: '예약하기',
),
// 7일 내 만료 예정
MaintenanceStatusCardData(
title: '7일 내',
count: expiring7Days,
subtitle: '만료 임박',
status: expiring7Days > 0 ? MaintenanceCardStatus.critical : MaintenanceCardStatus.active,
actionLabel: '즉시 처리',
),
// 만료된 계약
MaintenanceStatusCardData(
title: '만료됨',
count: expiredContracts,
subtitle: '조치 필요',
status: expiredContracts > 0 ? MaintenanceCardStatus.expired : MaintenanceCardStatus.active,
actionLabel: '갱신하기',
),
];
// 추가 요약 정보
Map<String, int> get summaryStats => {
'총 활성 계약': activeContracts,
'방문 계약': visitContracts,
'원격 계약': remoteContracts,
'예정된 방문': upcomingVisits,
'연체 유지보수': overdueMaintenances,
};
// 위험도 계산
double get riskScore {
double score = 0.0;
if (totalContracts == 0) return 0.0;
score += (expiredContracts / totalContracts) * 0.4; // 40% 가중치
score += (expiring7Days / totalContracts) * 0.3; // 30% 가중치
score += (expiring30Days / totalContracts) * 0.2; // 20% 가중치
score += (expiring60Days / totalContracts) * 0.1; // 10% 가중치
return score.clamp(0.0, 1.0);
}
// 위험도 상태
MaintenanceCardStatus get riskStatus {
final risk = riskScore;
if (risk >= 0.7) return MaintenanceCardStatus.critical;
if (risk >= 0.5) return MaintenanceCardStatus.urgent;
if (risk >= 0.3) return MaintenanceCardStatus.warning;
return MaintenanceCardStatus.active;
}
}