facility_booking_page.dart 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. import 'dart:math';
  2. import 'package:cpt_facility/modules/location/facility_location_page.dart';
  3. import 'package:cs_resources/generated/assets.dart';
  4. import 'package:cs_resources/generated/l10n.dart';
  5. import 'package:cs_resources/theme/app_colors_theme.dart';
  6. import 'package:domain/entity/facility_book_entity.dart';
  7. import 'package:domain/entity/facility_index_entity.dart';
  8. import 'package:flutter/material.dart';
  9. import 'package:auto_route/auto_route.dart';
  10. import 'package:flutter_hooks/flutter_hooks.dart';
  11. import 'package:hooks_riverpod/hooks_riverpod.dart';
  12. import 'package:router/ext/auto_router_extensions.dart';
  13. import 'package:shared/utils/date_time_utils.dart';
  14. import 'package:shared/utils/log_utils.dart';
  15. import 'package:widgets/ext/ex_widget.dart';
  16. import 'package:widgets/load_state_layout.dart';
  17. import 'package:widgets/my_appbar.dart';
  18. import 'package:widgets/my_button.dart';
  19. import 'package:widgets/my_load_image.dart';
  20. import 'package:widgets/my_text_view.dart';
  21. import 'package:widgets/shatter/select_calendar/calendar_bottom_sheet.dart';
  22. import 'package:widgets/widget_export.dart';
  23. import '../../router/page/facility_page_router.dart';
  24. import 'facility_booking_view_model.dart';
  25. @RoutePage()
  26. class FacilityBookingPage extends HookConsumerWidget {
  27. final FacilityIndexEntity facilityEntity;
  28. const FacilityBookingPage({Key? key, required this.facilityEntity}) : super(key: key);
  29. //启动当前页面
  30. static void startInstance({BuildContext? context, required FacilityIndexEntity facilityEntity}) {
  31. if (context != null) {
  32. context.router.push(FacilityBookingPageRoute(facilityEntity: facilityEntity));
  33. } else {
  34. appRouter.push(FacilityBookingPageRoute(facilityEntity: facilityEntity));
  35. }
  36. }
  37. @override
  38. Widget build(BuildContext context, WidgetRef ref) {
  39. final viewModel = ref.watch(facilityBookingViewModelProvider.notifier);
  40. final state = ref.watch(facilityBookingViewModelProvider);
  41. useEffect(() {
  42. // 组件挂载时执行 - 执行接口请求
  43. Future.microtask(() {
  44. viewModel.setFacilityId(facilityEntity.id, facilityEntity.name);
  45. viewModel.fetchListByDate();
  46. });
  47. return () {
  48. // 组件卸载时执行
  49. };
  50. }, []);
  51. return Scaffold(
  52. appBar: MyAppBar.appBar(
  53. context,
  54. facilityEntity.name ?? "",
  55. backgroundColor: context.appColors.backgroundWhite,
  56. actions: [
  57. //去设施小区的定位图片
  58. Visibility(
  59. visible: facilityEntity.mapResources.isNotEmpty,
  60. child: const MyAssetImage(
  61. Assets.facilityTitleLocationIcon,
  62. width: 44,
  63. height: 44,
  64. ).marginOnly(right: 3).onTap(() {
  65. FacilityLocationPage.startInstance(context: context, imageUrls: facilityEntity.mapResources);
  66. }),
  67. )
  68. ],
  69. ),
  70. backgroundColor: context.appColors.backgroundDark,
  71. body: Column(
  72. mainAxisSize: MainAxisSize.max,
  73. crossAxisAlignment: CrossAxisAlignment.center,
  74. children: [
  75. //顶部的选中的日期与日历选择
  76. Row(
  77. mainAxisSize: MainAxisSize.max,
  78. children: [
  79. MyTextView(
  80. "${DateTimeUtils.getWeekday(state.selectedDate, languageCode: 'en')}, ${DateTimeUtils.formatDate(state.selectedDate, format: 'dd MMM yyyy')}",
  81. textColor: context.appColors.textBlack,
  82. fontSize: 17,
  83. marginTop: 18,
  84. marginBottom: 16,
  85. marginLeft: 15,
  86. isFontMedium: true,
  87. ).expanded(),
  88. const MyAssetImage(Assets.facilityConfirmDateIcon, width: 22.5, height: 22.5).marginOnly(right: 10).onTap(() {
  89. //日历日期选择器
  90. _datePickerBottomSheet(context, ref);
  91. }, padding: 5),
  92. ],
  93. ),
  94. //二周的日期选择
  95. WeeklyCalendar(
  96. selectedDate: state.selectedDate,
  97. onChangedSelectedDate: (dateTime) {
  98. viewModel.changeSelectedDate(dateTime);
  99. },
  100. ),
  101. //每天的单独数据
  102. LoadStateLayout(
  103. state: state.loadingState,
  104. errorMessage: state.errorMessage,
  105. errorRetry: () {
  106. viewModel.retryRequest();
  107. },
  108. successSliverWidget: [
  109. SliverToBoxAdapter(
  110. child: MyTextView(
  111. S.current.quota_left_msg(state.data?.remainQuota ?? 0, state.data?.quotaResetOn ?? "-"),
  112. marginTop: 7,
  113. marginLeft: 10,
  114. marginBottom: 15,
  115. textColor: context.appColors.textBlack,
  116. fontSize: 12,
  117. isFontMedium: true,
  118. ),
  119. ),
  120. SliverList(
  121. delegate: SliverChildBuilderDelegate(
  122. (context, index) {
  123. return _buildFacilityOption(context, ref, state.data?.facilities?[index], index);
  124. },
  125. childCount: state.data?.facilities?.length,
  126. ))
  127. ],
  128. ).marginOnly(top: 5).expanded(),
  129. //底部按钮
  130. MyButton(
  131. onPressed: viewModel.gotoConfirmPage,
  132. text: S.current.next,
  133. textColor: Colors.white,
  134. backgroundColor: context.appColors.btnBgDefault,
  135. fontWeight: FontWeight.w500,
  136. type: ClickType.throttle,
  137. fontSize: 16,
  138. minHeight: 50,
  139. radius: 0,
  140. )
  141. ],
  142. ),
  143. );
  144. }
  145. //日期日历的选择器,底部弹窗选择
  146. void _datePickerBottomSheet(BuildContext context, WidgetRef ref) {
  147. final viewModel = ref.watch(facilityBookingViewModelProvider.notifier);
  148. final state = ref.watch(facilityBookingViewModelProvider);
  149. showModalBottomSheet<void>(
  150. context: context,
  151. isScrollControlled: true,
  152. shape: const RoundedRectangleBorder(
  153. borderRadius: BorderRadius.only(topLeft: Radius.circular(30.0), topRight: Radius.circular(30.0)),
  154. ),
  155. builder: (BuildContext context) {
  156. return CustomCalendarBottomSheet(
  157. firstDate: DateTime.now(),
  158. lastDate: DateTime.now().add(const Duration(days: 365)),
  159. selectedDate: state.selectedDate,
  160. locale: "en",
  161. onDateChange: (dateTime) {
  162. Navigator.pop(context);
  163. viewModel.changeSelectedDate(dateTime);
  164. },
  165. );
  166. },
  167. );
  168. }
  169. //生产当前设施的选项
  170. Widget _buildFacilityOption(BuildContext context, WidgetRef ref, FacilityBookFacilities? item, int index) {
  171. final viewModel = ref.watch(facilityBookingViewModelProvider.notifier);
  172. return Column(
  173. children: [
  174. Container(
  175. width: double.infinity,
  176. height: 38,
  177. color: context.appColors.btnBgDefault,
  178. child: Center(
  179. child: MyTextView(
  180. item?.name ?? "",
  181. fontSize: 16,
  182. textColor: Colors.white,
  183. textAlign: TextAlign.center,
  184. isFontMedium: true,
  185. ),
  186. ),
  187. ),
  188. GridView.builder(
  189. shrinkWrap: true,
  190. physics: const NeverScrollableScrollPhysics(),
  191. gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
  192. crossAxisCount: 4,
  193. childAspectRatio: 82 / 43,
  194. mainAxisSpacing: 6.5,
  195. crossAxisSpacing: 6.5,
  196. ),
  197. itemCount: item?.periods?.length,
  198. itemBuilder: (context, innerIndex) {
  199. return Container(
  200. decoration: BoxDecoration(
  201. color: item?.periods?[innerIndex].selected == true
  202. ? context.appColors.orangeBG
  203. : item?.periods?[innerIndex].enable == true
  204. ? context.appColors.whiteBG
  205. : context.appColors.disEnableGray,
  206. borderRadius: BorderRadius.circular(5.0),
  207. ),
  208. child: Column(
  209. crossAxisAlignment: CrossAxisAlignment.center,
  210. mainAxisAlignment: MainAxisAlignment.center, // 垂直居中
  211. children: [
  212. MyTextView(
  213. item?.periods?[innerIndex].start ?? "",
  214. fontSize: 12,
  215. textColor: item?.periods?[innerIndex].selected == true ? context.appColors.textWhite : context.appColors.textBlack,
  216. isFontMedium: true,
  217. ),
  218. MyTextView(
  219. item?.periods?[innerIndex].end ?? "",
  220. fontSize: 12,
  221. textColor: item?.periods?[innerIndex].selected == true ? context.appColors.textWhite : context.appColors.textBlack,
  222. isFontMedium: true,
  223. ),
  224. ],
  225. ),
  226. ).onTap(() {
  227. //点击选中,可用并且未选中的情况下点击选中
  228. if (item?.periods?[innerIndex].enable == true && item?.periods?[innerIndex].selected == false) {
  229. viewModel.selectPeriods(index, innerIndex);
  230. }
  231. });
  232. },
  233. ).marginSymmetric(horizontal: 10, vertical: 17),
  234. ],
  235. );
  236. }
  237. }