// 功能描述:配置用户端路由、鉴权守卫及登录后安全回跳。 // 版本:1.1.0 import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import '../ui/features/auth/login_page.dart'; import '../ui/features/address/addresses_page.dart'; import '../ui/features/auth/register_page.dart'; import '../ui/features/home/home_page.dart'; import '../ui/features/orders/orders_page.dart'; import '../ui/features/orders/gas_contracts_page.dart'; import '../ui/features/orders/shop_order_detail_page.dart'; import '../ui/features/orders/payment_confirmation_page.dart'; import '../ui/features/orders/gas_order_create_page.dart'; import '../ui/features/orders/delivery_detail_page.dart'; import '../ui/features/orders/delivery_track_page.dart'; import '../ui/features/orders/invoice_preview_page.dart'; import '../ui/features/profile/profile_page.dart'; import '../ui/features/profile/devices_page.dart'; import '../ui/features/profile/device_groups_page.dart'; import '../ui/features/profile/emergency_contacts_page.dart'; import '../ui/features/profile/family_sharing_page.dart'; import '../ui/features/profile/profile_edit_page.dart'; import '../ui/features/profile/user_records_page.dart'; import '../ui/features/profile/usage_statistics_page.dart'; import '../ui/features/profile/message_center_page.dart'; import '../ui/features/settings/settings_page.dart'; import '../ui/features/settings/login_password_page.dart'; import '../ui/features/settings/payment_password_page.dart'; import '../ui/features/wallet/wallet_page.dart'; import '../ui/features/wallet/recharge_records_page.dart'; import '../ui/features/wallet/recharge_page.dart'; import '../ui/features/wallet/wallet_bills_page.dart'; import '../ui/features/wallet/withdrawal_page.dart'; import '../ui/features/wallet/bank_cards_page.dart'; import '../ui/features/wallet/deposit_page.dart'; import '../ui/features/wallet/deposit_return_page.dart'; import '../ui/features/shop/shop_page.dart'; import '../ui/features/shop/checkout_page.dart'; import '../ui/features/shop/cart_page.dart'; import '../ui/features/shop/favorites_page.dart'; import '../ui/features/shop/product_detail_page.dart'; import '../ui/features/home/safety_contents_page.dart'; import '../ui/features/tickets/ticket_detail_page.dart'; import '../ui/features/tickets/repair_page.dart'; import 'auth_navigation.dart'; import 'dependencies.dart'; GoRouter createRouter( AppDependencies dependencies, { String initialLocation = '/home', }) => GoRouter( initialLocation: initialLocation, refreshListenable: dependencies.session, redirect: (context, state) { final authRoute = state.matchedLocation == '/login' || state.matchedLocation == '/register'; final publicRoute = state.matchedLocation == '/home' || state.matchedLocation == '/shop' || state.matchedLocation == '/contents' || state.matchedLocation.startsWith('/contents/') || state.matchedLocation.startsWith('/products/'); if (!dependencies.session.isAuthenticated && !authRoute && !publicRoute) { return buildAuthLocation( '/login', redirectTarget: state.uri.toString(), sessionExpired: dependencies.session.hasExpired, ); } if (dependencies.session.isAuthenticated && state.matchedLocation == '/login') { return sanitizeRedirectTarget(state.uri.queryParameters['redirect']) ?? '/home'; } return null; }, routes: [ GoRoute( path: '/devices', builder: (_, state) => DevicesPage(repository: dependencies.repository), ), GoRoute( path: '/records', builder: (_, state) => UserRecordsPage(repository: dependencies.repository), ), GoRoute( path: '/usage', builder: (_, state) => UsageStatisticsPage(repository: dependencies.repository), ), GoRoute( path: '/messages', builder: (_, state) => MessageCenterPage(repository: dependencies.repository), ), GoRoute( path: '/device-groups', builder: (_, state) => DeviceGroupsPage(repository: dependencies.repository), ), GoRoute( path: '/safety/contacts', builder: (_, state) => EmergencyContactsPage(repository: dependencies.repository), ), GoRoute( path: '/family', builder: (_, state) => FamilySharingPage(repository: dependencies.repository), ), GoRoute( path: '/contents', builder: (_, state) => SafetyContentsPage(repository: dependencies.repository), ), GoRoute( path: '/contents/:identity', builder: (_, state) => SafetyContentsPage( repository: dependencies.repository, identity: state.pathParameters['identity']!, ), ), GoRoute( path: '/settings/payment-password', builder: (_, state) => PaymentPasswordPage(repository: dependencies.repository), ), GoRoute( path: '/settings', builder: (_, state) => SettingsPage(repository: dependencies.repository, session: dependencies.session), ), GoRoute( path: '/settings/password', builder: (_, state) => LoginPasswordPage(repository: dependencies.repository, session: dependencies.session), ), GoRoute( path: '/gas/order', builder: (_, _) => GasOrderCreatePage(repository: dependencies.repository), ), GoRoute( path: '/gas/orders/:identity', builder: (_, state) => ShopOrderDetailPage( repository: dependencies.repository, identity: state.pathParameters['identity']!, business: 'gas', ), ), GoRoute( path: '/shop/orders/:identity', builder: (_, state) => ShopOrderDetailPage( repository: dependencies.repository, identity: state.pathParameters['identity']!, ), ), GoRoute( path: '/gas/orders/:identity/delivery', builder: (_, state) => DeliveryDetailPage( repository: dependencies.repository, identity: state.pathParameters['identity']!, ), ), GoRoute( path: '/gas/orders/:identity/delivery/track', builder: (_, state) => DeliveryTrackPage( repository: dependencies.repository, identity: state.pathParameters['identity']!, ), ), GoRoute( path: '/invoice/:business/:identity', builder: (_, state) => InvoicePreviewPage( repository: dependencies.repository, business: state.pathParameters['business']!, identity: state.pathParameters['identity']!, ), ), GoRoute( path: '/payment/:business/:identity', builder: (_, state) => PaymentConfirmationPage( repository: dependencies.repository, business: state.pathParameters['business']!, identity: state.pathParameters['identity']!, ), ), GoRoute( path: '/favorites', builder: (_, state) => FavoritesPage(repository: dependencies.repository), ), GoRoute( path: '/cart', builder: (_, state) => CartPage(repository: dependencies.repository), ), GoRoute( path: '/cart/checkout', builder: (_, state) => CheckoutPage(repository: dependencies.repository, productIdentity: '', fromCart: true), ), GoRoute( path: '/repair', builder: (_, state) => RepairPage( repository: dependencies.repository, draftStore: dependencies.repairDraftStore, ), ), GoRoute( path: '/tickets/:identity', builder: (_, state) => TicketDetailPage( repository: dependencies.repository, identity: state.pathParameters['identity']!, ), ), GoRoute( path: '/checkout/:identity', builder: (_, state) => CheckoutPage( repository: dependencies.repository, productIdentity: state.pathParameters['identity']!, initialQuantity: int.tryParse(state.uri.queryParameters['quantity'] ?? '') ?? 1, ), ), GoRoute( path: '/products/:identity', builder: (_, state) => ProductDetailPage( repository: dependencies.repository, identity: state.pathParameters['identity']!, authenticated: dependencies.session.isAuthenticated, ), ), GoRoute( path: '/addresses', builder: (context, state) => AddressesPage( repository: dependencies.repository, selecting: state.uri.queryParameters['select'] == '1', ), ), GoRoute( path: '/profile/edit', builder: (context, state) => ProfileEditPage(repository: dependencies.repository), ), GoRoute( path: '/login', builder: (context, state) => LoginPage( session: dependencies.session, repository: dependencies.repository, redirectTarget: sanitizeRedirectTarget(state.uri.queryParameters['redirect']), showSessionExpiredMessage: state.uri.queryParameters['reason'] == 'expired', ), ), GoRoute( path: '/register', builder: (context, state) => RegisterPage( session: dependencies.session, redirectTarget: sanitizeRedirectTarget(state.uri.queryParameters['redirect']), showSessionExpiredMessage: state.uri.queryParameters['reason'] == 'expired', ), ), GoRoute( path: '/records/contracts', builder: (context, state) => GasContractsPage(repository: dependencies.repository), ), GoRoute( path: '/wallet', builder: (context, state) => WalletPage(repository: dependencies.repository), ), GoRoute( path: '/records/wallet', builder: (context, state) => WalletBillsPage(repository: dependencies.repository), ), GoRoute( path: '/wallet/recharge-records', builder: (context, state) => RechargeRecordsPage(repository: dependencies.repository), ), GoRoute( path: '/wallet/recharge', builder: (context, state) => RechargePage(repository: dependencies.repository), ), GoRoute( path: '/wallet/withdraw', builder: (context, state) => WithdrawalPage(repository: dependencies.repository), ), GoRoute( path: '/wallet/banks', builder: (context, state) => BankCardsPage(repository: dependencies.repository), ), GoRoute( path: '/deposits', builder: (context, state) => DepositPage(repository: dependencies.repository), ), GoRoute( path: '/deposits/return', builder: (context, state) => DepositReturnPage( repository: dependencies.repository, depositIdentity: state.uri.queryParameters['deposit'] ?? '', ), ), StatefulShellRoute.indexedStack( builder: (context, state, navigationShell) => _UserShell(navigationShell: navigationShell), branches: [ StatefulShellBranch( routes: [ GoRoute( path: '/home', builder: (context, state) => HomePage( repository: dependencies.repository, authenticated: dependencies.session.isAuthenticated, ), ), ], ), StatefulShellBranch( routes: [ GoRoute( path: '/shop', builder: (context, state) => ShopPage( repository: dependencies.repository, authenticated: dependencies.session.isAuthenticated, ), ), ], ), StatefulShellBranch( routes: [ GoRoute( path: '/orders', builder: (context, state) => OrdersPage( key: ValueKey(state.uri.queryParameters['tab']), repository: dependencies.repository, initialTab: switch (state.uri.queryParameters['tab']) { 'gas' => 1, 'shop' => 0, 'tickets' => 3, _ => 1, }, ), ), ], ), StatefulShellBranch( routes: [ GoRoute( path: '/me', builder: (context, state) => ProfilePage( session: dependencies.session, repository: dependencies.repository, openRepair: state.uri.queryParameters['repair'] == '1', ), ), ], ), ], ), ], ); class _UserShell extends StatelessWidget { const _UserShell({required this.navigationShell}); final StatefulNavigationShell navigationShell; @override Widget build(BuildContext context) => Scaffold( body: navigationShell, bottomNavigationBar: NavigationBar( selectedIndex: navigationShell.currentIndex, onDestinationSelected: (index) => navigationShell.goBranch(index, initialLocation: index == navigationShell.currentIndex), destinations: const [ NavigationDestination( icon: Icon(Icons.home_outlined), selectedIcon: Icon(Icons.home), label: '首页', ), NavigationDestination( icon: Icon(Icons.shopping_bag_outlined), selectedIcon: Icon(Icons.shopping_bag), label: '商城', ), NavigationDestination( icon: Icon(Icons.receipt_long_outlined), selectedIcon: Icon(Icons.receipt_long), label: '订单', ), NavigationDestination( icon: Icon(Icons.person_outline), selectedIcon: Icon(Icons.person), label: '我的', ), ], ), ); }