消息红点提示

This commit is contained in:
czz
2025-07-24 18:32:57 +08:00
parent 4adac4a6bf
commit cc6ef83587
4 changed files with 180 additions and 57 deletions

View File

@@ -8,6 +8,7 @@ import 'package:vbvs_app/common/color/ServiceConstant.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart'; import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/DailyLogUtils.dart'; import 'package:vbvs_app/common/util/DailyLogUtils.dart';
import 'package:vbvs_app/common/util/MyUtils.dart'; import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/common/util/requestWithLog.dart';
import 'package:vbvs_app/model/api_response.dart'; import 'package:vbvs_app/model/api_response.dart';
part 'message_controller.g.dart'; // 由json_serializable自动生成的部分 part 'message_controller.g.dart'; // 由json_serializable自动生成的部分
@@ -40,20 +41,21 @@ class MhMessageController extends GetControllerEx<MhMessageModel> {
attr = GetModel(MhMessageModel()).obs; attr = GetModel(MhMessageModel()).obs;
} }
RxList messageList = [].obs; RxList bodyMessageList = [].obs;
RxList systemMessageList = [].obs;
Future<ApiResponse> getMessageList({String? key}) async { Future<ApiResponse> getMessageList(String messageType) async {
try { try {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr); ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
String serviceAddress = ServiceConstant.service_address; String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service; String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.message_list; String serviceApi = ServiceConstant.message_list;
String messageType = "app_system"; // String messageType = "app_system";
if (model.type == 1) { // if (model.type == 1) {
messageType = "app_vsm"; // messageType = "app_vsm";
} else { // } else {
messageType = "app_system"; // messageType = "app_system";
} // }
String queryUrl = String queryUrl =
"${serviceAddress}${serviceName}${serviceApi}?type=${messageType}"; "${serviceAddress}${serviceName}${serviceApi}?type=${messageType}";
String? language = ""; String? language = "";
@@ -75,8 +77,17 @@ class MhMessageController extends GetControllerEx<MhMessageModel> {
ApiResponse.fromJson(responseData, (object) => object); ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(res, "请求成功".tr, "请求失败".tr); MyUtils.formatResponse(res, "请求成功".tr, "请求失败".tr);
if (res.code == HttpStatusCodes.ok) { if (res.code == HttpStatusCodes.ok) {
// updateAll();
// messageList.value = res.data;
if (res.code == HttpStatusCodes.ok) {
if (messageType == "app_vsm") {
bodyMessageList.assignAll(res.data ?? []);
} else if (messageType == "app_system") {
systemMessageList.assignAll(res.data ?? []);
}
}
updateAll(); updateAll();
messageList.value = res.data;
return res; return res;
} }
} else { } else {
@@ -127,14 +138,14 @@ class MhMessageController extends GetControllerEx<MhMessageModel> {
(e) => e['type'] == 'app_vsm', (e) => e['type'] == 'app_vsm',
orElse: () => null, orElse: () => null,
); );
model.body_message_read = vsmItem?['count'] ?? 0; model.body_message_read = (vsmItem?['count'] ?? 0) > 0 ? 1 : 0;
// 查找 type 为 app_system 的项 // 查找 type 为 app_system 的项
var systemItem = dataList.firstWhere( var systemItem = dataList.firstWhere(
(e) => e['type'] == 'app_system', (e) => e['type'] == 'app_system',
orElse: () => null, orElse: () => null,
); );
model.system_message_read = systemItem?['count'] ?? 0; model.system_message_read = (systemItem?['count'] ?? 0) > 0 ? 1 : 0;
updateAll(); updateAll();
return res; return res;
@@ -195,4 +206,38 @@ class MhMessageController extends GetControllerEx<MhMessageModel> {
return ApiResponse(code: -1, msg: "服务器.失败".tr); return ApiResponse(code: -1, msg: "服务器.失败".tr);
} }
} }
// 全部消息已读
// / 更新消息为已读状态
// / 如果传入 [mid],则更新指定消息;如果传入 [all] 为 true则更新该类型的所有消息
Future<void> updateMessageReadStatus(String messageType,
{String? mid, bool all = false}) async {
final serviceAddress = ServiceConstant.service_address;
final serviceName = ServiceConstant.server_service;
final serviceApi = ServiceConstant.message_read;
// 构建 query 参数
String queryUrl =
"$serviceAddress$serviceName$serviceApi?type=$messageType";
if (all) {
queryUrl += "&mid=ALL";
} else if (mid != null && mid.isNotEmpty) {
queryUrl += "&mid=$mid";
}
await requestWithLog(
logTitle: all ? '更新所有消息为已读' : '更新消息为已读',
method: MyHttpMethod.post,
queryUrl: queryUrl,
onSuccess: (res) {
if (res.code == HttpStatusCodes.ok) {
getMessageList(messageType);
}
},
onFailure: (res) {
print('失败');
},
);
}
} }

