diff --git a/lib/common/api/hard_api.dart b/lib/common/api/hard_api.dart index e55dc77..d418fa0 100644 --- a/lib/common/api/hard_api.dart +++ b/lib/common/api/hard_api.dart @@ -130,4 +130,15 @@ abstract class HardApi { if (res.data == null) return null; return ServiceChartLatitude.fromJson(res.data); } + + /// android查询今日的广播 + static Future broadcastToday( + dynamic formData, + ) async { + final res = await HttpManage() + .dio + .get("/hard/hard-broadcast/ad/today", queryParameters: formData); + if (res.data == null) return null; + return ServiceBroadcastTodayPage.fromJson(res.data); + } } diff --git a/lib/common/models/api/hard_api_models.dart b/lib/common/models/api/hard_api_models.dart index 437d028..dd081dd 100644 --- a/lib/common/models/api/hard_api_models.dart +++ b/lib/common/models/api/hard_api_models.dart @@ -378,3 +378,94 @@ class ServiceChartLatitudeItem { Map toJson() => _$ServiceChartLatitudeItemToJson(this); } + +@JsonSerializable() +class ServiceBroadcastToday { + /// 广播id + final String id; + + /// 预定用户 + final String userId; + + /// 用户名 + final String username; + + /// 用户手机号 + final String userMobile; + + /// 硬件id + final String hardId; + + /// mq主题 + final String topic; + + /// 业务类型 + final String? bizType; + + /// 关联业务编号 + final String? bizId; + + /// 预定标题 + final String title; + + /// 预定内容 + final String content; + + /// 当前广播次数 + final int? broadcastCount; + + /// 最大广播次数 + final int? broadcastMaxCount; + + /// 是否广播语音 + @JsonKey(fromJson: JsonTool.stringToBoolean, toJson: JsonTool.booleanToString) + final bool isBroadcast; + + /// 用餐时间段 + final String? hourType; + + /// 商品介绍 + String productDesc; + + /// 支付价格 + int payPrice; + + ServiceBroadcastToday({ + required this.id, + required this.userId, + required this.username, + required this.userMobile, + required this.hardId, + required this.topic, + this.bizType, + this.bizId, + required this.title, + required this.content, + this.broadcastCount, + this.broadcastMaxCount, + required this.isBroadcast, + this.hourType, + required this.productDesc, + required this.payPrice, + }); + + factory ServiceBroadcastToday.fromJson(Map json) => + _$ServiceBroadcastTodayFromJson( + json, + ); + + Map toJson() => _$ServiceBroadcastTodayToJson(this); +} + +@JsonSerializable() +class ServiceBroadcastTodayPage extends ServicePageBase { + List? records; + ServiceBroadcastTodayPage({ + this.records, + }); + factory ServiceBroadcastTodayPage.fromJson(Map json) => + _$ServiceBroadcastTodayPageFromJson( + json, + ); + Map toJson() => _$ServiceBroadcastTodayPageToJson(this); +} diff --git a/lib/common/models/api/hard_api_models.g.dart b/lib/common/models/api/hard_api_models.g.dart index e756056..0757f1f 100644 --- a/lib/common/models/api/hard_api_models.g.dart +++ b/lib/common/models/api/hard_api_models.g.dart @@ -243,3 +243,68 @@ Map _$ServiceChartLatitudeItemToJson( 'sum': instance.sum, 'count': instance.count, }; + +ServiceBroadcastToday _$ServiceBroadcastTodayFromJson( + Map json) => + ServiceBroadcastToday( + id: json['id'] as String, + userId: json['userId'] as String, + username: json['username'] as String, + userMobile: json['userMobile'] as String, + hardId: json['hardId'] as String, + topic: json['topic'] as String, + bizType: json['bizType'] as String?, + bizId: json['bizId'] as String?, + title: json['title'] as String, + content: json['content'] as String, + broadcastCount: (json['broadcastCount'] as num?)?.toInt(), + broadcastMaxCount: (json['broadcastMaxCount'] as num?)?.toInt(), + isBroadcast: JsonTool.stringToBoolean(json['isBroadcast'] as String), + hourType: json['hourType'] as String?, + productDesc: json['productDesc'] as String, + payPrice: (json['payPrice'] as num).toInt(), + ); + +Map _$ServiceBroadcastTodayToJson( + ServiceBroadcastToday instance) => + { + 'id': instance.id, + 'userId': instance.userId, + 'username': instance.username, + 'userMobile': instance.userMobile, + 'hardId': instance.hardId, + 'topic': instance.topic, + 'bizType': instance.bizType, + 'bizId': instance.bizId, + 'title': instance.title, + 'content': instance.content, + 'broadcastCount': instance.broadcastCount, + 'broadcastMaxCount': instance.broadcastMaxCount, + 'isBroadcast': JsonTool.booleanToString(instance.isBroadcast), + 'hourType': instance.hourType, + 'productDesc': instance.productDesc, + 'payPrice': instance.payPrice, + }; + +ServiceBroadcastTodayPage _$ServiceBroadcastTodayPageFromJson( + Map json) => + ServiceBroadcastTodayPage( + records: (json['records'] as List?) + ?.map( + (e) => ServiceBroadcastToday.fromJson(e as Map)) + .toList(), + ) + ..current = (json['current'] as num).toInt() + ..pages = (json['pages'] as num).toInt() + ..size = (json['size'] as num).toInt() + ..total = (json['total'] as num).toInt(); + +Map _$ServiceBroadcastTodayPageToJson( + ServiceBroadcastTodayPage instance) => + { + 'current': instance.current, + 'pages': instance.pages, + 'size': instance.size, + 'total': instance.total, + 'records': instance.records, + }; diff --git a/lib/common/models/mq/mq_models.dart b/lib/common/models/mq/mq_models.dart index dba56b9..03e8c4e 100644 --- a/lib/common/models/mq/mq_models.dart +++ b/lib/common/models/mq/mq_models.dart @@ -97,6 +97,10 @@ class MqttTakeFoodBroadcastMsg { /// 时间段类型 String hourType; + /// 是否完成订单 + @JsonKey(fromJson: JsonTool.stringToBoolean, toJson: JsonTool.booleanToString) + bool isDone; + MqttTakeFoodBroadcastMsg({ required this.topic, required this.userId, @@ -109,6 +113,7 @@ class MqttTakeFoodBroadcastMsg { required this.productDesc, required this.payPrice, required this.hourType, + required this.isDone, }); factory MqttTakeFoodBroadcastMsg.fromJson(Map json) => diff --git a/lib/common/models/mq/mq_models.g.dart b/lib/common/models/mq/mq_models.g.dart index 11816d2..f5c5174 100644 --- a/lib/common/models/mq/mq_models.g.dart +++ b/lib/common/models/mq/mq_models.g.dart @@ -61,6 +61,7 @@ MqttTakeFoodBroadcastMsg _$MqttTakeFoodBroadcastMsgFromJson( productDesc: json['productDesc'] as String, payPrice: (json['payPrice'] as num).toInt(), hourType: json['hourType'] as String, + isDone: JsonTool.stringToBoolean(json['isDone'] as String), ); Map _$MqttTakeFoodBroadcastMsgToJson( @@ -77,4 +78,5 @@ Map _$MqttTakeFoodBroadcastMsgToJson( 'productDesc': instance.productDesc, 'payPrice': instance.payPrice, 'hourType': instance.hourType, + 'isDone': JsonTool.booleanToString(instance.isDone), }; diff --git a/lib/common/services/database/dao/broadcast_dao.dart b/lib/common/services/database/dao/broadcast_dao.dart index 1ef8fc1..bacf850 100644 --- a/lib/common/services/database/dao/broadcast_dao.dart +++ b/lib/common/services/database/dao/broadcast_dao.dart @@ -1,3 +1,4 @@ +import 'package:common_utils/common_utils.dart'; import 'package:floor/floor.dart'; import 'package:get/get.dart'; @@ -18,12 +19,36 @@ abstract class BroadcastDao { return await database.rawUpdate(sql, []); } + Future delByServiceCodes( + List codes, + ) async { + if (ObjectUtil.isEmptyList(codes)) return 0; + final appC = Get.find(); + final database = appC.dataBase.database; + final placeholders = List.generate(codes.length, (index) => '?').join(', '); + final sql = ''' + DELETE FROM broadcast + WHERE + serviceCode IN ($placeholders) + AND strftime('%Y-%m-%d', saleDate) = strftime('%Y-%m-%d', 'now', 'localtime') + '''; + return await database.rawDelete(sql, [...codes]); + } + @insert Future save(BroadcastEntity entity); @insert Future batchSave(List entitys); + @Query(""" + DELETE FROM broadcast + WHERE + isDone = 1 + AND (:serviceCode = '-1' OR serviceCode = :serviceCode) + """) + Future del(String serviceCode); + @update Future edit(BroadcastEntity entity); diff --git a/lib/common/services/database/database.g.dart b/lib/common/services/database/database.g.dart index 0972d3d..a922132 100644 --- a/lib/common/services/database/database.g.dart +++ b/lib/common/services/database/database.g.dart @@ -274,6 +274,13 @@ class _$BroadcastDao extends BroadcastDao { final UpdateAdapter _broadcastEntityUpdateAdapter; + @override + Future del(String serviceCode) async { + await _queryAdapter.queryNoReturn( + 'DELETE FROM broadcast WHERE isDone = 1 AND (?1 = \'-1\' OR serviceCode = ?1)', + arguments: [serviceCode]); + } + @override Future> getAll() async { return _queryAdapter.queryList( diff --git a/lib/common/utils/sync/sync_take_food_broadcast_tool.dart b/lib/common/utils/sync/sync_take_food_broadcast_tool.dart index bc6b43d..722f9db 100644 --- a/lib/common/utils/sync/sync_take_food_broadcast_tool.dart +++ b/lib/common/utils/sync/sync_take_food_broadcast_tool.dart @@ -11,6 +11,11 @@ abstract class SyncTakeFoodBroadcastTool { static Future addTask(MqttTakeFoodBroadcastMsg msg) async { final appC = Get.find(); final broadcastDao = appC.dataBase.getBroadcastDao; + // 完成就删除掉 + if (msg.isDone) { + await broadcastDao.del(msg.id); + return; + } final saveObj = BroadcastEntity( content: msg.content, broadcastCount: 0, @@ -72,6 +77,12 @@ abstract class SyncTakeFoodBroadcastTool { if (i < totalGroups - 1) { await Future.delayed(const Duration(seconds: 3)); } + // 更新广播次数 + for (final v in currentGroup) { + v.broadcastCount++; + await broadcastDao.edit(v); + } + // 发送mq消息 } } catch (e, stack) { logger.e("|$_tag|检查广播,广播错误,error:|$e|stack:|$stack|"); @@ -79,4 +90,62 @@ abstract class SyncTakeFoodBroadcastTool { _isBroadcast = false; } } + + /// 手动查询今天所有的广播并且更新本地数据库 + static Future queryTodayBroadcast() async { + // 检查有没有网络 + if (!AppNetworkTool.isAutoNetwork()) return; + int currentPage = 1; + final pa = {"current": currentPage, "size": 100}; + while (true) { + final isMore = await _queryTodayBroadcastGroup(pa); + if (!isMore) break; + currentPage++; + } + } + + /// 手动查询今天所有的广播并且更新本地数据库 + static Future _queryTodayBroadcastGroup(dynamic pa) async { + final serviceList = await HardApi.broadcastToday(pa); + if (serviceList == null) return false; + final result = serviceList.size == 100; + if (ObjectUtil.isEmptyList(serviceList.records)) return false; + final appC = Get.find(); + final broadcastDao = appC.dataBase.getBroadcastDao; + final serviceCodes = + serviceList.records?.map((e) => e.id.toString()).toList(); + if (ObjectUtil.isEmptyList(serviceCodes)) { + return result; + } + // 根据服务码查询本地数据库 + await broadcastDao.delByServiceCodes(serviceCodes!); + final saveList = serviceList.records! + .map((e) => _convertServiceBroadcastTodayToBroadcastEntity(e)) + .toList(); + await broadcastDao.batchSave(saveList); + return result; + } + + /// 把 ServiceBroadcastToday 转化为 BroadcastEntity + static BroadcastEntity _convertServiceBroadcastTodayToBroadcastEntity( + ServiceBroadcastToday obj, + ) { + return BroadcastEntity( + content: obj.content, + broadcastCount: 0, + broadcastMaxCount: obj.broadcastMaxCount ?? 20, + isBroadcast: true, + isDone: false, + productDesc: obj.productDesc, + serviceCode: obj.id, + userId: obj.userId, + username: obj.username, + userMobile: obj.userMobile, + payPrice: obj.payPrice, + hourType: + ProductHourType.values.fromCode(obj.hourType) ?? ProductHourType.NOON, + enable: true, + createTime: DateTime.now(), + ); + } } diff --git a/lib/pages/canteen_reserve/controller.dart b/lib/pages/canteen_reserve/controller.dart index 727b7b3..76e80fb 100644 --- a/lib/pages/canteen_reserve/controller.dart +++ b/lib/pages/canteen_reserve/controller.dart @@ -1,4 +1,3 @@ -import 'package:flutter/src/widgets/framework.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:forui/forui.dart'; import 'package:get/get.dart'; @@ -122,7 +121,8 @@ class CanteenReserveController extends GetxController { status: '广播中...', maskType: EasyLoadingMaskType.black, ); - await _getReservePage(); + // 立即执行一次广播 + SyncTakeFoodBroadcastTool.doCheckBroadcast(); EasyLoading.dismiss(); } @@ -149,4 +149,24 @@ class CanteenReserveController extends GetxController { await _getReservePage(); EasyLoading.dismiss(); } + + /// 同步所有广播 + Future syncAllBroadcast() async { + // 是否同步所有广播 + final isSure = await appMessageDialog(Get.context!, "是否同步所有广播"); + if (!isSure) return; + EasyLoading.show( + status: '同步中...', + maskType: EasyLoadingMaskType.black, + ); + try { + await SyncTakeFoodBroadcastTool.queryTodayBroadcast(); + await _getReservePage(); + EasyLoading.dismiss(); + } catch (e, stack) { + logger.e("同步广播失败error:|$e|stack:|$stack|"); + Toast.error(msg: "同步失败"); + EasyLoading.dismiss(); + } + } } diff --git a/lib/pages/canteen_reserve/view.dart b/lib/pages/canteen_reserve/view.dart index 32e6ba3..859cceb 100644 --- a/lib/pages/canteen_reserve/view.dart +++ b/lib/pages/canteen_reserve/view.dart @@ -36,8 +36,22 @@ class CanteenReservePage extends GetView { Widget _buildCondition(BuildContext context, double headerHeight) { final theme = FTheme.of(context); return [ - const Spacer(), appRadioHourTypeDialog(context, controller.hourTypeC).width(300.w), + const Spacer(), + FButton( + style: FButtonStyle.outline, + prefix: FIcon( + FAssets.icons.rotateCcw, + size: theme.typography.base.fontSize, + ), + label: Text( + '同步所有广播', + style: theme.typography.base.copyWith( + color: theme.colorScheme.primary, + ), + ), + onPress: () => controller.syncAllBroadcast(), + ), FButton( prefix: FIcon( FAssets.icons.rocket, @@ -53,7 +67,7 @@ class CanteenReservePage extends GetView { ), FButton( prefix: FIcon( - FAssets.icons.rocket, + FAssets.icons.laptopMinimalCheck, size: theme.typography.base.fontSize, ), label: Text(