diff --git a/images/mine/icon_message_checbox.png b/images/mine/icon_message_checbox.png new file mode 100644 index 00000000..d911945b Binary files /dev/null and b/images/mine/icon_message_checbox.png differ diff --git a/images/mine/icon_message_close.png b/images/mine/icon_message_close.png new file mode 100644 index 00000000..2753fc2a Binary files /dev/null and b/images/mine/icon_message_close.png differ diff --git a/images/mine/icon_message_readed.png b/images/mine/icon_message_readed.png new file mode 100644 index 00000000..6d781ba9 Binary files /dev/null and b/images/mine/icon_message_readed.png differ diff --git a/images/mine/icon_message_unread.png b/images/mine/icon_message_unread.png new file mode 100644 index 00000000..b87c1c32 Binary files /dev/null and b/images/mine/icon_message_unread.png differ diff --git a/lib/app_settings/app_colors.dart b/lib/app_settings/app_colors.dart index 961b6434..f273d9ef 100755 --- a/lib/app_settings/app_colors.dart +++ b/lib/app_settings/app_colors.dart @@ -150,6 +150,7 @@ class AppColors { static Color openPassageModeColor = const Color(0xFFEB2A3B); // 首页开启常开模式颜色(红色) static Color listTimeYellowColor = const Color(0xFFF3BA37); // 首页时间过期颜色(黄色) + static Color messageTipsColor = const Color.fromRGBO(202, 220, 247, 1); //消息页面顶部提示条背景色 static Color get lockDetailBottomBtnUneable => const Color(0xFF808080); // 首页时间灰色颜色(灰色) diff --git a/lib/mine/message/messageList/messageList_page.dart b/lib/mine/message/messageList/messageList_page.dart index dd0cb4ed..74369e70 100755 --- a/lib/mine/message/messageList/messageList_page.dart +++ b/lib/mine/message/messageList/messageList_page.dart @@ -29,6 +29,38 @@ class _MessageListPageState extends State final MessageListLogic logic = Get.put(MessageListLogic()); final MessageListState state = Get.find().state; + // 修改 _showCheckboxes 状态变量为可观察状态 + final RxBool _showCheckboxes = false.obs; + + // 添加选中状态 + final RxList _selectedItems = [].obs; + + // 添加控制通知横幅显示的状态 + bool showNotificationBanner = true; + + // 添加设置状态变量 + final RxBool _pushNotificationEnabled = false.obs; + + // 删除方法 + void deleteSelectedMessages() { + final List selectedMessages = []; + for (int i = 0; i < state.itemDataList.value.length; i++) { + if (_selectedItems[i]) { + selectedMessages.add(state.itemDataList.value[i]); + } + } + + // 调用删除接口 + //logic.deletMessageDataRequest(selectedMessages); + + // 清空选中状态 + _selectedItems.clear(); + _selectedItems.addAll( + List.generate(state.itemDataList.value.length, (index) => false)); + _showCheckboxes.value = false; + setState(() {}); + } + void getHttpData() { logic.messageListDataRequest().then((MessageListEntity value) { setState(() {}); @@ -39,38 +71,60 @@ class _MessageListPageState extends State void initState() { super.initState(); + // 获取当前消息推送设置状态 + _loadPushNotificationStatus(); + getHttpData(); } + // 加载消息推送状态 + void _loadPushNotificationStatus() async { + final bool? enabled = await Storage.getBool('push_notification_enabled'); + _pushNotificationEnabled.value = enabled ?? false; + } + + //添加以时间分组的方法 + Map> _groupMessagesByDate() { + Map> grouped = {}; + state.itemDataList.forEach((item) { + String date = DateTool().dateToYMDString(item.createdAt!.toString()); + if (!grouped.containsKey(date)) { + grouped[date] = []; + } + grouped[date]!.add(item); + }); + return grouped; + } + @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.mainBackgroundColor, appBar: widget.showAppBar ? TitleAppBar( - barTitle: '消息'.tr, - haveBack: true, - actionsList: [ - TextButton( - child: Text( - '清空'.tr, - style: TextStyle(color: Colors.white, fontSize: 24.sp), - ), - onPressed: () async { - final bool? isDemoMode = - await Storage.getBool(ifIsDemoModeOrNot); - if (isDemoMode == false) { - ShowTipView().showIosTipWithContentDialog('是否清空?'.tr, + barTitle: '消息'.tr, + haveBack: true, + actionsList: [ + TextButton( + child: Text( + '清空'.tr, + style: TextStyle(color: Colors.white, fontSize: 24.sp), + ), + onPressed: () async { + final bool? isDemoMode = + await Storage.getBool(ifIsDemoModeOrNot); + if (isDemoMode == false) { + ShowTipView().showIosTipWithContentDialog('是否清空?'.tr, () async { logic.deletAllMessageDataRequest(); }); - } else { - logic.showToast('演示模式'.tr); - } - }, - ), - ], - backgroundColor: AppColors.mainColor) + } else { + logic.showToast('演示模式'.tr); + } + }, + ), + ], + backgroundColor: AppColors.mainColor) : null, body: EasyRefreshTool(onRefresh: () { logic.pageNo = 1; @@ -80,116 +134,354 @@ class _MessageListPageState extends State }, child: Obx(() { return state.itemDataList.value.isEmpty ? NoData() - : SlidableAutoCloseBehavior( + : Stack( + children: [ + Positioned( + top: 0, + left: 0, + right: 0, + child: Container( + height: showNotificationBanner ? 100 : 70, + child: Column(children: [ + showNotificationBanner + ? Container( + padding: + EdgeInsets.only(left: 10, right: 10), + color: AppColors.messageTipsColor, + height: 30, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text('开启消息通知开关,及时获取通知', + style: TextStyle( + color: Colors.black, + fontSize: 20.sp)), + Row(children: [ + !_pushNotificationEnabled.value + ? GestureDetector(child: Text('去开启', + style: TextStyle( + color: Colors.blue, + fontSize: 20.sp)), + onTap: (){ + + }) : SizedBox.shrink(), + SizedBox(width: 10), + InkWell( + child: Image.asset( + 'images/mine/icon_message_close.png', + width: 24.w, + height: 24.w), + onTap: () { + // 可以通过控制一个状态变量来隐藏整个通知栏 + setState(() { + showNotificationBanner = + false; + }); + }), + ]) + ])) + : SizedBox.shrink(), + Container( + padding: + EdgeInsets.only(left: 15.w, right: 24.w, top: 20.h), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text('告警', + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 30.sp)), + // 点击多选可以进行删除 + GestureDetector( + onTap: () { + // 没有多选删除的 api接口,无法使用 + // if (_showCheckboxes.value) { + // deleteSelectedMessages(); + // } else { + // setState(() { + // _showCheckboxes.value = + // !_showCheckboxes.value; + // }); + // } + }, + child: _showCheckboxes.value + ? Text('删除', + style: TextStyle( + fontSize: 24.sp, + color: Colors.red)) + : Image.asset( + 'images/mine/icon_message_checbox.png', + width: 30.w, + height: 30.h), + ) + ]), + ) + ]))), + Container( + child: Container( + padding: EdgeInsets.only( + top: showNotificationBanner ? 80 : 50), child: ListView.builder( - itemCount: state.itemDataList.value.length, - itemBuilder: (BuildContext c, int index) { - final MessageItemEntity messageItemEntity = - state.itemDataList.value[index]; - return Slidable( - key: ValueKey(messageItemEntity.id), - endActionPane: ActionPane( - extentRatio: 0.2, - motion: const ScrollMotion(), - children: [ - SlidableAction( - onPressed: (BuildContext context) { - logic.deletMessageDataRequest( - messageItemEntity.id!, () { - logic.pageNo = 1; - getHttpData(); - }); - }, - backgroundColor: Colors.red, - foregroundColor: Colors.white, - label: '删除'.tr, - padding: EdgeInsets.only(left: 5.w, right: 5.w), - ), - ], + itemCount: _buildGroupedListItems().length, + itemBuilder: (BuildContext context, int index) { + var item = _buildGroupedListItems()[index]; + + if (item is String) { + // 日期标题 + return Container( + padding: EdgeInsets.symmetric( + horizontal: 16.w, vertical: 10.h), + color: AppColors.mainBackgroundColor, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: item.substring(8, 10), + style: TextStyle( + color: Colors.black, + fontSize: 36.sp, + fontWeight: FontWeight.w600, + ), + ), + TextSpan( + text: ' ', + ), + TextSpan( + text: item.substring(5, 7), + style: TextStyle( + color: Colors.grey, fontSize: 20.sp, fontWeight: FontWeight.w400), + ), + ], + ), ), - child: _messageListItem(messageItemEntity, () { - Get.toNamed(Routers.messageDetailPage, - arguments: { - 'messageItemEntity': messageItemEntity - }); - }), ); - }), - ); + } else if (item is MessageItemEntity) { + // 消息项 + return _messageListItem(item, () { + Get.toNamed(Routers.messageDetailPage, + arguments: { + 'messageItemEntity': item + }); + }); + } + return Container(); + }, + ), + ), + ) + ], + ); })), ); } + // 构建分组列表 + List _buildGroupedListItems() { + List items = []; + Map> grouped = _groupMessagesByDate(); + + grouped.forEach((date, messages) { + items.add(date); // 添加日期标题 + items.addAll(messages.map((message) => message)); // 添加该日期下的所有消息 + }); + + // 初始化选中状态 + if (_selectedItems.length != state.itemDataList.value.length) { + _selectedItems.clear(); + _selectedItems.addAll( + List.generate(state.itemDataList.value.length, (index) => false)); + } + + return items; + } + Widget _messageListItem( MessageItemEntity messageItemEntity, Function() action) { + final int index = state.itemDataList.value.indexOf(messageItemEntity); + + // 查找当前消息在其所属日期分组中的位置 + Map> grouped = _groupMessagesByDate(); + bool isLastInGroupSimple = false; + + // 确定当前消息属于哪个日期分组 + for (var entry in grouped.entries) { + int messageIndex = entry.value.indexWhere((msg) => msg.id == messageItemEntity.id); + if (messageIndex != -1) { + // 如果是该分组的最后一条消息 + isLastInGroupSimple = messageIndex == entry.value.length - 1; + break; + } + } + return GestureDetector( - onTap: action, - child: Container( - height: 90.h, - width: 1.sw, - margin: EdgeInsets.only(bottom: 2.h), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10.w), - ), - child: Container( - width: 1.sw, - margin: EdgeInsets.only(left: 20.w, right: 20.w), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( - children: [ - if (messageItemEntity.readAt! == 0) + onTap: () { + // 如果是多选模式,切换选中状态 + if (_showCheckboxes.value) { + _selectedItems[index] = !_selectedItems[index]; + setState(() {}); + } else { + // 否则跳转到详情页 + action(); + } + }, + child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Container( + padding: EdgeInsets.only(left: 10), + transform: Matrix4.translationValues(0, 20, 0), + child: Column( + children: [ + Image.asset( + messageItemEntity.readAt! == 0 + ? 'images/mine/icon_message_unread.png' + : 'images/mine/icon_message_readed.png', + width: 18.w, + height: 18.h), + // 添加竖线,根据是否是分组最后一条消息来决定是否显示 + if (!isLastInGroupSimple) Container( - width: 10.w, - height: 10.w, - decoration: BoxDecoration( - color: Colors.red, - borderRadius: BorderRadius.circular(5.w), - ), + width: 0.5, + height: 190.h, + color: AppColors.placeholderTextColor, ) - else - Container(), - if (messageItemEntity.readAt! == 0) - SizedBox(width: 5.w) - else - Container(), - Flexible( - child: Text( - messageItemEntity.data!, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: 22.sp, - color: messageItemEntity.readAt! == 0 - ? AppColors.blackColor - : AppColors.placeholderTextColor), - ), + ], + )), + Expanded( + child: Slidable( + key: Key(messageItemEntity.id.toString()), // 为每个item添加唯一key + endActionPane: ActionPane( + motion: const ScrollMotion(), + children: [ + SlidableAction( + onPressed: (context) { + // 删除单条消息 + logic.deletMessageDataRequest( + messageItemEntity.id!, () { + logic.pageNo = 1; + getHttpData(); + }); + }, + backgroundColor: Colors.red, + foregroundColor: Colors.white, + icon: Icons.delete, + label: '删除', + ), + ], + ), child: Container( + width: 1.sw, + margin: EdgeInsets.all(20.h), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10.w), ), - ], - ), - SizedBox(height: 10.h), - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - // Image.asset('images/mine/icon_mine_gatewaySignal_strong.png', width: 40.w, height: 40.w,), - // SizedBox(width: 10.w,), - Text( - DateTool().dateToYMDHNString( - messageItemEntity.createdAt!.toString()), - style: TextStyle( - fontSize: 18.sp, - color: messageItemEntity.readAt! == 0 - ? AppColors.blackColor - : AppColors.placeholderTextColor)), - ], - ), - SizedBox(width: 20.h), - ], - ), - ), - ), - ); + child: Container( + width: 1.sw, + margin: EdgeInsets.only(left: 20.w, right: 20.w, top: 8.h, bottom: 12.h), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(height: 4.h), + Row( + children: [ + Flexible( + child: Text( + // 调用请求标题 + '远程开门请求', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 22.sp, + color: messageItemEntity.readAt! == 0 + ? AppColors.blackColor + : AppColors.placeholderTextColor), + ), + ), + ], + ), + SizedBox(height: 4.h), + Wrap( + children: [ + // if (messageItemEntity.readAt! == 0) + // Container( + // width: 10.w, + // height: 10.w, + // decoration: BoxDecoration( + // color: Colors.red, + // borderRadius: BorderRadius.circular(5.w), + // ), + // ) + // else + // Container(), + // if (messageItemEntity.readAt! == 0) + // SizedBox(width: 5.w) + // else + // Container(), + Container( + margin: EdgeInsets.only(top: 4.h), + child: Text( + DateTool().dateToHnString(messageItemEntity.createdAt!.toString()), + style: TextStyle( + fontSize: 18.sp, + color: messageItemEntity.readAt! == 0 + ? AppColors.blackColor + : AppColors.placeholderTextColor, + ), + ), + ), + Container( + width: 1, + height: 10, + margin: EdgeInsets.only(left: 5.w, right: 5.w, top: 8.h), + color: messageItemEntity.readAt! == 0 + ? AppColors.blackColor + : AppColors.placeholderTextColor, + ), + Container(transform: Matrix4.translationValues(0, -18, 0), + child: Text(' ${messageItemEntity.data!}', + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 18.sp, + color: messageItemEntity.readAt! == 0 + ? AppColors.blackColor + : AppColors.placeholderTextColor, + ), + )), + Container(child: GestureDetector( + child: Text('点击查看', style: TextStyle(fontWeight: FontWeight.w500, fontSize: 18.sp, color: AppColors.mainColor),), + ),alignment: Alignment.centerRight,) + ], + ), + // SizedBox(height: 5.h), + // Row( + // mainAxisAlignment: MainAxisAlignment.start, + // children: [ + // // Image.asset('images/mine/icon_mine_gatewaySignal_strong.png', width: 40.w, height: 40.w,), + // // SizedBox(width: 10.w,), + // Text( + // DateTool().dateToHnString(messageItemEntity + // .createdAt! + // .toString()), + // style: TextStyle( + // fontSize: 18.sp, + // color: messageItemEntity.readAt! == 0 + // ? AppColors.blackColor + // : AppColors.placeholderTextColor)), + // ], + // ), + SizedBox(width: 20.h), + ]))))), + // 显示选中状态的复选框 + if (_showCheckboxes.value) + Checkbox( + value: _selectedItems[index], + activeColor: Colors.blue, + onChanged: (val) { + _selectedItems[index] = val!; + setState(() {}); + }, + ) + ])); } } diff --git a/lib/tools/dateTool.dart b/lib/tools/dateTool.dart index 2764b3aa..84710301 100755 --- a/lib/tools/dateTool.dart +++ b/lib/tools/dateTool.dart @@ -194,6 +194,45 @@ class DateTool { return appointmentDate; } + /// 将时间戳传化为月 + String dateToMMString(String? timestamp) { + timestamp ??= '0'; + int time = int.parse(timestamp); + if (timestamp.length == 10) { + time = time * 1000; + } + final DateTime nowDate = DateTime.fromMillisecondsSinceEpoch(time); + final String appointmentDate = + formatDate(nowDate, [mm]); + return appointmentDate; + } + + /// 将时间戳传化为日 + String dateToDDString(String? timestamp) { + timestamp ??= '0'; + int time = int.parse(timestamp); + if (timestamp.length == 10) { + time = time * 1000; + } + final DateTime nowDate = DateTime.fromMillisecondsSinceEpoch(time); + final String appointmentDate = + formatDate(nowDate, [dd]); + return appointmentDate; + } + + /// 将时间戳传化为时分 + String dateToHnString(String? timestamp) { + timestamp ??= '0'; + int time = int.parse(timestamp); + if (timestamp.length == 10) { + time = time * 1000; + } + final DateTime nowDate = DateTime.fromMillisecondsSinceEpoch(time); + final String appointmentDate = + formatDate(nowDate, [HH, ':', nn]); + return appointmentDate; + } + /// 将时间戳传化为年月日 (年-月-日 时:分) String dateIntToYMDHNString(int? time) { time ??= 0;