vehicle_detail_page.dart 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_riverpod/flutter_riverpod.dart';
  3. import 'package:go_router/go_router.dart';
  4. import 'package:tdesign_flutter/tdesign_flutter.dart';
  5. import '../../core/theme/app_colors.dart';
  6. import '../../core/utils/date_utils.dart' as du;
  7. import '../../shared/models/user_model.dart';
  8. import '../../shared/widgets/app_card.dart';
  9. import '../../shared/widgets/approval_timeline.dart';
  10. import '../../shared/widgets/approval_actions.dart';
  11. import 'vehicle_model.dart';
  12. import 'vehicle_list_controller.dart';
  13. class VehicleDetailPage extends ConsumerWidget {
  14. final String id;
  15. const VehicleDetailPage({super.key, required this.id});
  16. @override
  17. Widget build(BuildContext context, WidgetRef ref) {
  18. final vehicle = mockVehicles.firstWhere((e) => e.id == id,
  19. orElse: () => mockVehicles.first);
  20. return Scaffold(
  21. appBar: TDNavBar(
  22. title: '用车详情',
  23. titleColor: Colors.white,
  24. backgroundColor: const Color(0xFF00ABF3),
  25. centerTitle: false,
  26. ),
  27. body: Column(children: [
  28. Expanded(
  29. child: SingleChildScrollView(
  30. padding: const EdgeInsets.all(12),
  31. child: Column(children: [
  32. _buildStatusHeader(vehicle),
  33. const SizedBox(height: 12),
  34. _buildInfoSection(vehicle),
  35. const SizedBox(height: 12),
  36. if (vehicle.approvalRecords.isNotEmpty || vehicle.approvalChain.isNotEmpty)
  37. AppCard(
  38. child: ApprovalTimeline(
  39. records: vehicle.approvalRecords,
  40. chain: vehicle.approvalChain,
  41. currentApproverId: vehicle.currentApproverId,
  42. ),
  43. ),
  44. ]),
  45. ),
  46. ),
  47. ApprovalActions(
  48. status: vehicle.status,
  49. userRole: UserRole.employee,
  50. onApprove: () {},
  51. onReject: () {},
  52. onEdit: () => context.push('/vehicle/apply?id=${vehicle.id}'),
  53. onWithdraw: () {},
  54. ),
  55. ]),
  56. );
  57. }
  58. Widget _buildStatusHeader(VehicleModel vehicle) {
  59. final (icon, color, text) = switch (vehicle.status) {
  60. 'approved' => (Icons.check_circle, AppColors.success, '已通过'),
  61. 'rejected' => (Icons.cancel, AppColors.error, '已拒绝'),
  62. 'draft' => (Icons.edit, AppColors.textHint, '草稿'),
  63. _ => (Icons.schedule, AppColors.warning, '待审批'),
  64. };
  65. return Container(
  66. padding: const EdgeInsets.all(20),
  67. decoration: BoxDecoration(
  68. color: color.withValues(alpha: 0.08),
  69. borderRadius: BorderRadius.circular(12)),
  70. child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
  71. Icon(icon, color: color, size: 36),
  72. const SizedBox(width: 10),
  73. Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
  74. Text(text, style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: color)),
  75. if (vehicle.status == 'pending')
  76. Text('当前审批人:${vehicle.currentApproverId}',
  77. style: const TextStyle(fontSize: 12, color: AppColors.textSecondary)),
  78. ]),
  79. ]),
  80. );
  81. }
  82. Widget _buildInfoSection(VehicleModel vehicle) {
  83. return _buildDetailCard('基本信息', [
  84. TDCell(title: '申请单号', note: vehicle.applicationNo, showBottomBorder: true),
  85. TDCell(title: '申请人', note: '${vehicle.applicantName} · ${vehicle.deptName}', showBottomBorder: true),
  86. TDCell(title: '车辆类型', note: vehicle.vehicleType, showBottomBorder: true),
  87. TDCell(title: '用车目的', note: vehicle.purpose, showBottomBorder: true),
  88. TDCell(title: '出发地', note: vehicle.origin, showBottomBorder: true),
  89. TDCell(title: '目的地', note: vehicle.destination, showBottomBorder: true),
  90. TDCell(title: '预计时间', note: '${du.DateUtils.formatDateTime(vehicle.startTime)} ~ ${du.DateUtils.formatDateTime(vehicle.endTime)}', showBottomBorder: true),
  91. TDCell(title: '乘车人数', note: '${vehicle.passengerCount}人', showBottomBorder: true),
  92. TDCell(title: '驾驶员', note: vehicle.driver.isEmpty ? '-' : vehicle.driver, showBottomBorder: true),
  93. TDCell(title: '预估里程', note: '${vehicle.estimatedMileage}公里', showBottomBorder: true),
  94. TDCell(title: '预估费用', note: '¥${vehicle.estimatedCost.toStringAsFixed(2)}', showBottomBorder: vehicle.reason.isNotEmpty),
  95. if (vehicle.reason.isNotEmpty)
  96. TDCell(title: '用车事由', note: vehicle.reason, showBottomBorder: false),
  97. ]);
  98. }
  99. Widget _buildDetailCard(String title, List<Widget> cells) {
  100. return Container(
  101. margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
  102. decoration: BoxDecoration(
  103. color: AppColors.cardWhite,
  104. borderRadius: BorderRadius.circular(10),
  105. boxShadow: [BoxShadow(color: Colors.black.withValues(alpha: 0.04), blurRadius: 4, offset: const Offset(0, 1))],
  106. ),
  107. child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
  108. Padding(
  109. padding: const EdgeInsets.fromLTRB(14, 12, 14, 8),
  110. child: Text(title, style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: AppColors.textPrimary)),
  111. ),
  112. ...cells,
  113. ]),
  114. );
  115. }
  116. }