import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../shell/nav_bar_config.dart'; import '../../core/utils/date_utils.dart' as du; import '../../shared/widgets/filter_tabs.dart'; import '../../shared/widgets/list_card.dart'; import '../../shared/widgets/status_tag.dart'; import '../../shared/widgets/empty_state.dart'; import '../../shared/widgets/loading_widget.dart'; import 'overtime_list_controller.dart'; import '../../core/i18n/app_localizations.dart'; import 'overtime_model.dart'; class OvertimeListPage extends ConsumerStatefulWidget { const OvertimeListPage({super.key}); @override ConsumerState createState() => _OvertimeListPageState(); } class _OvertimeListPageState extends ConsumerState { final _scrollCtrl = ScrollController(); static const _tabs = ['全部', '草稿', '审批中', '已通过', '已拒绝']; static const _tabStatusKeys = [ '', 'draft', 'pending', 'approved', 'rejected', ]; @override void initState() { super.initState(); _scrollCtrl.addListener(_onScroll); } void _onScroll() { if (_scrollCtrl.position.pixels >= _scrollCtrl.position.maxScrollExtent - 100) { ref.read(overtimePageProvider.notifier).state++; } } @override void dispose() { _scrollCtrl.removeListener(_onScroll); _scrollCtrl.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final status = ref.watch(overtimeStatusFilterProvider); final itemsAsync = ref.watch(overtimeListProvider); final l10n = AppLocalizations.of(context); int selectedIndex = _tabStatusKeys.indexOf(status); if (selectedIndex < 0) selectedIndex = 0; ref .read(navBarConfigProvider.notifier) .update( NavBarConfig( title: l10n.get('overtimeList'), showBack: true, onBack: () => context.pop(), ), ); return Column( children: [ FilterTabs( tabs: _tabs, selectedIndex: selectedIndex, onChanged: (index) { ref.read(overtimeStatusFilterProvider.notifier).state = _tabStatusKeys[index]; }, ), Expanded( child: itemsAsync.when( loading: () => const LoadingWidget(), error: (_, _) => const EmptyState(message: '加载失败'), data: (items) => items.isEmpty ? const EmptyState(message: '暂无加班记录') : RefreshIndicator( onRefresh: () async { ref.invalidate(overtimeListProvider); }, child: ListView.builder( controller: _scrollCtrl, padding: const EdgeInsets.fromLTRB(16, 16, 16, 24), itemCount: items.length, itemBuilder: (_, i) => Padding( padding: const EdgeInsets.only(bottom: 16), child: _buildItem(items[i]), ), ), ), ), ), ], ); } Widget _buildItem(OvertimeModel item) { return ListCard( cardNo: item.applicationNo, description: '${item.otType} · ${item.compensationType}', amount: '${item.otHours.toStringAsFixed(1)}小时', date: du.DateUtils.formatDate(item.otDate), statusTag: StatusTag.fromStatus(item.status), onTap: () => context.push('/overtime/detail/${item.id}'), ); } }