import 'package:aioa_mobile/features/requests/application/leave_request_controller.dart'; import 'package:aioa_mobile/features/requests/data/leave_request_repository.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; class LeaveRequestDetailPage extends ConsumerWidget { const LeaveRequestDetailPage({required this.id, super.key}); final String id; @override Widget build(BuildContext context, WidgetRef ref) { final detail = ref.watch(leaveRequestDetailProvider(id)); return Scaffold( appBar: AppBar(title: const Text('申请详情')), body: detail.when( loading: () => const Center(child: CircularProgressIndicator()), error: (error, _) => Center(child: Text('详情加载失败:$error')), data: (value) => _DetailBody(id: id, detail: value), ), ); } } class _DetailBody extends ConsumerWidget { const _DetailBody({required this.id, required this.detail}); final String id; final LeaveRequestDetail detail; @override Widget build(BuildContext context, WidgetRef ref) { final request = detail.request; final formatter = DateFormat('yyyy-MM-dd HH:mm'); return ListView( padding: const EdgeInsets.all(16), children: [ Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( _statusLabel(request.status), style: Theme.of( context, ).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.w800), ), const SizedBox(height: 14), _row('请假类型', _typeLabel(request.type)), _row('开始时间', formatter.format(request.startsAt.toLocal())), _row('结束时间', formatter.format(request.endsAt.toLocal())), _row('请假原因', request.reason), ], ), ), ), const SizedBox(height: 14), Text( '流程时间线', style: Theme.of( context, ).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w700), ), const SizedBox(height: 8), if (detail.timeline.isEmpty) const Card( child: ListTile( leading: Icon(Icons.edit_note), title: Text('草稿已创建'), ), ) else for (final event in detail.timeline) _TimelineTile(event: event), const SizedBox(height: 16), if (request.status == 'DRAFT') FilledButton.icon( onPressed: () => _transition(context, ref, 'submit'), icon: const Icon(Icons.send_outlined), label: const Padding( padding: EdgeInsets.symmetric(vertical: 12), child: Text('提交审批'), ), ), if (request.status == 'PENDING') OutlinedButton.icon( onPressed: () => _transition(context, ref, 'withdraw'), icon: const Icon(Icons.undo), label: const Padding( padding: EdgeInsets.symmetric(vertical: 12), child: Text('撤回申请'), ), ), ], ); } Future _transition( BuildContext context, WidgetRef ref, String action, ) async { final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( title: Text(action == 'submit' ? '提交审批' : '撤回申请'), content: Text(action == 'submit' ? '提交后将进入审批流程,确认继续?' : '确认撤回当前申请?'), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('取消'), ), FilledButton( onPressed: () => Navigator.pop(context, true), child: const Text('确认'), ), ], ), ); if (confirmed != true || !context.mounted) return; final error = await ref .read(leaveRequestDetailProvider(id).notifier) .transition(action); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(error ?? (action == 'submit' ? '已提交审批' : '已撤回'))), ); } Widget _row(String label, String value) => Padding( padding: const EdgeInsets.only(bottom: 10), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(width: 78, child: Text(label)), Expanded( child: Text( value, style: const TextStyle(fontWeight: FontWeight.w600), ), ), ], ), ); String _typeLabel(String value) => switch (value) { 'PERSONAL' => '事假', 'SICK' => '病假', 'ANNUAL' => '年假', _ => value, }; String _statusLabel(String value) => switch (value) { 'DRAFT' => '草稿', 'PENDING' => '审批中', 'APPROVED' => '已通过', 'REJECTED' => '已驳回', 'WITHDRAWN' => '已撤回', _ => value, }; } class _TimelineTile extends StatelessWidget { const _TimelineTile({required this.event}); final LeaveTimelineEvent event; @override Widget build(BuildContext context) => Card( child: ListTile( leading: const Icon(Icons.radio_button_checked), title: Text(_eventLabel(event.eventType)), subtitle: Text( '${event.fromStatus} → ${event.toStatus}\n${DateFormat('MM-dd HH:mm').format(event.occurredAt.toLocal())}', ), isThreeLine: true, ), ); String _eventLabel(String value) => switch (value) { 'LEAVE_REQUEST_SUBMITTED' => '申请已提交', 'LEAVE_REQUEST_WITHDRAWN' => '申请已撤回', 'LEAVE_REQUEST_APPROVED' => '申请已通过', 'LEAVE_REQUEST_REJECTED' => '申请已驳回', 'LEAVE_APPROVAL_TASK_APPROVED' => '审批节点已通过', 'LEAVE_APPROVAL_TASK_REJECTED' => '审批节点已驳回', _ => value, }; }