Files
superport/lib/screens/overview/widgets/statistics_card_grid.dart

317 lines
9.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:superport/utils/constants.dart';
import 'package:superport/data/models/dashboard/overview_stats.dart';
import 'package:superport/screens/common/components/shadcn_components.dart';
import 'package:superport/screens/common/theme_shadcn.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
/// 대시보드 통계 카드 그리드
class StatisticsCardGrid extends StatelessWidget {
final OverviewStats stats;
const StatisticsCardGrid({
super.key,
required this.stats,
});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 제목
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text(
'시스템 현황',
style: ShadcnTheme.headingH4,
),
),
// 통계 카드 그리드 (2x4)
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 4,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 1.2,
children: [
_buildStatCard(
context,
'전체 회사',
stats.totalCompanies.toString(),
Icons.business,
ShadcnTheme.primary,
'/companies',
),
_buildStatCard(
context,
'활성 사용자',
stats.activeUsers.toString(),
Icons.people,
ShadcnTheme.success,
'/users',
),
_buildStatCard(
context,
'전체 장비',
stats.totalEquipment.toString(),
Icons.inventory,
ShadcnTheme.info,
'/equipment',
),
_buildStatCard(
context,
'활성 라이선스',
stats.activeLicenses.toString(),
Icons.verified_user,
ShadcnTheme.warning,
'/licenses',
),
_buildStatCard(
context,
'사용 중 장비',
stats.inUseEquipment.toString(),
Icons.work,
ShadcnTheme.primary,
'/equipment?status=inuse',
),
_buildStatCard(
context,
'사용 가능',
stats.availableEquipment.toString(),
Icons.check_circle,
ShadcnTheme.success,
'/equipment?status=available',
),
_buildStatCard(
context,
'유지보수',
stats.maintenanceEquipment.toString(),
Icons.build,
ShadcnTheme.warning,
'/equipment?status=maintenance',
),
_buildStatCard(
context,
'창고 위치',
stats.totalWarehouseLocations.toString(),
Icons.location_on,
ShadcnTheme.info,
'/warehouse-locations',
),
],
),
const SizedBox(height: 24),
// 장비 상태 요약
_buildEquipmentStatusSummary(context),
],
);
}
/// 개별 통계 카드
Widget _buildStatCard(
BuildContext context,
String title,
String value,
IconData icon,
Color color,
String? route,
) {
return GestureDetector(
onTap: route != null ? () => _navigateToRoute(context, route) : null,
child: ShadcnCard(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(
icon,
color: color,
size: 24,
),
if (route != null)
Icon(
Icons.arrow_forward_ios,
size: 12,
color: ShadcnTheme.muted,
),
],
),
const SizedBox(height: 12),
Text(
value,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: ShadcnTheme.foreground,
),
),
const SizedBox(height: 4),
Text(
title,
style: TextStyle(
fontSize: 12,
color: ShadcnTheme.mutedForeground,
fontWeight: FontWeight.w500,
),
),
],
),
),
);
}
/// 장비 상태 요약 섹션
Widget _buildEquipmentStatusSummary(BuildContext context) {
final total = stats.totalEquipment;
if (total == 0) return const SizedBox.shrink();
return ShadcnCard(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'장비 상태 분포',
style: ShadcnTheme.headingH5,
),
ShadButton.ghost(
onPressed: () => Navigator.pushNamed(context, Routes.equipment),
size: ShadButtonSize.sm,
child: const Row(
children: [
Text('전체 보기'),
SizedBox(width: 4),
Icon(Icons.arrow_forward, size: 16),
],
),
),
],
),
const SizedBox(height: 16),
// 상태별 프로그레스 바
_buildStatusProgress(
'사용 중',
stats.inUseEquipment,
total,
ShadcnTheme.primary
),
const SizedBox(height: 12),
_buildStatusProgress(
'사용 가능',
stats.availableEquipment,
total,
ShadcnTheme.success
),
const SizedBox(height: 12),
_buildStatusProgress(
'유지보수',
stats.maintenanceEquipment,
total,
ShadcnTheme.warning
),
const SizedBox(height: 16),
// 요약 정보
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: ShadcnTheme.muted.withValues(alpha: 0.5 * 255),
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildSummaryItem('가동률', '${((stats.inUseEquipment / total) * 100).toStringAsFixed(1)}%'),
_buildSummaryItem('가용률', '${((stats.availableEquipment / total) * 100).toStringAsFixed(1)}%'),
_buildSummaryItem('총 장비', '$total개'),
],
),
),
],
),
);
}
/// 상태별 프로그레스 바
Widget _buildStatusProgress(String label, int count, int total, Color color) {
final percentage = total > 0 ? (count / total) : 0.0;
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: ShadcnTheme.bodyMedium),
Text('$count개 (${(percentage * 100).toStringAsFixed(1)}%)',
style: ShadcnTheme.bodySmall.copyWith(color: ShadcnTheme.mutedForeground)),
],
),
const SizedBox(height: 4),
ShadProgress(
value: percentage * 100,
),
],
);
}
/// 요약 항목
Widget _buildSummaryItem(String label, String value) {
return Column(
children: [
Text(
value,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: ShadcnTheme.foreground,
),
),
const SizedBox(height: 4),
Text(
label,
style: TextStyle(
fontSize: 12,
color: ShadcnTheme.mutedForeground,
),
),
],
);
}
/// 라우트 네비게이션 처리
void _navigateToRoute(BuildContext context, String route) {
switch (route) {
case '/companies':
Navigator.pushNamed(context, Routes.companies);
break;
case '/users':
Navigator.pushNamed(context, Routes.users);
break;
case '/equipment':
Navigator.pushNamed(context, Routes.equipment);
break;
case '/licenses':
Navigator.pushNamed(context, Routes.maintenanceSchedule);
break;
case '/warehouse-locations':
Navigator.pushNamed(context, Routes.warehouseLocations);
break;
default:
Navigator.pushNamed(context, Routes.equipment);
}
}
}