View File

@@ -1,18 +1,12 @@
import 'package:ef/ef.dart'; import 'package:ef/ef.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/FitTool.dart'; import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart'; import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/component/tool/CustomCard.dart'; import 'package:vbvs_app/component/tool/CustomCard.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/device/device_share_controller.dart'; import 'package:vbvs_app/controller/device/device_share_controller.dart';
import 'package:vbvs_app/controller/message/message_controller.dart'; import 'package:vbvs_app/controller/mh_controller/message_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart'; import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/enum/MessageStatus.dart'; import 'package:vbvs_app/enum/MessageStatus.dart';
import 'package:vbvs_app/model/api_response.dart';
import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
class MhMessageListWidget extends StatefulWidget { class MhMessageListWidget extends StatefulWidget {
final data; final data;
@@ -25,12 +19,19 @@ class MhMessageListWidget extends StatefulWidget {
class _MhMessageListWidgetState extends State<MhMessageListWidget> { class _MhMessageListWidgetState extends State<MhMessageListWidget> {
ThemeController themeController = Get.find(); ThemeController themeController = Get.find();
MessageController messageController = Get.find();
DeviceShareController deviceShareController = Get.find(); DeviceShareController deviceShareController = Get.find();
MhMessageController messageController = Get.find();
late RxMap<String, dynamic> messageInfo;
// @override
// void initState() {
// super.initState();
// messageInfo = Map<String, dynamic>.from(widget.data).obs; // 复制成 obs
// }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var messageInfo = widget.data; messageInfo = Map<String, dynamic>.from(widget.data).obs;
print(messageInfo); print(messageInfo);
return Stack( return Stack(
children: [ children: [
@@ -40,7 +41,10 @@ class _MhMessageListWidgetState extends State<MhMessageListWidget> {
borderRadius: 20.rpx, borderRadius: 20.rpx,
padding: padding:
EdgeInsetsDirectional.fromSTEB(30.rpx, 26.rpx, 30.rpx, 26.rpx), EdgeInsetsDirectional.fromSTEB(30.rpx, 26.rpx, 30.rpx, 26.rpx),
onTap: () {}, onTap: () async {
messageController.updateMessageReadStatus(messageInfo['type'],
mid: messageInfo['_id']);
},
child: Column( child: Column(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: [ children: [
@@ -103,7 +107,7 @@ class _MhMessageListWidgetState extends State<MhMessageListWidget> {
colors: [Color(0xFF84F5FF)], colors: [Color(0xFF84F5FF)],
enableAnimation: true, // 有点击缩放动画 enableAnimation: true, // 有点击缩放动画
enableGradient: false, // 不用渐变 enableGradient: false, // 不用渐变
onTap: () { onTap: () async {
// if (messageInfo['status'] == 1) { // if (messageInfo['status'] == 1) {
// showConfirmDialog( // showConfirmDialog(
// context, Container(), "是否确认接受该设备".tr, // context, Container(), "是否确认接受该设备".tr,
@@ -130,6 +134,11 @@ class _MhMessageListWidgetState extends State<MhMessageListWidget> {
// } // }
// }, onCancel: () {}); // }, onCancel: () {});
// } // }
await messageController.updateMessageReadStatus(
messageInfo['type'],
mid: messageInfo['_id']);
// await messageController.getMessageList();
Get.toNamed('/messageDetail', arguments: messageInfo); Get.toNamed('/messageDetail', arguments: messageInfo);
}, },
child: Center( child: Center(
@@ -150,6 +159,27 @@ class _MhMessageListWidgetState extends State<MhMessageListWidget> {
], ],
), ),
), ),
Obx(() {
final info = messageInfo.value;
final readTime = info['read_time'];
final shouldShowDot = readTime == null || readTime.toString().isEmpty;
return shouldShowDot
? Positioned(
top: 30.rpx,
right: 30.rpx,
child: Container(
width: 15.rpx,
height: 15.rpx,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
),
)
: SizedBox.shrink();
})
], ],
); );
} }

View File

@@ -150,7 +150,7 @@ class _MessageDetailPageState extends State<MessageDetailPage> {
.toList(), .toList(),
), ),
), ),
].divide(SizedBox(width: 20.rpx)), ].divide(SizedBox(width: 0.rpx)),
), ),
], ],
))), ))),
@@ -180,12 +180,13 @@ class _MessageDetailPageState extends State<MessageDetailPage> {
if (apiResponse.code == HttpStatusCodes.ok) { if (apiResponse.code == HttpStatusCodes.ok) {
TopSlideNotification.show(context, TopSlideNotification.show(context,
text: apiResponse.msg!, textColor: Color(0xFF00C1AA)); text: apiResponse.msg!, textColor: Color(0xFF00C1AA));
messageController.getMessageList(); messageController.getMessageList(widget.data['type']);
messageController.updateAll(); messageController.updateAll();
//todo 更新设备列表
} else { } else {
TopSlideNotification.show(context, TopSlideNotification.show(context,
text: apiResponse.msg!, textColor: Color(0XFFFF7159)); text: apiResponse.msg!, textColor: Color(0XFFFF7159));
messageController.getMessageList(); messageController.getMessageList(widget.data['type']);
messageController.updateAll(); messageController.updateAll();
} }
} }

