import 'package:flutter/material.dart'; import '../core/app_colors.dart'; /// Shared visual building blocks for doctor and administrator pages. /// /// These widgets intentionally contain no business state so the back-office /// screens keep using their existing providers and services. class BackofficeSurface extends StatelessWidget { final Widget child; const BackofficeSurface({super.key, required this.child}); @override Widget build(BuildContext context) { return DecoratedBox( decoration: const BoxDecoration(gradient: AppColors.bgGradient), child: child, ); } } class BackofficeSectionCard extends StatelessWidget { final Widget child; final EdgeInsetsGeometry padding; final EdgeInsetsGeometry? margin; const BackofficeSectionCard({ super.key, required this.child, this.padding = const EdgeInsets.all(16), this.margin, }); @override Widget build(BuildContext context) { return Container( margin: margin, padding: padding, decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.94), borderRadius: BorderRadius.circular(20), border: Border.all(color: Colors.white), boxShadow: AppColors.cardShadowLight, ), child: child, ); } } class BackofficeLoadingState extends StatelessWidget { final String message; const BackofficeLoadingState({super.key, this.message = '正在加载'}); @override Widget build(BuildContext context) { return Center( child: BackofficeSectionCard( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 20), child: Column( mainAxisSize: MainAxisSize.min, children: [ const SizedBox( width: 28, height: 28, child: CircularProgressIndicator( strokeWidth: 2.5, color: AppColors.primary, ), ), const SizedBox(height: 12), Text(message, style: const TextStyle(color: AppColors.textHint)), ], ), ), ); } } class BackofficeEmptyState extends StatelessWidget { final IconData icon; final String title; final String? description; final String? actionLabel; final VoidCallback? onAction; const BackofficeEmptyState({ super.key, required this.icon, required this.title, this.description, this.actionLabel, this.onAction, }); @override Widget build(BuildContext context) { return Center( child: Padding( padding: const EdgeInsets.all(24), child: BackofficeSectionCard( padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 30), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( width: 64, height: 64, decoration: const BoxDecoration( color: AppColors.primaryLight, shape: BoxShape.circle, ), child: Icon(icon, size: 30, color: AppColors.primary), ), const SizedBox(height: 16), Text( title, textAlign: TextAlign.center, style: const TextStyle( fontSize: 17, fontWeight: FontWeight.w700, color: AppColors.textPrimary, ), ), if (description != null) ...[ const SizedBox(height: 6), Text( description!, textAlign: TextAlign.center, style: const TextStyle( fontSize: 13, height: 1.5, color: AppColors.textHint, ), ), ], if (actionLabel != null && onAction != null) ...[ const SizedBox(height: 18), FilledButton( onPressed: onAction, style: FilledButton.styleFrom( backgroundColor: AppColors.primary, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 22, vertical: 11, ), ), child: Text(actionLabel!), ), ], ], ), ), ), ); } } class BackofficeErrorState extends StatelessWidget { final String message; final VoidCallback? onRetry; const BackofficeErrorState({super.key, this.message = '加载失败', this.onRetry}); @override Widget build(BuildContext context) { return BackofficeEmptyState( icon: Icons.cloud_off_outlined, title: message, description: '请检查网络后重试', actionLabel: onRetry == null ? null : '重新加载', onAction: onRetry, ); } } class BackofficeInactiveDoctorBanner extends StatelessWidget { const BackofficeInactiveDoctorBanner({super.key}); @override Widget build(BuildContext context) { return Container( margin: const EdgeInsets.only(bottom: 16), padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: AppColors.warningLight, borderRadius: BorderRadius.circular(16), border: Border.all(color: AppColors.warning.withValues(alpha: 0.35)), ), child: const Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(Icons.pause_circle_outline, color: AppColors.warningText), SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '账号已停用', style: TextStyle( fontSize: 15, fontWeight: FontWeight.w700, color: AppColors.warningText, ), ), SizedBox(height: 3), Text( '您仍可服务已绑定患者,但新患者暂时无法选择您。', style: TextStyle( fontSize: 13, height: 1.4, color: AppColors.textSecondary, ), ), ], ), ), ], ), ); } }