import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../core/theme/app_colors.dart'; import '../shell/nav_bar_config.dart'; import '../../core/utils/date_utils.dart' as du; import '../../shared/widgets/status_banner.dart'; import '../../shared/widgets/approval_timeline.dart'; import 'vehicle_model.dart'; import '../../core/i18n/app_localizations.dart'; import 'vehicle_list_controller.dart'; class VehicleDetailPage extends ConsumerWidget { final String id; const VehicleDetailPage({super.key, required this.id}); @override Widget build(BuildContext context, WidgetRef ref) { final vehicle = mockVehicles.firstWhere( (e) => e.id == id, orElse: () => mockVehicles.first, ); final (icon, color, statusText) = _statusProps(vehicle.status); final l10n = AppLocalizations.of(context); ref .read(navBarConfigProvider.notifier) .update( NavBarConfig( title: l10n.get('vehicleDetail'), showBack: true, onBack: () => context.pop(), ), ); return Column( children: [ Expanded( child: SingleChildScrollView( padding: const EdgeInsets.fromLTRB(16, 16, 16, 32), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ StatusBanner( icon: icon, statusText: statusText, subText: _statusSubText(vehicle), color: color, ), const SizedBox(height: 8), Text( '提交时间:${du.DateUtils.formatDateTime(vehicle.createTime)}', style: const TextStyle( fontSize: AppFontSizes.caption, color: AppColors.textSecondary, ), ), const SizedBox(height: 16), _buildInfoSection(vehicle), const SizedBox(height: 16), _buildMapSection(), const SizedBox(height: 16), if (vehicle.approvalRecords.isNotEmpty || vehicle.approvalChain.isNotEmpty) Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.bgCard, borderRadius: BorderRadius.circular(8), ), child: ApprovalTimeline( records: vehicle.approvalRecords, chain: vehicle.approvalChain, currentApproverId: vehicle.currentApproverId, ), ), ], ), ), ), _buildActionBar(context, vehicle), ], ); } Widget _buildInfoSection(VehicleModel vehicle) { return Container( padding: const EdgeInsets.fromLTRB(16, 8, 16, 8), decoration: BoxDecoration( color: AppColors.bgCard, borderRadius: BorderRadius.circular(8), ), child: Column( children: [ _infoRow('申请人', vehicle.applicantName), _infoRow('所属部门', vehicle.deptName), _infoRow('用车车型', vehicle.vehicleType), _infoRow('用车目的', vehicle.purpose), _infoRow('出发地点', vehicle.origin), _infoRow('目的地点', vehicle.destination), _infoRow( '预计时间', '${du.DateUtils.formatDateTime(vehicle.startTime)} ~ ${du.DateUtils.formatTime(vehicle.endTime)}', ), _infoRow('乘车人数', '${vehicle.passengerCount}人'), _infoRow('预估里程', '${vehicle.estimatedMileage.toStringAsFixed(0)}公里'), ], ), ); } Widget _infoRow(String label, String value) { return Container( height: 44, padding: const EdgeInsets.symmetric(vertical: 0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( label, style: const TextStyle( fontSize: AppFontSizes.body, color: AppColors.textSecondary, ), ), Flexible( child: Text( value, style: const TextStyle( fontSize: AppFontSizes.body, color: AppColors.textPrimary, ), textAlign: TextAlign.right, overflow: TextOverflow.ellipsis, ), ), ], ), ); } Widget _buildMapSection() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.bgCard, borderRadius: BorderRadius.circular(8), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( '行程预览', style: TextStyle( fontSize: AppFontSizes.subtitle, fontWeight: FontWeight.w600, color: AppColors.textPrimary, ), ), const SizedBox(height: 8), Container( height: 160, width: double.infinity, decoration: BoxDecoration( color: const Color(0xFFE8F4FD), borderRadius: BorderRadius.circular(8), ), child: const Center( child: Text( '地图路线预览', style: TextStyle( fontSize: AppFontSizes.body, color: AppColors.primary, ), ), ), ), ], ), ); } Widget _buildActionBar(BuildContext context, VehicleModel vehicle) { // 根据状态显示操作按钮 Widget? actionButton; if (vehicle.status == 'pending' || vehicle.status == 'draft') { actionButton = _singleButton('撤回申请', AppColors.primary, () {}); } else if (vehicle.status == 'approved') { // 已通过可显示确认还车 actionButton = _singleButton('确认还车并登记', AppColors.primary, () {}); } if (actionButton == null) return const SizedBox.shrink(); return Container( height: 72, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), decoration: const BoxDecoration(color: AppColors.bgCard), child: Row(children: [const Spacer(), actionButton, const Spacer()]), ); } Widget _singleButton(String label, Color color, VoidCallback onTap) { return SizedBox( height: 40, child: Material( color: color, borderRadius: BorderRadius.circular(22), child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(22), child: Center( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 32), child: Text( label, style: const TextStyle( fontSize: AppFontSizes.body, fontWeight: FontWeight.w500, color: Colors.white, ), ), ), ), ), ), ); } (IconData, Color, String) _statusProps(String status) { switch (status) { case 'approved': return (Icons.check_circle, AppColors.success, '已通过'); case 'rejected': return (Icons.cancel, AppColors.danger, '已拒绝'); case 'draft': return (Icons.edit_note, AppColors.statusGray, '草稿'); case 'revoked': return (Icons.cancel_outlined, AppColors.revokedText, '已撤回'); case 'returned': return (Icons.assignment_return, AppColors.primary, '已还车'); default: return (Icons.access_time, AppColors.warning, '审批中'); } } String _statusSubText(VehicleModel vehicle) { switch (vehicle.status) { case 'pending': return vehicle.currentApproverId.isNotEmpty ? '当前审批人:${vehicle.currentApproverId}' : '等待审批'; case 'approved': return vehicle.currentApproverId.isNotEmpty ? '当前审批人:${vehicle.currentApproverId}' : '已通过'; default: return ''; } } }