From c32f052cb0566408b367b29ccdbfe9371030c3fb Mon Sep 17 00:00:00 2001 From: liyi Date: Mon, 18 Aug 2025 14:48:24 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E8=B0=83=E6=95=B4=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E4=B8=ADUI=EF=BC=88=E6=9C=AA=E5=AE=8C?= =?UTF-8?q?=E6=88=90=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../doorLockLog/date_time_extensions.dart | 11 + .../doorLockLog/doorLockLog_logic.dart | 3 +- .../doorLockLog/doorLockLog_page.dart | 138 ++++------- .../doorLockLog/doorLockLog_state.dart | 17 +- .../doorLockLog/week_calendar_view.dart | 220 ++++++++++++++++++ 5 files changed, 294 insertions(+), 95 deletions(-) create mode 100644 lib/main/lockDetail/doorLockLog/date_time_extensions.dart create mode 100644 lib/main/lockDetail/doorLockLog/week_calendar_view.dart diff --git a/lib/main/lockDetail/doorLockLog/date_time_extensions.dart b/lib/main/lockDetail/doorLockLog/date_time_extensions.dart new file mode 100644 index 00000000..3f68a99f --- /dev/null +++ b/lib/main/lockDetail/doorLockLog/date_time_extensions.dart @@ -0,0 +1,11 @@ +extension DateTimeExtensions on DateTime { + /// 返回一个新的 DateTime,只保留年月日,时间部分设为 00:00:00.000 + DateTime get withoutTime { + return DateTime(year, month, day); + } + + /// 判断两个日期是否是同一天(忽略时间) + bool isSameDate(DateTime other) { + return year == other.year && month == other.month && day == other.day; + } +} \ No newline at end of file diff --git a/lib/main/lockDetail/doorLockLog/doorLockLog_logic.dart b/lib/main/lockDetail/doorLockLog/doorLockLog_logic.dart index 4999b8ed..599850bf 100755 --- a/lib/main/lockDetail/doorLockLog/doorLockLog_logic.dart +++ b/lib/main/lockDetail/doorLockLog/doorLockLog_logic.dart @@ -4,6 +4,7 @@ import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:get/get.dart'; import 'package:star_lock/apm/apm_helper.dart'; import 'package:star_lock/app_settings/app_settings.dart'; +import 'package:star_lock/main/lockDetail/doorLockLog/date_time_extensions.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_state.dart'; @@ -235,7 +236,7 @@ class DoorLockLogLogic extends BaseGetXController { lockId: state.keyInfos.value.lockId!, lockEventType: state.dropdownValue.value, pageNo: pageNo, - pageSize: int.parse(pageSize), + pageSize: 1000, startDate: state.startDate.value, endDate: state.endDate.value); if (entity.errorCode!.codeIsSuccessful) { diff --git a/lib/main/lockDetail/doorLockLog/doorLockLog_page.dart b/lib/main/lockDetail/doorLockLog/doorLockLog_page.dart index e9f93968..00578350 100755 --- a/lib/main/lockDetail/doorLockLog/doorLockLog_page.dart +++ b/lib/main/lockDetail/doorLockLog/doorLockLog_page.dart @@ -5,10 +5,13 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:intl/intl.dart'; import 'package:star_lock/appRouters.dart'; +import 'package:star_lock/app_settings/app_settings.dart'; +import 'package:star_lock/main/lockDetail/doorLockLog/date_time_extensions.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_logic.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_state.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/exportRecordDialog/exportRecordDialog_page.dart'; +import 'package:star_lock/main/lockDetail/doorLockLog/week_calendar_view.dart'; import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart'; import 'package:star_lock/main/lockDetail/videoLog/widget/full_screenImage_page.dart'; import 'package:star_lock/main/lockDetail/videoLog/widget/video_thumbnail_image.dart'; @@ -97,12 +100,6 @@ class _DoorLockLogPageState extends State with RouteAware { crossAxisAlignment: CrossAxisAlignment.start, children: [ topAdvancedCalendarWidget(), - Divider( - height: 1, - color: AppColors.greyLineColor, - indent: 30.w, - endIndent: 30.w, - ), eventDropDownWidget(), Expanded(child: timeLineView()) ], @@ -152,88 +149,14 @@ class _DoorLockLogPageState extends State with RouteAware { } } - // switch (value) { - // case "读取记录".tr: - // { - // logic.mockNetworkDataRequest(isRefresh: true); - // } - // break; - // case '清空记录'.tr: - // { - // ShowCupertinoAlertView().showClearOperationRecordAlert( - // clearClick: () { - // logic.clearOperationRecordRequest(); - // }); - // } - // break; - // case '导出记录': - // { - // showDialog( - // context: context, - // builder: (BuildContext context) { - // return ExportRecordDialog( - // onExport: (String filePath) { - // Get.toNamed(Routers.exportSuccessPage, - // arguments: {'filePath': filePath}); - // }, - // ); - // }, - // ); - // } - // break; - // } - // } - //顶部日历小部件 Widget topAdvancedCalendarWidget() { - final ThemeData theme = Theme.of(context); - return Theme( - data: theme.copyWith( - textTheme: theme.textTheme.copyWith( - titleMedium: theme.textTheme.titleMedium!.copyWith( - fontSize: 16, - color: theme.colorScheme.secondary, - ), - bodyLarge: theme.textTheme.bodyLarge!.copyWith( - fontSize: 14, - color: Colors.black54, - ), - bodyMedium: theme.textTheme.bodyMedium!.copyWith( - fontSize: 12, - color: Colors.black87, - ), - ), - primaryColor: AppColors.mainColor, - highlightColor: Colors.yellow, - disabledColor: Colors.grey, - ), - child: Stack( - children: [ - AdvancedCalendar( - controller: state.calendarControllerCustom, - events: state.events, - weekLineHeight: 48.0, - startWeekDay: 1, - innerDot: true, - keepLineSize: true, - calendarTextStyle: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w400, - height: 1.3125, - letterSpacing: 0, - ), - ), - Positioned( - top: 8.0, - right: 8.0, - child: Obx(() => Text( - '${state.currentSelectDate.value.year}${'年'.tr}${state.currentSelectDate.value.month}${'月'.tr}', - style: theme.textTheme.titleMedium!.copyWith( - fontSize: 16, - color: theme.colorScheme.secondary, - ), - )), - ), + return Container( + margin: EdgeInsets.only(top: 20.h, left: 30.w, bottom: 10.h, right: 20.w), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildWeekCalendar(), ], ), ); @@ -325,7 +248,8 @@ class _DoorLockLogPageState extends State with RouteAware { return '${formatTimestampToHHmm(item.operateDate!)} ' + '密码'.tr + '开锁'.tr + - '(${'昵称'.tr}:${item.username})'+'(${'密码'.tr}:${item.keyboardPwd})'; + '(${'昵称'.tr}:${item.username})' + + '(${'密码'.tr}:${item.keyboardPwd})'; case 30: return '${formatTimestampToHHmm(item.operateDate!)} ' + '卡'.tr + @@ -622,4 +546,44 @@ class _DoorLockLogPageState extends State with RouteAware { } state.ifCurrentScreen.value = false; } + + List getCurrentWeekDates() { + final now = DateTime.now(); + // weekday: 1=周一, 2=周二, ..., 7=周日 + // 计算距离上一个周日相差的天数 + // 如果今天是周日,weekday == 7,偏移为 0 + final int daysSinceSunday = now.weekday % 7; // 周一=1 -> %7=1, 周日=7 -> %7=0 + + final List weekDates = []; + for (int i = 0; i < 7; i++) { + final DateTime day = DateTime( + now.year, + now.month, + now.day - daysSinceSunday + i, // 从周日开始累加 + ); + weekDates.add(day); + } + + return weekDates; + } + + Widget _buildWeekCalendar() { + return Obx(() { + final list = state.lockLogItemList.value; + final dateSet = list + .map((e) => DateTime.fromMillisecondsSinceEpoch(e.operateDate!)) + .map((dt) => dt.withoutTime) // 转为年月日 + .toSet(); // 用 Set 提升查找性能 + AppLog.log('dateSet:${dateSet}'); + return WeekCalendarView( + hasData: (DateTime date) { + return dateSet.contains(date.withoutTime); + }, + onDateSelected: (DateTime date) {}, + onWeekChanged: (DateTime start, DateTime end) { + + }, + ); + }); + } } diff --git a/lib/main/lockDetail/doorLockLog/doorLockLog_state.dart b/lib/main/lockDetail/doorLockLog/doorLockLog_state.dart index 722e605e..0732970f 100755 --- a/lib/main/lockDetail/doorLockLog/doorLockLog_state.dart +++ b/lib/main/lockDetail/doorLockLog/doorLockLog_state.dart @@ -1,4 +1,3 @@ - import 'package:get/get.dart'; import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart'; @@ -13,10 +12,13 @@ class DoorLockLogState { DoorLockLogState() { keyInfos.value = Get.arguments['keyInfo']; } + final Rx lockLogEntity = DoorLockLogEntity().obs; final Rx keyInfos = LockListInfoItemEntity().obs; final RxList lockLogItemList = [].obs; + final RxList eventList = + [].obs; final AdvancedCalendarController calendarControllerToday = AdvancedCalendarController.today(); final AdvancedCalendarController calendarControllerCustom = @@ -26,13 +28,14 @@ class DoorLockLogState { DateTime(2024, 10, 10), ]; - final RxInt startDate = - DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day) - .millisecondsSinceEpoch - .obs; +// 获取当前月份的第一天 00:00:00.000 + final RxInt startDate = DateTime(DateTime.now().year, DateTime.now().month, 1) + .millisecondsSinceEpoch + .obs; + +// 获取当前月份的最后一天 23:59:59.999 final RxInt endDate = DateTime( - DateTime.now().year, DateTime.now().month, DateTime.now().day + 1) - .subtract(const Duration(milliseconds: 1)) + DateTime.now().year, DateTime.now().month + 1, 0, 23, 59, 59, 999) .millisecondsSinceEpoch .obs; diff --git a/lib/main/lockDetail/doorLockLog/week_calendar_view.dart b/lib/main/lockDetail/doorLockLog/week_calendar_view.dart new file mode 100644 index 00000000..de4f77c0 --- /dev/null +++ b/lib/main/lockDetail/doorLockLog/week_calendar_view.dart @@ -0,0 +1,220 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:star_lock/app_settings/app_colors.dart'; +import 'package:star_lock/main/lockDetail/doorLockLog/date_time_extensions.dart'; + +class WeekCalendarView extends StatefulWidget { + // 用于判断某一天是否有数据(激活状态) + final bool Function(DateTime date)? hasData; + final void Function(DateTime date)? onDateSelected; // 新增:选中日期回调 + final void Function(DateTime start, DateTime end)? onWeekChanged; + + const WeekCalendarView({ + Key? key, + this.hasData, + this.onDateSelected, + this.onWeekChanged, + }) : super(key: key); + + @override + _WeekCalendarViewState createState() => _WeekCalendarViewState(); +} + +class _WeekCalendarViewState extends State { + final PageController _pageController = PageController(initialPage: 500); + int _currentPage = 500; + + // 当前选中的日期(以 DateTime 格式存储) + late DateTime _selectedDate; + + @override + void initState() { + super.initState(); + _selectedDate = DateTime.now().withoutTime; // 默认选中今天 + } + + // 获取指定 page 对应的一周日期 + List _getWeekDatesForPage(int page) { + final now = DateTime.now(); + final baseSunday = + DateTime(now.year, now.month, now.day - (now.weekday % 7)); + final daysOffset = (page - 500) * 7; + final targetSunday = baseSunday.add(Duration(days: daysOffset)); + return List.generate( + 7, + (i) => DateTime( + targetSunday.year, targetSunday.month, targetSunday.day + i)); + } + + // 判断是否为今天 + bool _isToday(DateTime date) { + final now = DateTime.now(); + return date.year == now.year && + date.month == now.month && + date.day == now.day; + } + + // 判断是否为选中日期 + bool _isSelected(DateTime date) { + return date.year == _selectedDate.year && + date.month == _selectedDate.month && + date.day == _selectedDate.day; + } + + // 判断是否有数据(激活状态) + bool _hasData(DateTime date) { + return widget.hasData?.call(date.withoutTime) ?? false; + } + + void _onDateSelected(DateTime date) { + setState(() { + _selectedDate = date.withoutTime; + }); + // 触发回调,通知父组件 + widget.onDateSelected?.call(date); + } + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 当前周范围提示 + _buildWeekRangeLabel(_currentPage), + + SizedBox(height: 10.h), + + SizedBox( + height: 100.h, + child: PageView.builder( + controller: _pageController, + itemCount: 1000, + itemBuilder: (context, page) { + final weekDates = _getWeekDatesForPage(page); + return Row( + children: weekDates.asMap().entries.map((entry) { + final int index = entry.key; + final DateTime date = entry.value; + final bool isSelected = _isSelected(date); + final bool hasData = _hasData(date); + final bool isToday = _isToday(date); + + // 确定文字颜色 + Color textColor; + if (isSelected) { + textColor = Colors.white; // 选中时文字为白色 + } else if (hasData) { + textColor = Colors.black; // 有数据:黑色 + } else if (isToday) { + textColor = Colors.black; // 今天:黑色 + } else { + textColor = Colors.grey; // 默认:灰色 + } + + // 确定背景颜色 + Color? bgColor; + if (isSelected) { + bgColor = AppColors.mainColor; // 选中用主题色 + } + // 其他状态无背景 + + return GestureDetector( + onTap: () => _onDateSelected(date), + child: Container( + padding: EdgeInsets.all(4.w), + width: 75.w, + height: 75.w, + decoration: BoxDecoration( + color: bgColor, + borderRadius: BorderRadius.circular(50.r), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + [ + '简写周日', + '简写周一', + '简写周二', + '简写周三', + '简写周四', + '简写周五', + '简写周六' + ][index] + .tr, + style: TextStyle( + fontSize: 14.sp, + color: textColor, + fontWeight: FontWeight.w400, + ), + ), + Text( + date.day.toString(), + style: TextStyle( + fontSize: 26.sp, + color: textColor, + fontWeight: FontWeight.w600, + ), + ), + if (isToday && !isSelected) // 今天但未选中 + SizedBox(height: 2.h), + if (isToday && !isSelected) + Container( + width: 6.w, + height: 6.w, + decoration: BoxDecoration( + color: AppColors.mainColor, + shape: BoxShape.circle, + ), + ), + ], + ), + ), + ); + }).toList(), + ); + }, + onPageChanged: (page) { + setState(() { + _currentPage = page; + }); + // ✅ 获取当前页对应的周的起止日期 + final dates = _getWeekDatesForPage(page); + final startOfWeek = dates.first; + final endOfWeek = dates.last; + + // ✅ 触发回调,可用于请求接口 + widget.onWeekChanged?.call(startOfWeek, endOfWeek); + }, + ), + ), + ], + ); + } + + Widget _buildWeekRangeLabel(int page) { + final dates = _getWeekDatesForPage(page); + final start = dates[0]; + final end = dates[6]; + + String label; + + if (start.year == end.year) { + // 同一年:显示为 "2025年8月18日 - 8月24日" + label = + '${start.year}${'年'.tr}${start.month}${'月'.tr}${start.day}${'日'.tr} - ${end.month}${'月'.tr}${end.day}${'日'.tr}'; + } else { + // 跨年:显示为 "2024年12月31日 - 2025年1月6日" + label = + '${start.year}${'年'.tr}${start.month}${'月'.tr}${start.day}${'日'.tr} - ${end.year}${'年'.tr}${end.month}${'月'.tr}${end.day}${'日'.tr}'; + } + + return Text( + label, + style: TextStyle(fontSize: 24.sp, fontWeight: FontWeight.w600), + ); + } +}