import 'package:flutter/material.dart'; import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:go_router/go_router.dart'; import '../../utils/constants.dart'; import '../../theme/app_colors.dart'; import '../common/app_button.dart'; /// 应用侧边栏组件 class AppSidebar extends StatefulWidget { const AppSidebar({Key? key}) : super(key: key); @override State createState() => _AppSidebarState(); } class _AppSidebarState extends State { bool _collapsed = false; @override Widget build(BuildContext context) { final currentPath = GoRouterState.of(context).uri.path; return AnimatedContainer( duration: const Duration(milliseconds: 240), curve: Curves.easeOutCubic, width: _collapsed ? 84 : 280, decoration: BoxDecoration( gradient: const LinearGradient( colors: [ Color(0xFFF9FBFD), Color(0xFFFFFFFF), ], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), border: Border( right: BorderSide(color: AppColors.borderLight.withOpacity(0.7)), ), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.04), blurRadius: 24, offset: const Offset(0, 8), ), ], ), child: SafeArea( bottom: true, child: Column( children: [ _buildBrandSection(), const SizedBox(height: 8), Expanded(child: _buildNavigation(currentPath)), _buildFooter(), ], ), ), ); } Widget _buildBrandSection() { return Padding( padding: EdgeInsets.symmetric( horizontal: _collapsed ? 10 : 18, vertical: 18, ), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( width: 48, height: 48, decoration: BoxDecoration( borderRadius: BorderRadius.circular(14), gradient: const LinearGradient( colors: [Color(0xFF4D7CFE), Color(0xFF72B6FB)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), boxShadow: [ BoxShadow( color: AppColors.primary.withOpacity(0.25), blurRadius: 16, offset: const Offset(0, 8), ), ], ), child: const Icon( LucideIcons.sparkles, color: Colors.white, size: 24, ), ), if (!_collapsed) ...[ const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: const [ Text( '灵越智报', style: TextStyle( fontSize: 18, fontWeight: FontWeight.w700, color: AppColors.textPrimary, letterSpacing: 0.4, ), ), SizedBox(height: 4), Text( '智能票据 · 知识化处理', style: TextStyle( fontSize: 11, color: AppColors.textSecondary, letterSpacing: 0.2, ), ), ], ), ), ], Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(12), onTap: () { setState(() { _collapsed = !_collapsed; }); }, child: Container( width: 32, height: 32, decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), color: AppColors.backgroundLight, ), child: Icon( _collapsed ? LucideIcons.chevron_right : LucideIcons.chevron_left, size: 18, color: AppColors.textSecondary, ), ), ), ), ], ), ); } Widget _buildNavigation(String currentPath) { final sections = [ _SidebarSection( title: '工作台', items: [ _SidebarItem( icon: LucideIcons.house, label: '概览总览', path: AppRoutes.home, ), _SidebarItem( icon: LucideIcons.upload, label: '上传与解析', path: AppRoutes.upload, badge: '新', ), _SidebarItem( icon: LucideIcons.sparkles, label: 'AI 处理流程', path: AppRoutes.process, ), ], ), _SidebarSection( title: '业务中心', items: [ _SidebarItem( icon: LucideIcons.layout_panel_left, label: '文档管理', path: AppRoutes.documents, ), _SidebarItem( icon: LucideIcons.network, label: '关系牵引', path: AppRoutes.traction, ), _SidebarItem( icon: LucideIcons.trending_up, label: '结果分析', path: AppRoutes.result, ), ], ), ]; return ListView( padding: EdgeInsets.symmetric( horizontal: _collapsed ? 10 : 16, vertical: 12, ), children: [ if (!_collapsed) _buildInsightCard(), if (!_collapsed) const SizedBox(height: 16), for (final section in sections) ...[ _buildSectionHeader(section.title), const SizedBox(height: 8), for (final item in section.items) _buildNavItem( item, currentPath == item.path, ), const SizedBox(height: 18), ], ], ); } Widget _buildSectionHeader(String title) { return AnimatedOpacity( duration: const Duration(milliseconds: 160), opacity: _collapsed ? 0 : 1, child: Row( children: [ Container( width: 4, height: 12, decoration: BoxDecoration( color: AppColors.primary, borderRadius: BorderRadius.circular(2), ), ), const SizedBox(width: 8), if (!_collapsed) Text( title, style: const TextStyle( fontSize: 12, fontWeight: FontWeight.w600, letterSpacing: 0.4, color: AppColors.textSecondary, ), ), ], ), ); } Widget _buildNavItem(_SidebarItem item, bool isActive) { final itemContent = InkWell( borderRadius: BorderRadius.circular(12), onTap: () => context.go(item.path), child: AnimatedContainer( duration: const Duration(milliseconds: 180), curve: Curves.easeOut, margin: const EdgeInsets.symmetric(vertical: 4), padding: EdgeInsets.symmetric( horizontal: _collapsed ? 12 : 20, vertical: 13, ), decoration: BoxDecoration( color: isActive ? AppColors.primary.withOpacity(0.12) : Colors.transparent, borderRadius: BorderRadius.circular(12), border: Border.all( color: isActive ? AppColors.primary.withOpacity(0.4) : Colors.transparent, width: 1, ), ), child: Row( children: [ AnimatedContainer( duration: const Duration(milliseconds: 240), curve: Curves.easeOut, width: 28, height: 28, decoration: BoxDecoration( color: isActive ? AppColors.primary.withOpacity(0.12) : AppColors.backgroundLight, borderRadius: BorderRadius.circular(8), ), child: Icon( item.icon, size: 16, color: isActive ? AppColors.primary : AppColors.textSecondary, ), ), if (!_collapsed) ...[ const SizedBox(width: 14), Expanded( child: Row( children: [ Expanded( child: Text( item.label, style: TextStyle( fontSize: 15, fontWeight: isActive ? FontWeight.w600 : FontWeight.w500, color: isActive ? AppColors.primary : AppColors.textSecondary, ), ), ), if (item.badge != null) Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 2, ), decoration: BoxDecoration( color: AppColors.primary, borderRadius: BorderRadius.circular(12), ), child: Text( item.badge!, style: const TextStyle( fontSize: 10, color: Colors.white, fontWeight: FontWeight.w600, letterSpacing: 0.4, ), ), ), ], ), ), ], ], ), ), ); if (_collapsed) { return Tooltip( message: item.label, preferBelow: false, child: itemContent, ); } return itemContent; } Widget _buildInsightCard() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), gradient: const LinearGradient( colors: [Color(0xFFEDF4FF), Color(0xFFFFFFFF)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), border: Border.all(color: AppColors.primary.withOpacity(0.08)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: AppColors.primary.withOpacity(0.12)), ), child: Icon( LucideIcons.activity, size: 18, color: AppColors.primary, ), ), const SizedBox(width: 12), const Expanded( child: Text( '今日处理 58 份文档', style: TextStyle( fontSize: 13, fontWeight: FontWeight.w600, color: AppColors.textPrimary, ), ), ), ], ), const SizedBox(height: 12), Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: const [ Text( '成功率', style: TextStyle( fontSize: 11, color: AppColors.textSecondary, ), ), SizedBox(height: 4), Text( '98.4%', style: TextStyle( fontSize: 15, fontWeight: FontWeight.bold, color: AppColors.primary, ), ), ], ), ), Container( width: 1, height: 32, color: AppColors.borderLight, ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: const [ Text( '平均耗时', style: TextStyle( fontSize: 11, color: AppColors.textSecondary, ), ), SizedBox(height: 4), Text( '13.6s', style: TextStyle( fontSize: 15, fontWeight: FontWeight.bold, color: AppColors.textPrimary, ), ), ], ), ), ], ), ], ), ); } Widget _buildFooter() { return Container( padding: EdgeInsets.symmetric( horizontal: _collapsed ? 10 : 18, vertical: 20, ), decoration: BoxDecoration( border: Border( top: BorderSide(color: AppColors.borderLight.withOpacity(0.6)), ), ), child: Column( crossAxisAlignment: _collapsed ? CrossAxisAlignment.center : CrossAxisAlignment.start, children: [ if (!_collapsed) Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: AppColors.primary.withOpacity(0.08), borderRadius: BorderRadius.circular(14), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( '高级能力体验', style: TextStyle( fontSize: 13, fontWeight: FontWeight.w600, color: AppColors.textPrimary, ), ), const SizedBox(height: 6), Text( '解锁批量导出、自动化流程、团队协作等高级特性', style: TextStyle( fontSize: 11, color: AppColors.textSecondary.withOpacity(0.8), height: 1.4, ), ), const SizedBox(height: 12), AppButton( text: '立即升级', type: ButtonType.primary, size: ButtonSize.small, fullWidth: true, onPressed: () {}, ), ], ), ), if (!_collapsed) const SizedBox(height: 16), InkWell( borderRadius: BorderRadius.circular(12), onTap: () {}, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 10), child: Row( children: [ const CircleAvatar( radius: 16, backgroundColor: AppColors.backgroundLight, child: Icon( LucideIcons.user_round, size: 16, color: AppColors.textSecondary, ), ), if (!_collapsed) ...[ const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: const [ Text( 'Han Wen', style: TextStyle( fontSize: 13, fontWeight: FontWeight.w600, color: AppColors.textPrimary, ), ), SizedBox(height: 2), Text( '产品体验账号', style: TextStyle( fontSize: 11, color: AppColors.textSecondary, ), ), ], ), ), const Icon( LucideIcons.log_out, size: 16, color: AppColors.textSecondary, ), ], ], ), ), ), ], ), ); } } class _SidebarItem { final IconData icon; final String label; final String path; final String? badge; _SidebarItem({ required this.icon, required this.label, required this.path, this.badge, }); } class _SidebarSection { final String title; final List<_SidebarItem> items; _SidebarSection({required this.title, required this.items}); }