消息中心
This commit is contained in:
106
ln_jq_app/lib/pages/c_page/message/controller.dart
Normal file
106
ln_jq_app/lib/pages/c_page/message/controller.dart
Normal file
@@ -0,0 +1,106 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:getx_scaffold/getx_scaffold.dart';
|
||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||
import 'model.dart';
|
||||
|
||||
class MessageController extends GetxController {
|
||||
final RefreshController refreshController = RefreshController(initialRefresh: false);
|
||||
final RxList<MessageModel> messageList = <MessageModel>[].obs;
|
||||
int _pageNum = 1;
|
||||
final int _pageSize = 10;
|
||||
|
||||
// 模拟所有已读状态,实际应根据接口判断
|
||||
final RxBool allRead = false.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
_loadData(isRefresh: true);
|
||||
}
|
||||
|
||||
Future<void> _loadData({bool isRefresh = false}) async {
|
||||
if (isRefresh) {
|
||||
_pageNum = 1;
|
||||
} else {
|
||||
_pageNum++;
|
||||
}
|
||||
|
||||
try {
|
||||
// 模拟请求延迟
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
// 模拟数据 (请替换为实际接口请求)
|
||||
// var response = await HttpService.to.post('message/list', data: {'pageNum': _pageNum, 'pageSize': _pageSize});
|
||||
|
||||
List<MessageModel> newData = List.generate(10, (index) {
|
||||
int id = (_pageNum - 1) * _pageSize + index;
|
||||
return MessageModel(
|
||||
id: id.toString(),
|
||||
title: '加氢预约失败通知',
|
||||
content: '1月6日14时30分-1月6日15时30分,北京朝阳加氢站加氢预约失败。原因:设备维护',
|
||||
createTime: '刚刚',
|
||||
isRead: index % 3 == 0 ? 1 : 0,
|
||||
);
|
||||
});
|
||||
|
||||
if (isRefresh) {
|
||||
messageList.assignAll(newData);
|
||||
refreshController.refreshCompleted();
|
||||
} else {
|
||||
if (newData.isEmpty) {
|
||||
refreshController.loadNoData();
|
||||
} else {
|
||||
messageList.addAll(newData);
|
||||
refreshController.loadComplete();
|
||||
}
|
||||
}
|
||||
|
||||
_checkAllRead();
|
||||
|
||||
} catch (e) {
|
||||
if (isRefresh) {
|
||||
refreshController.refreshFailed();
|
||||
} else {
|
||||
refreshController.loadFailed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onRefresh() => _loadData(isRefresh: true);
|
||||
void onLoading() => _loadData(isRefresh: false);
|
||||
|
||||
// 标记全部已读
|
||||
void markAllRead() async {
|
||||
showLoading('正在标记...');
|
||||
try {
|
||||
// await HttpService.to.post('message/readAll');
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
for (var msg in messageList) {
|
||||
msg.isRead = 1;
|
||||
}
|
||||
messageList.refresh();
|
||||
allRead.value = true;
|
||||
|
||||
dismissLoading();
|
||||
showSuccessToast('全部已读');
|
||||
} catch (e) {
|
||||
dismissLoading();
|
||||
showErrorToast('操作失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 标记单条已读(弹窗显示时调用)
|
||||
void markRead(MessageModel message) async {
|
||||
if (message.isRead == 1) return;
|
||||
|
||||
// await HttpService.to.post('message/read', data: {'id': message.id});
|
||||
message.isRead = 1;
|
||||
messageList.refresh();
|
||||
_checkAllRead();
|
||||
}
|
||||
|
||||
void _checkAllRead() {
|
||||
allRead.value = messageList.every((msg) => msg.isRead == 1);
|
||||
}
|
||||
}
|
||||
25
ln_jq_app/lib/pages/c_page/message/model.dart
Normal file
25
ln_jq_app/lib/pages/c_page/message/model.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
class MessageModel {
|
||||
final String id;
|
||||
final String title;
|
||||
final String content;
|
||||
final String createTime;
|
||||
int isRead; // 0: 未读, 1: 已读
|
||||
|
||||
MessageModel({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.content,
|
||||
required this.createTime,
|
||||
required this.isRead,
|
||||
});
|
||||
|
||||
factory MessageModel.fromJson(Map<String, dynamic> json) {
|
||||
return MessageModel(
|
||||
id: json['id']?.toString() ?? '',
|
||||
title: json['title']?.toString() ?? '消息通知',
|
||||
content: json['content']?.toString() ?? '',
|
||||
createTime: json['createTime']?.toString() ?? '',
|
||||
isRead: json['isRead'] as int? ?? 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
150
ln_jq_app/lib/pages/c_page/message/view.dart
Normal file
150
ln_jq_app/lib/pages/c_page/message/view.dart
Normal file
@@ -0,0 +1,150 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||
import 'controller.dart';
|
||||
import 'model.dart';
|
||||
|
||||
class MessagePage extends GetView<MessageController> {
|
||||
const MessagePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Get.put(MessageController());
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF5F5F5),
|
||||
appBar: AppBar(title: const Text('消息通知'), centerTitle: true),
|
||||
body: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Obx(() => SmartRefresher(
|
||||
controller: controller.refreshController,
|
||||
enablePullUp: true,
|
||||
onRefresh: controller.onRefresh,
|
||||
onLoading: controller.onLoading,
|
||||
child: ListView.separated(
|
||||
padding: const EdgeInsets.all(12),
|
||||
itemCount: controller.messageList.length,
|
||||
separatorBuilder: (_, __) => const SizedBox(height: 12),
|
||||
itemBuilder: (context, index) {
|
||||
return _buildMessageItem(context, controller.messageList[index]);
|
||||
},
|
||||
),
|
||||
)),
|
||||
),
|
||||
Obx(() => !controller.allRead.value
|
||||
? Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
color: Colors.white,
|
||||
child: ElevatedButton(
|
||||
onPressed: controller.markAllRead,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue,
|
||||
minimumSize: const Size(double.infinity, 44),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
),
|
||||
child: const Text('全部标为已读', style: TextStyle(fontSize: 16, color: Colors.white)),
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink()),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMessageItem(BuildContext context, MessageModel item) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
controller.markRead(item);
|
||||
_showMessageDialog(context, item);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 6, right: 12),
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: BoxDecoration(
|
||||
color: item.isRead == 1 ? Colors.grey[300] : const Color(0xFFFAAD14),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
item.title,
|
||||
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black87),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
item.content,
|
||||
style: TextStyle(fontSize: 14, color: Colors.grey[600]),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
item.createTime,
|
||||
style: TextStyle(fontSize: 12, color: Colors.grey[400]),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showMessageDialog(BuildContext context, MessageModel item) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
builder: (context) {
|
||||
return Dialog(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
item.title,
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
item.content,
|
||||
style: const TextStyle(fontSize: 15, height: 1.5, color: Colors.black87),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: OutlinedButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
style: OutlinedButton.styleFrom(
|
||||
side: const BorderSide(color: Colors.blue),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
|
||||
),
|
||||
child: const Text('确认', style: TextStyle(color: Colors.blue)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import 'package:get/get.dart';
|
||||
import 'package:getx_scaffold/common/index.dart';
|
||||
import 'package:getx_scaffold/common/widgets/index.dart';
|
||||
import 'package:ln_jq_app/common/styles/theme.dart';
|
||||
import 'package:ln_jq_app/pages/c_page/message/view.dart';
|
||||
import 'package:ln_jq_app/storage_service.dart';
|
||||
import 'controller.dart';
|
||||
|
||||
@@ -82,7 +83,8 @@ class MinePage extends GetView<MineController> {
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
// TODO: 跳转
|
||||
// 跳转消息中心
|
||||
Get.to(() => const MessagePage());
|
||||
},
|
||||
// 这里的 style 是为了模拟你图片里的灰色圆形背景
|
||||
style: IconButton.styleFrom(
|
||||
|
||||
@@ -933,6 +933,14 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "6.0.3"
|
||||
pull_to_refresh:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: pull_to_refresh
|
||||
sha256: bbadd5a931837b57739cf08736bea63167e284e71fb23b218c8c9a6e042aad12
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
rational:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -51,6 +51,9 @@ dependencies:
|
||||
flutter_inappwebview: ^6.1.5 # WebView插件
|
||||
geolocator: ^14.0.2 # 获取精确定位
|
||||
aliyun_push_flutter: ^1.3.6
|
||||
pull_to_refresh: ^2.0.0
|
||||
|
||||
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Reference in New Issue
Block a user