| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- import 'package:flutter_riverpod/flutter_riverpod.dart';
- import 'package:go_router/go_router.dart';
- import 'package:tdesign_flutter/tdesign_flutter.dart';
- import '../../core/theme/app_colors.dart';
- import '../../core/utils/responsive.dart';
- import 'home_controller.dart';
- class HomePage extends ConsumerWidget {
- const HomePage({super.key});
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- final summaryAsync = ref.watch(homeSummaryProvider);
- return Scaffold(
- appBar: TDNavBar(
- title: 'TBOSS · 工作台',
- titleColor: Colors.white,
- backgroundColor: const Color(0xFF00ABF3),
- centerTitle: false,
- useDefaultBack: false,
- leftBarItems: [TDNavBarItem(icon: Icons.close, iconColor: Colors.white, action: () => SystemNavigator.pop())],
- ),
- body: summaryAsync.when(
- loading: () =>
- const Center(child: CircularProgressIndicator()),
- error: (_, __) => const Center(child: Text('加载失败')),
- data: (summary) => LayoutBuilder(
- builder: (context, constraints) {
- final r = ResponsiveHelper(
- width: constraints.maxWidth,
- height: constraints.maxHeight,
- isLandscape: constraints.maxWidth > constraints.maxHeight,
- isWide: constraints.maxWidth > 600,
- );
- return _buildContent(context, summary, r);
- },
- ),
- ),
- );
- }
- Widget _buildContent(
- BuildContext context, HomeSummary summary, ResponsiveHelper r) {
- return SingleChildScrollView(
- padding: const EdgeInsets.all(12),
- child: Column(
- children: [
- _buildSection(
- title: '我的审批',
- r: r,
- items: [
- _EntryItem(
- icon: Icons.receipt_long,
- label: '报销单',
- badge: '${summary.expensePending}待办',
- color: AppColors.primary,
- onTap: () => context.push('/expense/list'),
- ),
- _EntryItem(
- icon: Icons.access_time,
- label: '加班',
- badge: '${summary.overtimePending}待办',
- color: AppColors.primary,
- onTap: () => context.push('/overtime/list'),
- ),
- _EntryItem(
- icon: Icons.directions_car,
- label: '用车',
- badge: '${summary.vehiclePending}待办',
- color: AppColors.warning,
- onTap: () => context.push('/vehicle/list'),
- ),
- _EntryItem(
- icon: Icons.assignment,
- label: '报销申请',
- badge: summary.expenseApplyPending > 0
- ? '${summary.expenseApplyPending}待办'
- : '0待办',
- color: Colors.deepPurple,
- onTap: () => context.push('/expense-apply/list'),
- ),
- ],
- ),
- const SizedBox(height: 12),
- _buildSection(
- title: '我的数据',
- r: r,
- items: [
- _EntryItem(
- icon: Icons.edit_note,
- label: '外出日志',
- badge: '${summary.logCount}条',
- color: AppColors.success,
- onTap: () => context.push('/outing-log/list'),
- ),
- _EntryItem(
- icon: Icons.campaign,
- label: '公告通知',
- badge: summary.announcementUnread > 0
- ? '${summary.announcementUnread}未读'
- : '${summary.announcementCount}条',
- color: const Color(0xFF722ED1),
- onTap: () => context.push('/announcement/list'),
- ),
- ],
- ),
- const SizedBox(height: 12),
- _buildSection(
- title: '报表中心',
- r: r,
- items: [
- _EntryItem(
- icon: Icons.pie_chart,
- label: '报销明细表',
- badge: '',
- color: AppColors.primary,
- onTap: () => context.push('/report/expense-detail'),
- ),
- _EntryItem(
- icon: Icons.bar_chart,
- label: '加班明细表',
- badge: '',
- color: AppColors.success,
- onTap: () => context.push('/report/overtime-detail'),
- ),
- _EntryItem(
- icon: Icons.directions_car,
- label: '用车明细表',
- badge: '',
- color: AppColors.warning,
- onTap: () => context.push('/report/vehicle-detail'),
- ),
- _EntryItem(
- icon: Icons.receipt,
- label: '报销申请明细表',
- badge: '',
- color: Colors.deepPurple,
- onTap: () => context.push('/report/expense-apply-detail'),
- ),
- ],
- ),
- ],
- ),
- );
- }
- Widget _buildSection({
- required String title,
- required ResponsiveHelper r,
- required List<_EntryItem> items,
- }) {
- return Container(
- padding: const EdgeInsets.all(16),
- decoration: BoxDecoration(
- color: AppColors.cardWhite,
- borderRadius: BorderRadius.circular(12),
- boxShadow: [
- BoxShadow(
- color: Colors.black.withValues(alpha: 0.04),
- blurRadius: 4,
- offset: const Offset(0, 1),
- ),
- ],
- ),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- title,
- style: const TextStyle(
- fontSize: 15,
- fontWeight: FontWeight.w600,
- color: AppColors.textPrimary,
- ),
- ),
- const SizedBox(height: 14),
- if (r.isLandscape)
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: items
- .map((item) => Expanded(child: _buildEntry(item)))
- .toList(),
- )
- else
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: items.map((item) => _buildEntry(item)).toList(),
- ),
- ],
- ),
- );
- }
- Widget _buildEntry(_EntryItem item) {
- return GestureDetector(
- onTap: item.onTap,
- child: Column(
- children: [
- Container(
- width: 48,
- height: 48,
- decoration: BoxDecoration(
- color: item.color,
- borderRadius: BorderRadius.circular(24),
- ),
- child: Icon(item.icon, color: Colors.white, size: 24),
- ),
- const SizedBox(height: 8),
- Text(
- item.label,
- style: const TextStyle(
- fontSize: 12,
- color: AppColors.textSecondary,
- ),
- ),
- const SizedBox(height: 2),
- Text(
- item.badge,
- style: TextStyle(
- fontSize: 10,
- color: item.badge.contains('0')
- ? AppColors.textHint
- : AppColors.error,
- ),
- ),
- ],
- ),
- );
- }
- }
- class _EntryItem {
- final IconData icon;
- final String label;
- final String badge;
- final Color color;
- final VoidCallback onTap;
- const _EntryItem({
- required this.icon,
- required this.label,
- required this.badge,
- required this.color,
- required this.onTap,
- });
- }
|