import 'package:flutter/material.dart'; import '../../data/api/report_data_source.dart'; import '../../data/models/models.dart'; import '../../routing/app_routes.dart'; import '../../theme/wise_tokens.dart'; import '../../widgets/app_card.dart'; import '../../widgets/badges.dart'; import '../../widgets/states.dart'; class InstitutionsPage extends StatefulWidget { const InstitutionsPage({required this.dataSource, super.key}); final ReportDataSource dataSource; @override State createState() => _InstitutionsPageState(); } class _InstitutionsPageState extends State { late Future> future = widget.dataSource.institutions(); @override Widget build(BuildContext context) { return FutureBuilder>( future: future, builder: (context, snapshot) { if (snapshot.connectionState != ConnectionState.done) return const LoadingState(); if (snapshot.hasError) return ErrorState(message: snapshot.error.toString(), onRetry: () => setState(() => future = widget.dataSource.institutions())); final items = [...snapshot.data ?? const []]..sort((a, b) => b.reportCount.compareTo(a.reportCount)); if (items.isEmpty) return const EmptyState(title: '暂无机构信息', message: '稍后再试', icon: Icons.account_balance_outlined); return ListView( padding: const EdgeInsets.all(WiseSpacing.x4), children: [ Text('研报来源机构', style: Theme.of(context).textTheme.titleLarge), const SizedBox(height: WiseSpacing.x3), for (final item in items) ...[ InstitutionCard( institution: item, onTap: () => openInstitutionDetail(context, widget.dataSource, item.id), ), const SizedBox(height: WiseSpacing.x3), ], ], ); }, ); } } class InstitutionCard extends StatelessWidget { const InstitutionCard({required this.institution, required this.onTap, super.key}); final Institution institution; final VoidCallback onTap; @override Widget build(BuildContext context) { final initials = institution.nameCn.isEmpty ? '研' : institution.nameCn.characters.take(2).toString(); return AppCard( onTap: onTap, child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ CircleAvatar( radius: 25, backgroundColor: WiseColors.secondary200, foregroundColor: WiseColors.primary, child: Text(initials, style: const TextStyle(fontWeight: FontWeight.w800)), ), const SizedBox(width: WiseSpacing.x3), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(institution.nameCn, style: Theme.of(context).textTheme.titleMedium), if (institution.nameEn.isNotEmpty) Text(institution.nameEn, maxLines: 1, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.bodySmall), const SizedBox(height: WiseSpacing.x2), Wrap( spacing: WiseSpacing.x2, runSpacing: WiseSpacing.x2, children: [ if (institution.institutionType.isNotEmpty) AppBadge(text: institution.institutionType), for (final topic in institution.coveredTopics.take(3)) AppBadge(text: topic, kind: BadgeKind.brand), ], ), ], ), ), const SizedBox(width: WiseSpacing.x2), Column( children: [ Text('${institution.reportCount}', style: Theme.of(context).textTheme.titleMedium?.copyWith(color: WiseColors.primary)), Text('份研报', style: Theme.of(context).textTheme.bodySmall), ], ), ], ), ); } }