facility_booking_page.dart 9.3 KB

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