View File

@@ -40,7 +40,7 @@ class _MessagePageState extends State<MessagePage> {
void _fetchMessageData() { void _fetchMessageData() {
String type = messageController.model.type == 1 ? "app_vsm" : "app_system"; String type = messageController.model.type == 1 ? "app_vsm" : "app_system";
messageController.updateMessageStatus(type: type); messageController.updateMessageStatus(type: type);
messageController.getMessageList().then((response) { messageController.getMessageList(type).then((response) {
if (response.code != HttpStatusCodes.ok) { if (response.code != HttpStatusCodes.ok) {
TopSlideNotification.show( TopSlideNotification.show(
// Get.context!, // Get.context!,
@@ -179,13 +179,13 @@ class _MessagePageState extends State<MessagePage> {
onPageChanged: _onPageChanged, onPageChanged: _onPageChanged,
children: [ children: [
Obx(() { Obx(() {
final list = messageController.messageList; final list = messageController.bodyMessageList;
return list.isEmpty return list.isEmpty
? const NullDataWidget() ? const NullDataWidget()
: _buildMessageListView(list); : _buildMessageListView(list);
}), }),
Obx(() { Obx(() {
final list = messageController.messageList; final list = messageController.systemMessageList;
return list.isEmpty return list.isEmpty
? const NullDataWidget() ? const NullDataWidget()
: _buildMessageListView(list); : _buildMessageListView(list);
@@ -211,7 +211,13 @@ class _MessagePageState extends State<MessagePage> {
), ),
width: double.infinity, width: double.infinity,
child: TextButton( child: TextButton(
onPressed: () {}, onPressed: () async {
// if (messageController.model.type == 1) {
// messageController.updateMessageReadStatus("app_vsm", all: true);
// } else {
// messageController.updateMessageReadStatus("app_system", all: true);
// }
},
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
@@ -264,22 +270,45 @@ class _MessagePageState extends State<MessagePage> {
height: 1.0, height: 1.0,
), ),
), ),
Obx(() { Obx(() {
return messageController.model.system_message_read == 1 if (messageController.model.system_message_read == 1) {
? Positioned( return Positioned(
top: -4, top: -4.rpx,
right: -14, right: -14.rpx,
child: Container( child: Container(
width: 8, width: 15.rpx,
height: 8, height: 15.rpx,
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: Colors.red, color: Colors.red,
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
), ),
) );
: const SizedBox.shrink(); } else {
return const SizedBox.shrink();
}
}), }),
// final allHaveReadTime =
// messageController.systemMessageList.any(
// (item) => !item.containsKey('read_time'),
// );
// return allHaveReadTime
// ? Positioned(
// top: -4,
// right: -14,
// child: Container(
// width: 15.rpx,
// height: 15.rpx,
// decoration: const BoxDecoration(
// color: Colors.red,
// shape: BoxShape.circle,
// ),
// ),
// )
// : const SizedBox.shrink();
], ],
), ),
); );
@@ -313,21 +342,39 @@ class _MessagePageState extends State<MessagePage> {
height: 1.0, height: 1.0,
), ),
), ),
// Obx(() {
// return messageController.model.body_message_read == 1
// ? Positioned(
// top: -4,
// right: -14,
// child: Container(
// width: 15.rpx,
// height: 15.rpx,
// decoration: const BoxDecoration(
// color: Colors.red,
// shape: BoxShape.circle,
// ),
// ),
// )
// : const SizedBox.shrink();
// }),
Obx(() { Obx(() {
return messageController.model.body_message_read == 1 if (messageController.model.body_message_read == 1) {
? Positioned( return Positioned(
top: -4, top: -4.rpx,
right: -14, right: -14.rpx,
child: Container( child: Container(
width: 8, width: 15.rpx,
height: 8, height: 15.rpx,
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: Colors.red, color: Colors.red,
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
), ),
) );
: const SizedBox.shrink(); } else {
return const SizedBox.shrink();
}
}), }),
], ],
), ),