Переглянути джерело

完善两个日期选择的联动

liukai 4 днів тому
батько
коміт
9814a01fd4

+ 0 - 4
packages/cpt_facility/lib/modules/booking/facility_booking_page.dart

@@ -68,15 +68,11 @@ class FacilityBookingPage extends HookConsumerWidget {
 
             //二周的日期选择
             WeeklyCalendar(
-              isAutoSelect: false,
               selectedDate: state.selectedDate,
               onChangedSelectedDate: (dateTime) {
                 Log.d("onChangedSelectedDate选中 - ${dateTime}}");
                 viewModel.changeSelectedDate(dateTime);
               },
-              onChangedPage: (dateTime, state) {
-                Log.d("onChangedPage - ${dateTime} state:${state}");
-              },
             ),
 
           ],

+ 24 - 7
packages/cs_widgets/lib/shatter/weekly_calendar/calendar_utils.dart

@@ -1,3 +1,5 @@
+import 'package:shared/utils/date_time_utils.dart';
+
 DateTime addDay(DateTime date, int days) {
   return date.add(Duration(days: days));
 }
@@ -18,6 +20,25 @@ DateTime firstDayOfWeek(DateTime date) {
   return date.subtract(Duration(days: date.weekday - 1));
 }
 
+//是否包含选中的日期
+bool hasSelectedDate(List<DateTime> list, DateTime selected) {
+  for (DateTime date in list) {
+    // 格式化日期并进行比较
+    if (DateTimeUtils.formatDate(date, format: 'yyyyMMdd') == DateTimeUtils.formatDate(selected, format: 'yyyyMMdd')) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// 检查日期是否小于今天
+bool isPastDate(DateTime now, DateTime date) {
+  // 获取当前日期的凌晨时间
+  DateTime todayMidnight = DateTime(now.year, now.month, now.day);
+  // 判断给定日期是否小于今天的凌晨时间
+  return date.isBefore(todayMidnight);
+}
+
 // ===================================  获取一周的数据  ↓  ===================================
 
 List<DateTime> getWeekdays(DateTime date, int at) {
@@ -40,9 +61,7 @@ List<DateTime> _subtractWeek(DateTime date, int subtract) {
 }
 
 List<DateTime> _getWeekDaysAt(DateTime date) {
-  return List.generate(7, (index) => index)
-      .map((index) => date.add(Duration(days: index)))
-      .toList();
+  return List.generate(7, (index) => index).map((index) => date.add(Duration(days: index))).toList();
 }
 
 // ===================================  获取二周的数据  ↓  ===================================
@@ -67,7 +86,5 @@ List<DateTime> _subtract2Week(DateTime date, int subtract) {
 }
 
 List<DateTime> _get2WeekDaysAt(DateTime date) {
-  return List.generate(14, (index) => index)
-      .map((index) => date.add(Duration(days: index)))
-      .toList();
-}
+  return List.generate(14, (index) => index).map((index) => date.add(Duration(days: index))).toList();
+}

+ 4 - 5
packages/cs_widgets/lib/shatter/weekly_calendar/day_cell.dart

@@ -1,6 +1,7 @@
 import 'package:cs_resources/theme/app_colors_theme.dart';
 import 'package:flutter/material.dart';
 import 'package:shared/utils/date_time_utils.dart';
+import 'calendar_utils.dart';
 
 class DayCell extends StatelessWidget {
   const DayCell({
@@ -26,7 +27,7 @@ class DayCell extends StatelessWidget {
       width: 40,
       height: 40,
       decoration: BoxDecoration(
-        color: _isPastDate(display)
+        color: isPastDate(current,display)
             ? context.appColors.disEnableGray.withOpacity(0.6) // 小于今天的日期背景颜色,禁用
             : _isSelected(display)
                 ? _isToday(display)
@@ -79,8 +80,6 @@ class DayCell extends StatelessWidget {
     return DateTimeUtils.formatDate(date, format: 'yyyyMMdd') == DateTimeUtils.formatDate(current, format: 'yyyyMMdd');
   }
 
-  // 检查日期是否小于今天
-  bool _isPastDate(DateTime date) {
-    return date.isBefore(DateTime.now().subtract(const Duration(days: 1))); // 小于今天
-  }
+
+
 }

+ 5 - 9
packages/cs_widgets/lib/shatter/weekly_calendar/day_table_view.dart

@@ -1,4 +1,5 @@
 import 'package:flutter/material.dart';
+import 'calendar_utils.dart';
 import 'day_cell.dart';
 
 /// 一周的数据为一行,展示两周共两行
@@ -24,9 +25,9 @@ class DayTableView extends StatelessWidget {
         Row(
           mainAxisAlignment: MainAxisAlignment.spaceAround,
           children: weekdays.sublist(0, 7).map(
-                (date) {
+            (date) {
               return GestureDetector(
-                onTap: _isPastDate(date) ? null : () => onSelect?.call(date),
+                onTap: isPastDate(currentDate, date) ? null : () => onSelect?.call(date),
                 child: SizedBox(
                   width: 40,
                   height: 40,
@@ -47,9 +48,9 @@ class DayTableView extends StatelessWidget {
         Row(
           mainAxisAlignment: MainAxisAlignment.spaceAround,
           children: weekdays.sublist(7, 14).map(
-                (date) {
+            (date) {
               return GestureDetector(
-                onTap: _isPastDate(date) ? null : () => onSelect?.call(date),
+                onTap: isPastDate(currentDate, date) ? null : () => onSelect?.call(date),
                 child: SizedBox(
                   width: 40,
                   height: 40,
@@ -66,9 +67,4 @@ class DayTableView extends StatelessWidget {
       ],
     );
   }
-
-  // 检查日期是否小于今天
-  bool _isPastDate(DateTime date) {
-    return date.isBefore(DateTime.now().subtract(const Duration(days: 1))); // 小于今天
-  }
 }

+ 203 - 203
packages/cs_widgets/lib/shatter/weekly_calendar/week_page.dart

@@ -1,203 +1,203 @@
-import 'package:flutter/material.dart';
-import 'package:shared/utils/log_utils.dart';
-import 'calendar_utils.dart' show get2Weekdays, addDay, subtractDay, firstDayOfWeek;
-import 'day_table_view.dart';
-
-enum PageState {
-  previous,
-  current,
-  next,
-}
-
-/// 一周的Days的PageView页面
-class WeekPage extends StatefulWidget {
-  const WeekPage({
-    super.key,
-    required this.selectedDate,
-    required this.now,
-    required this.isAutoSelect,
-    this.onChangedSelectedDate,
-    this.onChangedPage,
-  });
-
-  final DateTime now;
-  final DateTime selectedDate;
-  final bool isAutoSelect;
-
-  final Function(DateTime)? onChangedSelectedDate; //选择日期变化的监听
-  final Function(DateTime date, PageState state)? onChangedPage; //切换日期Page的监听
-
-  final double height = 40 + 40 + 10;
-
-  @override
-  State<StatefulWidget> createState() => _WeekPageState();
-}
-
-class _WeekPageState extends State<WeekPage> {
-  double get height => widget.height;
-  final int initialPage = 999;
-  List<int> pageCounts = [0, 1, 2];
-  int currentPage = 1;
-  late DateTime _currentPageDate;
-  late DateTime _slectedDate;
-
-  DateTime get now => widget.now;
-
-  DateTime get selectedDate => widget.selectedDate;
-
-  late PageController _pageController;
-
-  @override
-  void initState() {
-    super.initState();
-    _currentPageDate = selectedDate;
-    _slectedDate = selectedDate;
-    _pageController = PageController(initialPage: initialPage);
-  }
-
-  @override
-  void didUpdateWidget(covariant WeekPage oldWidget) {
-    super.didUpdateWidget(oldWidget);
-
-    if (widget.selectedDate != oldWidget.selectedDate) {
-      setState(() {
-        _currentPageDate = widget.selectedDate;
-        _slectedDate = widget.selectedDate;
-      });
-
-      // 计算要滚动到的页面索引
-      int targetPageIndex = _calculateTargetPageIndex(widget.selectedDate);
-
-      // 使用 WidgetsBinding 以确保在构建完成后再跳转页面
-      WidgetsBinding.instance.addPostFrameCallback((_) {
-        // 检查目标页面索引是否在有效范围内
-        Log.d("targetPageIndex:$targetPageIndex pageCounts.length:${pageCounts.length}");
-        if (targetPageIndex >= 0 && targetPageIndex < pageCounts.length) {
-          _pageController.jumpToPage(targetPageIndex);
-        } else {
-          //超过了索引就刷新数据源?
-          Log.d("超过了索引就刷新数据源");
-        }
-      });
-    }
-  }
-
-  // 计算要滚动到的页面索引
-  int _calculateTargetPageIndex(DateTime date) {
-    // 获取当前周的第一天
-    DateTime currentFirstDayOfWeek = firstDayOfWeek(now);
-    // 获取选中日期的周的第一天
-    DateTime targetFirstDayOfWeek = firstDayOfWeek(date);
-
-    // 计算当前日期与目标日期之间的天数差
-    int differenceInDays = targetFirstDayOfWeek.difference(currentFirstDayOfWeek).inDays + 1;
-
-    // 计算目标页面索引
-    // 每页14天
-    int targetPageIndex = (differenceInDays / 14).floor(); // 用floor确保向下取整
-
-    // 确保目标索引在有效范围内
-    // targetPageIndex = (targetPageIndex + pageCounts.length) % pageCounts.length;
-
-    Log.d("differenceInDays:$differenceInDays targetPageIndex:$targetPageIndex");
-
-    return targetPageIndex;
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    return Flexible(
-      child: AnimatedSize(
-        duration: const Duration(milliseconds: 250),
-        curve: Curves.easeInOut,
-        alignment: Alignment.topCenter,
-        child: SizedBox(
-          height: height,
-          child: pageViewBuilder(),
-        ),
-      ),
-    );
-  }
-
-  //PageView的方式展示不同的星期,每周每一个Page
-  Widget pageViewBuilder() {
-    return PageView.builder(
-      itemBuilder: (context, index) {
-        final idx = _getIndex(index);
-        return dayTable(idx);
-      },
-      onPageChanged: onPageChanged,
-      controller: _pageController,
-    );
-  }
-
-  //两周的数据
-  Widget dayTable(int index) {
-    int at = pageCounts[index] - 1;
-    final weekdays = get2Weekdays(now, at);
-    return DayTableView(
-      weekdays: weekdays,
-      onSelect: (date) {
-        setState(() {
-          _slectedDate = date;
-        });
-        //主动点击之后回调
-        widget.onChangedSelectedDate?.call(date);
-      },
-      selectedDate: _slectedDate,
-      currentDate: now,
-    );
-  }
-
-  //是否需要切换页面的时候自动选中
-  void changeSelectedDate(int value) {
-    if (_pageState(value) == PageState.next) {
-      if (widget.isAutoSelect) {
-        _slectedDate = addDay(selectedDate, 14);
-        widget.onChangedSelectedDate?.call(_slectedDate);
-      }
-    } else {
-      if (widget.isAutoSelect) {
-        _slectedDate = subtractDay(selectedDate, 14);
-        widget.onChangedSelectedDate?.call(_slectedDate);
-      }
-    }
-  }
-
-  //当切换页面的时候更新当前页面数据,返回当前页面第一条数据的日期
-  void updateCurrentPageDate(int value) {
-    final first = firstDayOfWeek(_currentPageDate);
-
-    if (_pageState(value) == PageState.next) {
-      _currentPageDate = addDay(first, 14);
-      widget.onChangedPage?.call(_currentPageDate, PageState.next);
-    } else {
-      _currentPageDate = subtractDay(first, 14);
-      widget.onChangedPage?.call(_currentPageDate, PageState.previous);
-    }
-  }
-
-  void onPageChanged(int value) {
-    changeSelectedDate(value);
-    updateCurrentPageDate(value);
-
-    int currentIndex = _getIndex(value);
-    int leftIndex = (currentIndex - 1 < 0) ? pageCounts.length - 1 : currentIndex - 1;
-    int rightIndex = (currentIndex + 1 > pageCounts.length - 1) ? 0 : currentIndex + 1;
-
-    pageCounts[leftIndex] = pageCounts[currentIndex] - 1;
-    pageCounts[rightIndex] = pageCounts[currentIndex] + 1;
-
-    currentPage = pageCounts[currentIndex];
-  }
-
-  int _getIndex(int idx) {
-    return (idx + 1) % pageCounts.length;
-  }
-
-  PageState _pageState(int idx) {
-    final prePage = currentPage;
-    final current = pageCounts[_getIndex(idx)];
-    return (prePage < current) ? PageState.next : PageState.previous;
-  }
-}
+// import 'package:flutter/material.dart';
+// import 'package:shared/utils/log_utils.dart';
+// import 'calendar_utils.dart' show get2Weekdays, addDay, subtractDay, firstDayOfWeek;
+// import 'day_table_view.dart';
+//
+// enum PageState {
+//   previous,
+//   current,
+//   next,
+// }
+//
+// /// 一周的Days的PageView页面
+// class WeekPage extends StatefulWidget {
+//   const WeekPage({
+//     super.key,
+//     required this.selectedDate,
+//     required this.now,
+//     required this.isAutoSelect,
+//     this.onChangedSelectedDate,
+//     this.onChangedPage,
+//   });
+//
+//   final DateTime now;
+//   final DateTime selectedDate;
+//   final bool isAutoSelect;
+//
+//   final Function(DateTime)? onChangedSelectedDate; //选择日期变化的监听
+//   final Function(DateTime date, PageState state)? onChangedPage; //切换日期Page的监听
+//
+//   final double height = 40 + 40 + 10;
+//
+//   @override
+//   State<StatefulWidget> createState() => _WeekPageState();
+// }
+//
+// class _WeekPageState extends State<WeekPage> {
+//   double get height => widget.height;
+//   final int initialPage = 999;
+//   List<int> pageCounts = [0, 1, 2];
+//   int currentPage = 1;
+//   late DateTime _currentPageDate;
+//   late DateTime _slectedDate;
+//
+//   DateTime get now => widget.now;
+//
+//   DateTime get selectedDate => widget.selectedDate;
+//
+//   late PageController _pageController;
+//
+//   @override
+//   void initState() {
+//     super.initState();
+//     _currentPageDate = selectedDate;
+//     _slectedDate = selectedDate;
+//     _pageController = PageController(initialPage: initialPage);
+//   }
+//
+//   @override
+//   void didUpdateWidget(covariant WeekPage oldWidget) {
+//     super.didUpdateWidget(oldWidget);
+//
+//     if (widget.selectedDate != oldWidget.selectedDate) {
+//       setState(() {
+//         _currentPageDate = widget.selectedDate;
+//         _slectedDate = widget.selectedDate;
+//       });
+//
+//       // 计算要滚动到的页面索引
+//       int targetPageIndex = _calculateTargetPageIndex(widget.selectedDate);
+//
+//       // 使用 WidgetsBinding 以确保在构建完成后再跳转页面
+//       WidgetsBinding.instance.addPostFrameCallback((_) {
+//         // 检查目标页面索引是否在有效范围内
+//         Log.d("targetPageIndex:$targetPageIndex pageCounts.length:${pageCounts.length}");
+//         if (targetPageIndex >= 0 && targetPageIndex < pageCounts.length) {
+//           _pageController.jumpToPage(targetPageIndex);
+//         } else {
+//           //超过了索引就刷新数据源?
+//           Log.d("超过了索引就刷新数据源");
+//         }
+//       });
+//     }
+//   }
+//
+//   // 计算要滚动到的页面索引
+//   int _calculateTargetPageIndex(DateTime date) {
+//     // 获取当前周的第一天
+//     DateTime currentFirstDayOfWeek = firstDayOfWeek(now);
+//     // 获取选中日期的周的第一天
+//     DateTime targetFirstDayOfWeek = firstDayOfWeek(date);
+//
+//     // 计算当前日期与目标日期之间的天数差
+//     int differenceInDays = targetFirstDayOfWeek.difference(currentFirstDayOfWeek).inDays + 1;
+//
+//     // 计算目标页面索引
+//     // 每页14天
+//     int targetPageIndex = (differenceInDays / 14).floor(); // 用floor确保向下取整
+//
+//     // 确保目标索引在有效范围内
+//     // targetPageIndex = (targetPageIndex + pageCounts.length) % pageCounts.length;
+//
+//     Log.d("differenceInDays:$differenceInDays targetPageIndex:$targetPageIndex");
+//
+//     return targetPageIndex;
+//   }
+//
+//   @override
+//   Widget build(BuildContext context) {
+//     return Flexible(
+//       child: AnimatedSize(
+//         duration: const Duration(milliseconds: 250),
+//         curve: Curves.easeInOut,
+//         alignment: Alignment.topCenter,
+//         child: SizedBox(
+//           height: height,
+//           child: pageViewBuilder(),
+//         ),
+//       ),
+//     );
+//   }
+//
+//   //PageView的方式展示不同的星期,每周每一个Page
+//   Widget pageViewBuilder() {
+//     return PageView.builder(
+//       itemBuilder: (context, index) {
+//         final idx = _getIndex(index);
+//         return dayTable(idx);
+//       },
+//       onPageChanged: onPageChanged,
+//       controller: _pageController,
+//     );
+//   }
+//
+//   //两周的数据
+//   Widget dayTable(int index) {
+//     int at = pageCounts[index] - 1;
+//     final weekdays = get2Weekdays(now, at);
+//     return DayTableView(
+//       weekdays: weekdays,
+//       onSelect: (date) {
+//         setState(() {
+//           _slectedDate = date;
+//         });
+//         //主动点击之后回调
+//         widget.onChangedSelectedDate?.call(date);
+//       },
+//       selectedDate: _slectedDate,
+//       currentDate: now,
+//     );
+//   }
+//
+//   //是否需要切换页面的时候自动选中
+//   void changeSelectedDate(int value) {
+//     if (_pageState(value) == PageState.next) {
+//       if (widget.isAutoSelect) {
+//         _slectedDate = addDay(selectedDate, 14);
+//         widget.onChangedSelectedDate?.call(_slectedDate);
+//       }
+//     } else {
+//       if (widget.isAutoSelect) {
+//         _slectedDate = subtractDay(selectedDate, 14);
+//         widget.onChangedSelectedDate?.call(_slectedDate);
+//       }
+//     }
+//   }
+//
+//   //当切换页面的时候更新当前页面数据,返回当前页面第一条数据的日期
+//   void updateCurrentPageDate(int value) {
+//     final first = firstDayOfWeek(_currentPageDate);
+//
+//     if (_pageState(value) == PageState.next) {
+//       _currentPageDate = addDay(first, 14);
+//       widget.onChangedPage?.call(_currentPageDate, PageState.next);
+//     } else {
+//       _currentPageDate = subtractDay(first, 14);
+//       widget.onChangedPage?.call(_currentPageDate, PageState.previous);
+//     }
+//   }
+//
+//   void onPageChanged(int value) {
+//     changeSelectedDate(value);
+//     updateCurrentPageDate(value);
+//
+//     int currentIndex = _getIndex(value);
+//     int leftIndex = (currentIndex - 1 < 0) ? pageCounts.length - 1 : currentIndex - 1;
+//     int rightIndex = (currentIndex + 1 > pageCounts.length - 1) ? 0 : currentIndex + 1;
+//
+//     pageCounts[leftIndex] = pageCounts[currentIndex] - 1;
+//     pageCounts[rightIndex] = pageCounts[currentIndex] + 1;
+//
+//     currentPage = pageCounts[currentIndex];
+//   }
+//
+//   int _getIndex(int idx) {
+//     return (idx + 1) % pageCounts.length;
+//   }
+//
+//   PageState _pageState(int idx) {
+//     final prePage = currentPage;
+//     final current = pageCounts[_getIndex(idx)];
+//     return (prePage < current) ? PageState.next : PageState.previous;
+//   }
+// }

+ 25 - 27
packages/cs_widgets/lib/shatter/weekly_calendar/weekly_calendar.dart

@@ -1,25 +1,20 @@
 import 'package:flutter/material.dart';
 import 'package:intl/date_symbol_data_local.dart';
 import 'package:shared/utils/log_utils.dart';
-import 'package:widgets/shatter/weekly_calendar/week_page.dart';
-
-import 'calendar_utils.dart' show getWeekdays;
+import 'calendar_utils.dart';
 import 'day_of_week_view.dart';
+import 'day_table_view.dart';
 
 /// 总入口,整合顶部的Week控件与底部的Days的PageView控件
 class WeeklyCalendar extends StatefulWidget {
   const WeeklyCalendar({
     super.key,
-    this.isAutoSelect = false,
     this.onChangedSelectedDate,
-    this.onChangedPage,
     this.selectedDate,
   });
 
-  final DateTime? selectedDate;
-  final bool isAutoSelect;
-  final Function(DateTime)? onChangedSelectedDate;
-  final Function(DateTime date, PageState state)? onChangedPage;
+  final DateTime? selectedDate; //当前选中的日期
+  final Function(DateTime)? onChangedSelectedDate; //选择日期的回调
 
   @override
   State<StatefulWidget> createState() => _WeeklyCalendarState();
@@ -27,22 +22,33 @@ class WeeklyCalendar extends StatefulWidget {
 
 class _WeeklyCalendarState extends State<WeeklyCalendar> {
   final DateTime now = DateTime.now();
-  DateTime currentPageDate = DateTime.now();
   DateTime? selectedDate;
+  late List<DateTime> currentDateList;
 
   @override
   void initState() {
     initializeDateFormatting("en"); //日期国际化指定
     super.initState();
-    selectedDate = widget.selectedDate ?? DateTime.now();
+
+    currentDateList = get2Weekdays(now, 0); //双周的数据
+    selectedDate = widget.selectedDate ?? now; //默认选中的数据
   }
 
   @override
   void didUpdateWidget(covariant WeeklyCalendar oldWidget) {
     super.didUpdateWidget(oldWidget);
     if (widget.selectedDate != oldWidget.selectedDate) {
+      //查看当前页面Date数据是否包含选中的 selectedDate
+      bool hasSelected = hasSelectedDate(currentDateList, widget.selectedDate ?? now);
+
       setState(() {
         selectedDate = widget.selectedDate;
+
+        if (!hasSelected) {
+          //如果不包含,需要更换数据源
+          Log.d("选中日期不在当前页面,需要更换数据源");
+          currentDateList = get2Weekdays(widget.selectedDate ?? now, 0);
+        }
       });
     }
   }
@@ -57,27 +63,19 @@ class _WeeklyCalendarState extends State<WeeklyCalendar> {
 
         const SizedBox(height: 12),
 
-        //底部是每个星期的Days的PageView布局
-        WeekPage(
-          selectedDate: selectedDate ?? DateTime.now(),
-          //默认选中的日期,如果没有填写默认是今天
-          now: now,
-          //今天的日期
-          isAutoSelect: widget.isAutoSelect,
-          //翻页是否自动选中
-          onChangedPage: (date, state) {
-            setState(() {
-              currentPageDate = date;
-            });
-            widget.onChangedPage?.call(date, state);
-          },
-          onChangedSelectedDate: (date) {
+        //底部是当前二周的数据
+        DayTableView(
+          weekdays: currentDateList,
+          onSelect: (date) {
             setState(() {
               selectedDate = date;
             });
+            //主动点击之后回调
             widget.onChangedSelectedDate?.call(date);
           },
-        ),
+          selectedDate: selectedDate ?? now,
+          currentDate: now,
+        )
       ],
     );
   }