feat:取餐、订餐、广播

This commit is contained in:
dzc committed 2025-04-27 17:18:26 +08:00
1 parent d5bfd91bc1
commit e5100b46b1
10 files changed
+313 -4

No files matched your search

+11
View File
@@ -130,4 +130,15 @@ abstract class HardApi {
if (res.data == null) return null;
return ServiceChartLatitude.fromJson(res.data);
}
/// android查询今日的广播
static Future<ServiceBroadcastTodayPage?> 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);
}
}
@@ -378,3 +378,94 @@ class ServiceChartLatitudeItem {
Map<String, dynamic> 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<String, dynamic> json) =>
_$ServiceBroadcastTodayFromJson(
json,
);
Map<String, dynamic> toJson() => _$ServiceBroadcastTodayToJson(this);
}
@JsonSerializable()
class ServiceBroadcastTodayPage extends ServicePageBase {
List<ServiceBroadcastToday>? records;
ServiceBroadcastTodayPage({
this.records,
});
factory ServiceBroadcastTodayPage.fromJson(Map<String, dynamic> json) =>
_$ServiceBroadcastTodayPageFromJson(
json,
);
Map<String, dynamic> toJson() => _$ServiceBroadcastTodayPageToJson(this);
}
@@ -243,3 +243,68 @@ Map<String, dynamic> _$ServiceChartLatitudeItemToJson(
'sum': instance.sum,
'count': instance.count,
};
ServiceBroadcastToday _$ServiceBroadcastTodayFromJson(
Map<String, dynamic> 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<String, dynamic> _$ServiceBroadcastTodayToJson(
ServiceBroadcastToday instance) =>
<String, dynamic>{
'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<String, dynamic> json) =>
ServiceBroadcastTodayPage(
records: (json['records'] as List<dynamic>?)
?.map(
(e) => ServiceBroadcastToday.fromJson(e as Map<String, dynamic>))
.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<String, dynamic> _$ServiceBroadcastTodayPageToJson(
ServiceBroadcastTodayPage instance) =>
<String, dynamic>{
'current': instance.current,
'pages': instance.pages,
'size': instance.size,
'total': instance.total,
'records': instance.records,
};
+5
View File
@@ -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<String, dynamic> json) =>
+2
View File
@@ -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<String, dynamic> _$MqttTakeFoodBroadcastMsgToJson(
@@ -77,4 +78,5 @@ Map<String, dynamic> _$MqttTakeFoodBroadcastMsgToJson(
'productDesc': instance.productDesc,
'payPrice': instance.payPrice,
'hourType': instance.hourType,
'isDone': JsonTool.booleanToString(instance.isDone),
};
@@ -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<int> delByServiceCodes(
List<String> codes,
) async {
if (ObjectUtil.isEmptyList(codes)) return 0;
final appC = Get.find<AppControl>();
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<void> save(BroadcastEntity entity);
@insert
Future<void> batchSave(List<BroadcastEntity> entitys);
@Query("""
DELETE FROM broadcast
WHERE
isDone = 1
AND (:serviceCode = '-1' OR serviceCode = :serviceCode)
""")
Future<void> del(String serviceCode);
@update
Future<void> edit(BroadcastEntity entity);
@@ -274,6 +274,13 @@ class _$BroadcastDao extends BroadcastDao {
final UpdateAdapter<BroadcastEntity> _broadcastEntityUpdateAdapter;
@override
Future<void> del(String serviceCode) async {
await _queryAdapter.queryNoReturn(
'DELETE FROM broadcast WHERE isDone = 1 AND (?1 = \'-1\' OR serviceCode = ?1)',
arguments: [serviceCode]);
}
@override
Future<List<BroadcastEntity>> getAll() async {
return _queryAdapter.queryList(
@@ -11,6 +11,11 @@ abstract class SyncTakeFoodBroadcastTool {
static Future<void> addTask(MqttTakeFoodBroadcastMsg msg) async {
final appC = Get.find<AppControl>();
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<void> 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<bool> _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<AppControl>();
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(),
);
}
}
+22 -2
View File
@@ -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<void> 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();
}
}
}
+16 -2
View File
@@ -36,8 +36,22 @@ class CanteenReservePage extends GetView<CanteenReserveController> {
Widget _buildCondition(BuildContext context, double headerHeight) {
final theme = FTheme.of(context);
return <Widget>[
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<CanteenReserveController> {
),
FButton(
prefix: FIcon(
FAssets.icons.rocket,
FAssets.icons.laptopMinimalCheck,
size: theme.typography.base.fontSize,
),
label: Text(