import 'package:flutter/material.dart'; import 'package:patbond_flutter/core/theme/app_theme.dart'; import 'package:patbond_flutter/data/demo_data.dart'; import 'package:patbond_flutter/models/models.dart'; import 'package:patbond_flutter/widgets/common.dart'; class ServicesPage extends StatefulWidget { const ServicesPage({ required this.showPersonal, required this.locationWeather, super.key, }); final bool showPersonal; final LocationWeather locationWeather; @override State createState() => _ServicesPageState(); } class _ServicesPageState extends State { late bool personal; String query = ''; String filter = '全部'; @override void initState() { super.initState(); personal = widget.showPersonal; } @override void didUpdateWidget(covariant ServicesPage oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.showPersonal != widget.showPersonal) { personal = widget.showPersonal; } } List get providers { final keyword = query.trim().toLowerCase(); var list = serviceProviders.where((provider) { final matchesType = personal ? provider.kind == ProviderKind.personal : provider.kind != ProviderKind.personal; final matchesQuery = keyword.isEmpty || provider.name.toLowerCase().contains(keyword) || provider.description.toLowerCase().contains(keyword) || provider.tags.any((tag) => tag.toLowerCase().contains(keyword)); return matchesType && matchesQuery; }).toList(); if (!personal) { if (filter == '距离优先') { list.sort( (a, b) => double.parse( a.distance.replaceAll('km', ''), ).compareTo(double.parse(b.distance.replaceAll('km', ''))), ); } else if (filter == '24H急诊') { list = list.where((item) => item.tags.contains('24H急诊')).toList(); } else if (filter == '美容洗护') { list = list .where((item) => item.kind == ProviderKind.grooming) .toList(); } } return list; } Future book(ServiceProviderModel provider) async { final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('确认预约'), content: Text('预约 ${provider.name}\n服务价格:¥${provider.price} 起'), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('取消'), ), FilledButton( onPressed: () => Navigator.pop(context, true), child: const Text('确认'), ), ], ), ); if (confirmed == true && mounted) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text('已提交「${provider.name}」预约(演示)'))); } } @override Widget build(BuildContext context) { return ListView( padding: const EdgeInsets.fromLTRB(16, 12, 16, 28), children: [ SegmentedButton( segments: const [ ButtonSegment( value: false, icon: Icon(Icons.apartment_outlined), label: Text('专业机构'), ), ButtonSegment( value: true, icon: Icon(Icons.person_pin_circle_outlined), label: Text('个人服务'), ), ], selected: {personal}, showSelectedIcon: false, onSelectionChanged: (value) => setState(() { personal = value.first; filter = '全部'; }), ), const SizedBox(height: 10), Row( children: [ const Icon( Icons.near_me_outlined, size: 17, color: AppColors.primary, ), const SizedBox(width: 5), Text( '正在展示 ${widget.locationWeather.displayArea} 附近的服务', style: Theme.of(context).textTheme.bodySmall, ), ], ), const SizedBox(height: 14), TextField( onChanged: (value) => setState(() => query = value), decoration: InputDecoration( hintText: personal ? '搜索遛狗、寄养或上门喂养…' : '搜索宠物医院、美容或服务…', prefixIcon: const Icon(Icons.search), suffixIcon: IconButton( tooltip: '筛选', onPressed: () => ScaffoldMessenger.of( context, ).showSnackBar(const SnackBar(content: Text('可使用下方快捷筛选条件'))), icon: const Icon(Icons.tune), ), ), ), if (!personal) ...[ const SizedBox(height: 12), SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: ['全部', '距离优先', '24H急诊', '美容洗护'] .map( (value) => Padding( padding: const EdgeInsets.only(right: 8), child: ChoiceChip( label: Text(value), selected: filter == value, onSelected: (_) => setState(() => filter = value), ), ), ) .toList(), ), ), ], const SizedBox(height: 16), if (providers.isEmpty) const EmptyState(message: '没有找到符合条件的服务') else ...providers.map( (provider) => Padding( padding: const EdgeInsets.only(bottom: 14), child: _ServiceCard( provider: provider, onBook: () => book(provider), ), ), ), ], ); } } class _ServiceCard extends StatelessWidget { const _ServiceCard({required this.provider, required this.onBook}); final ServiceProviderModel provider; final VoidCallback onBook; @override Widget build(BuildContext context) { return Card( clipBehavior: Clip.antiAlias, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Stack( children: [ AspectRatio( aspectRatio: 16 / 7, child: RemoteImage(url: provider.image), ), if (provider.verified) const Positioned( left: 12, top: 12, child: TagPill('认证服务', color: AppColors.success), ), Positioned( right: 12, bottom: 10, child: DecoratedBox( decoration: BoxDecoration( color: Colors.white.withAlpha(235), borderRadius: BorderRadius.circular(12), ), child: Padding( padding: const EdgeInsets.symmetric( horizontal: 9, vertical: 5, ), child: Text( '⭐ ${provider.rating}', style: const TextStyle(fontWeight: FontWeight.w800), ), ), ), ), ], ), Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( provider.name, style: Theme.of(context).textTheme.titleMedium, ), ), Text( provider.distance, style: Theme.of(context).textTheme.bodySmall, ), ], ), const SizedBox(height: 6), Text(provider.description), const SizedBox(height: 10), Wrap( spacing: 7, runSpacing: 7, children: provider.tags.map(TagPill.new).toList(), ), const SizedBox(height: 14), Row( children: [ Text( '¥${provider.price}', style: const TextStyle( color: AppColors.primary, fontSize: 20, fontWeight: FontWeight.w900, ), ), const Text(' 起', style: TextStyle(color: AppColors.muted)), const Spacer(), FilledButton.icon( onPressed: onBook, icon: const Icon(Icons.calendar_month_outlined, size: 18), label: const Text('立即预约'), ), ], ), ], ), ), ], ), ); } }