feat:机器上可以查询全部订单

This commit is contained in:
dzc committed 2026-09-07 10:33:48 +08:00
1 parent 88ff8988fb
commit a6fc25ddce
13 files changed
+956 -388

No files matched your search

+5 -1
View File
@@ -45,4 +45,8 @@ app.*.map.json
/android/app/release
# FVM Version Cache
.fvm/
.fvm/
# AI assist files
.video_agent/
.mimosa/
.v2c/
+16
View File
@@ -189,6 +189,22 @@ abstract class HardApi {
return ServiceVerificationRecordPage.fromJson(res.data);
}
/// 分页查询当前设备的交易记录;scope=MERCHANT 时按终端所属商户查询全部设备。
static Future<ServiceTerminalOrderRecordPage?> terminalOrderRecordPage({
required int current,
required int size,
required TerminalOrderRecordQueryRequest request,
}) async {
final res = await HttpManage().dio.post(
'/hard/hard-api/ad/order-record/page',
queryParameters: {'current': current, 'size': size},
data: request.toJson(),
options: dio.Options(headers: {'DEVICE-ID': '${request.hardId}'}),
);
if (res.data == null) return null;
return ServiceTerminalOrderRecordPage.fromJson(res.data);
}
/// 创建硬件订单
static Future<String?> createHardwareOrder(dynamic formData) async {
final res = await HttpManage().dio.post(
+107
View File
@@ -660,6 +660,7 @@ class VerificationRecordQueryRequest {
required this.startDate,
required this.endDate,
this.verificationType,
this.scope,
});
final int hardId;
@@ -667,12 +668,118 @@ class VerificationRecordQueryRequest {
final String endDate;
final String? verificationType;
/// 数据范围:留空仅本机,MERCHANT 按终端所属商户查询全部设备。
final String? scope;
factory VerificationRecordQueryRequest.fromJson(Map<String, dynamic> json) =>
_$VerificationRecordQueryRequestFromJson(json);
Map<String, dynamic> toJson() => _$VerificationRecordQueryRequestToJson(this);
}
/// 终端交易记录的服务端查询参数,数据范围由服务端按设备归属解析。
@JsonSerializable(includeIfNull: false)
class TerminalOrderRecordQueryRequest {
const TerminalOrderRecordQueryRequest({
required this.hardId,
required this.startDate,
required this.endDate,
this.scope,
this.orderStatusCodes,
this.hourType,
});
final int hardId;
final String startDate;
final String endDate;
/// 数据范围:留空仅本机,MERCHANT 按终端所属商户查询全部设备。
final String? scope;
/// 订单状态编码集合,留空查询全部状态。
final List<String>? orderStatusCodes;
/// 用餐时段编码,留空或 -1 不区分。
final String? hourType;
factory TerminalOrderRecordQueryRequest.fromJson(
Map<String, dynamic> json) =>
_$TerminalOrderRecordQueryRequestFromJson(json);
Map<String, dynamic> toJson() =>
_$TerminalOrderRecordQueryRequestToJson(this);
}
/// 交易记录远端行只承载列表展示字段,金额与时间口径和本地订单一致。
@JsonSerializable()
class ServiceTerminalOrderRecord {
const ServiceTerminalOrderRecord({
required this.orderId,
required this.orderNo,
required this.orderType,
required this.orderTypeName,
required this.orderStatus,
required this.orderStatusName,
required this.payType,
required this.payTypeName,
required this.username,
required this.productDesc,
required this.totalPrice,
required this.extraPrice,
required this.payPrice,
this.userDeptName,
this.hourType,
this.hardName,
this.createTime,
});
/// 后端 Long 为避免跨端精度丢失可能序列化为字符串,终端同时兼容数字返回。
@JsonKey(fromJson: JsonTool.anyToInt)
final int orderId;
final String orderNo;
final String orderType;
final String orderTypeName;
final String orderStatus;
final String orderStatusName;
final String payType;
final String payTypeName;
final String username;
final String? userDeptName;
final String productDesc;
final String? hourType;
/// 完成交易的设备名称;全部数据范围下用于区分不同机器。
final String? hardName;
/// 金额仍按整数分使用,同时兼容部分环境将数值序列化为字符串。
@JsonKey(fromJson: JsonTool.anyToInt)
final int totalPrice;
@JsonKey(fromJson: JsonTool.anyToInt)
final int extraPrice;
@JsonKey(fromJson: JsonTool.anyToInt)
final int payPrice;
final DateTime? createTime;
factory ServiceTerminalOrderRecord.fromJson(Map<String, dynamic> json) =>
_$ServiceTerminalOrderRecordFromJson(json);
Map<String, dynamic> toJson() => _$ServiceTerminalOrderRecordToJson(this);
}
@JsonSerializable()
class ServiceTerminalOrderRecordPage extends ServicePageBase {
ServiceTerminalOrderRecordPage({this.records});
final List<ServiceTerminalOrderRecord>? records;
factory ServiceTerminalOrderRecordPage.fromJson(
Map<String, dynamic> json) =>
_$ServiceTerminalOrderRecordPageFromJson(json);
@override
Map<String, dynamic> toJson() => _$ServiceTerminalOrderRecordPageToJson(this);
}
/// 核销记录只承载列表展示字段,不复用本地订单实体,避免混淆远端与本地状态。
@JsonSerializable()
class ServiceVerificationRecord {
@@ -368,6 +368,7 @@ VerificationRecordQueryRequest _$VerificationRecordQueryRequestFromJson(
startDate: json['startDate'] as String,
endDate: json['endDate'] as String,
verificationType: json['verificationType'] as String?,
scope: json['scope'] as String?,
);
Map<String, dynamic> _$VerificationRecordQueryRequestToJson(
@@ -385,9 +386,112 @@ Map<String, dynamic> _$VerificationRecordQueryRequestToJson(
}
writeNotNull('verificationType', instance.verificationType);
writeNotNull('scope', instance.scope);
return val;
}
TerminalOrderRecordQueryRequest _$TerminalOrderRecordQueryRequestFromJson(
Map<String, dynamic> json) =>
TerminalOrderRecordQueryRequest(
hardId: (json['hardId'] as num).toInt(),
startDate: json['startDate'] as String,
endDate: json['endDate'] as String,
scope: json['scope'] as String?,
orderStatusCodes: (json['orderStatusCodes'] as List<dynamic>?)
?.map((e) => e as String)
.toList(),
hourType: json['hourType'] as String?,
);
Map<String, dynamic> _$TerminalOrderRecordQueryRequestToJson(
TerminalOrderRecordQueryRequest instance) {
final val = <String, dynamic>{
'hardId': instance.hardId,
'startDate': instance.startDate,
'endDate': instance.endDate,
};
void writeNotNull(String key, dynamic value) {
if (value != null) {
val[key] = value;
}
}
writeNotNull('scope', instance.scope);
writeNotNull('orderStatusCodes', instance.orderStatusCodes);
writeNotNull('hourType', instance.hourType);
return val;
}
ServiceTerminalOrderRecord _$ServiceTerminalOrderRecordFromJson(
Map<String, dynamic> json) =>
ServiceTerminalOrderRecord(
orderId: JsonTool.anyToInt(json['orderId']),
orderNo: json['orderNo'] as String,
orderType: json['orderType'] as String,
orderTypeName: json['orderTypeName'] as String,
orderStatus: json['orderStatus'] as String,
orderStatusName: json['orderStatusName'] as String,
payType: json['payType'] as String,
payTypeName: json['payTypeName'] as String,
username: json['username'] as String,
productDesc: json['productDesc'] as String,
totalPrice: JsonTool.anyToInt(json['totalPrice']),
extraPrice: JsonTool.anyToInt(json['extraPrice']),
payPrice: JsonTool.anyToInt(json['payPrice']),
userDeptName: json['userDeptName'] as String?,
hourType: json['hourType'] as String?,
hardName: json['hardName'] as String?,
createTime: json['createTime'] == null
? null
: DateTime.parse(json['createTime'] as String),
);
Map<String, dynamic> _$ServiceTerminalOrderRecordToJson(
ServiceTerminalOrderRecord instance) =>
<String, dynamic>{
'orderId': instance.orderId,
'orderNo': instance.orderNo,
'orderType': instance.orderType,
'orderTypeName': instance.orderTypeName,
'orderStatus': instance.orderStatus,
'orderStatusName': instance.orderStatusName,
'payType': instance.payType,
'payTypeName': instance.payTypeName,
'username': instance.username,
'userDeptName': instance.userDeptName,
'productDesc': instance.productDesc,
'hourType': instance.hourType,
'hardName': instance.hardName,
'totalPrice': instance.totalPrice,
'extraPrice': instance.extraPrice,
'payPrice': instance.payPrice,
'createTime': instance.createTime?.toIso8601String(),
};
ServiceTerminalOrderRecordPage _$ServiceTerminalOrderRecordPageFromJson(
Map<String, dynamic> json) =>
ServiceTerminalOrderRecordPage(
records: (json['records'] as List<dynamic>?)
?.map((e) =>
ServiceTerminalOrderRecord.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> _$ServiceTerminalOrderRecordPageToJson(
ServiceTerminalOrderRecordPage instance) =>
<String, dynamic>{
'current': instance.current,
'pages': instance.pages,
'size': instance.size,
'total': instance.total,
'records': instance.records,
};
ServiceVerificationRecord _$ServiceVerificationRecordFromJson(
Map<String, dynamic> json) =>
ServiceVerificationRecord(
+1
View File
@@ -16,6 +16,7 @@ export './page/order_page_models.dart';
export './page/product_meal_period_models.dart';
export './page/reservation_menu_page_models.dart';
export './page/setting_page_enum_models.dart';
export './page/terminal_data_scope.dart';
export './page/verification_record_page_models.dart';
export './page/wallet_page_enum_models.dart';
@@ -0,0 +1,16 @@
/// 记录列表的数据范围。
///
/// [device] 仅查询本机数据;[merchant] 按当前终端权限(所属商户)查询全部设备数据,
/// 需要网络可用,服务端负责解析设备归属,客户端不指定商户范围。
enum TerminalDataScope {
device('本机数据'),
merchant('全部数据');
final String title;
const TerminalDataScope(this.title);
/// 服务端接口的 scope 协议值;本机范围沿用接口默认值,不额外传参。
String? get requestCode =>
this == TerminalDataScope.merchant ? 'MERCHANT' : null;
}
@@ -0,0 +1,87 @@
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
import 'package:flutter/material.dart';
import 'package:forui/forui.dart';
import 'package:pj_supermarket_cloud/common/index.dart';
/// 记录列表顶部的数据范围切换(本机数据 / 全部数据)。
///
/// 采用与状态筛选一致的胶囊语言:外层灰底承载选项,选中项以主题色填充,
/// 触控高度不小于 44,选中态同时用颜色和字重表达,避免仅靠颜色区分。
class TerminalDataScopeTabs extends StatelessWidget {
const TerminalDataScopeTabs({
super.key,
required this.scope,
required this.onChanged,
});
final TerminalDataScope scope;
final ValueChanged<TerminalDataScope> onChanged;
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(3.w),
decoration: BoxDecoration(
color: XfjDesignTokens.control,
borderRadius: BorderRadius.circular(XfjDesignTokens.controlRadius),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: TerminalDataScope.values
.map(
(item) => _ScopeTabButton(
label: item.title,
selected: scope == item,
onTap: () => onChanged(item),
),
)
.toList(),
),
);
}
}
class _ScopeTabButton extends StatelessWidget {
const _ScopeTabButton({
required this.label,
required this.selected,
required this.onTap,
});
final String label;
final bool selected;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
final theme = FTheme.of(context);
return Semantics(
button: true,
selected: selected,
label: '数据范围:$label',
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(XfjDesignTokens.controlRadius - 2),
child: AnimatedContainer(
duration: const Duration(milliseconds: 150),
curve: Curves.easeOut,
constraints: BoxConstraints(minHeight: 40.h),
padding: EdgeInsets.symmetric(horizontal: 20.w),
decoration: BoxDecoration(
color: selected ? XfjDesignTokens.primary : Colors.transparent,
borderRadius:
BorderRadius.circular(XfjDesignTokens.controlRadius - 2),
),
child: Text(
label,
style: theme.typography.base.copyWith(
color: selected ? Colors.white : const Color(0xFF344054),
fontWeight: selected ? FontWeight.w700 : FontWeight.w600,
),
).center(),
),
),
);
}
}
+1
View File
@@ -19,6 +19,7 @@ export './app/app_wallet_selector.dart';
export './app/terminal_shell.dart';
export './app/terminal_device_status.dart';
export './app/terminal_toolbar.dart';
export './app/terminal_data_scope_tabs.dart';
export './cashier/cashier_workspace.dart';
export './face/face_recognition_preview_layer.dart';
+218 -10
View File
@@ -21,6 +21,9 @@ class OrderHistoryController extends GetxController {
Rx<OrderStatus> currentStatus = OrderStatus.TOTAL.obs;
/// 列表数据范围;全部数据按终端所属商户在线查询,本机数据读本地数据库。
final scope = TerminalDataScope.device.obs;
RxList<OrderHistoryTableItem> tabList = <OrderHistoryTableItem>[].obs;
RxList<String> saleReasons = <String>[].obs;
@@ -100,6 +103,10 @@ class OrderHistoryController extends GetxController {
// 订单列表
Future<void> getOrder() async {
_collapseExpandedOrder();
if (scope.value == TerminalDataScope.merchant) {
await _getRemoteOrder();
return;
}
final appSetting = await AppSettingTool.getSysSetting();
final sysType = appSetting.sysType.name;
final orderDao = appC.dataBase.getOrderDao;
@@ -138,11 +145,160 @@ class OrderHistoryController extends GetxController {
orderList.value = list;
}
/// 展开列表订单并按需查询本地购物车;再次点击同一笔订单时收起。
/// 切换数据范围;全部数据依赖网络,离线时提示并保持本机数据。
Future<void> doScope(TerminalDataScope target) async {
if (scope.value == target) return;
if (target == TerminalDataScope.merchant && !AppNetworkTool.isAutoNetwork()) {
Toast.error(msg: '当前没有网络,无法查询全部数据');
return;
}
scope.value = target;
currentPage.value = 1;
EasyLoading.show(
status: '切换中...',
maskType: EasyLoadingMaskType.black,
);
try {
await getTotalList();
await getOrder();
} finally {
EasyLoading.dismiss();
}
}
/// 全部数据范围:按终端权限在线分页查询,服务端负责解析商户范围。
Future<void> _getRemoteOrder() async {
final appSetting = await AppSettingTool.getSysSetting();
final hardId = int.tryParse(appSetting.serviceId ?? '');
if (hardId == null) {
totalPage.value = 0;
orderList.clear();
Toast.error(msg: '设备尚未绑定,请先前往设置完成绑定');
return;
}
final orderStatusCodes = currentStatus.value == OrderStatus.TOTAL
? null
: [currentStatus.value.code];
String? hourTypeCode = hourType.value.code;
if (appSetting.sysType == SysType.SUPERMARKET) {
hourTypeCode = null;
}
try {
final response = await HardApi.terminalOrderRecordPage(
current: currentPage.value,
size: pageSize.value,
request: TerminalOrderRecordQueryRequest(
hardId: hardId,
startDate: DateUtil.formatDate(
selectDateTime[0],
format: DateFormats.y_mo_d,
),
endDate: DateUtil.formatDate(
selectDateTime[1],
format: DateFormats.y_mo_d,
),
scope: scope.value.requestCode,
orderStatusCodes: orderStatusCodes,
hourType: hourTypeCode,
),
);
// 服务端暂不支持关键词模糊查询,与核销记录一致仅过滤当前页。
final keyword = keywordC.text.trim().toLowerCase();
final records = (response?.records ?? const [])
.where((record) =>
keyword.isEmpty ||
record.orderNo.toLowerCase().contains(keyword) ||
record.username.toLowerCase().contains(keyword) ||
record.productDesc.toLowerCase().contains(keyword))
.map(_toOrderEntity)
.toList(growable: false);
totalPage.value = response?.total ?? 0;
orderList.value = records;
} catch (error, stack) {
totalPage.value = 0;
orderList.clear();
Toast.error(msg: '查询全部数据失败,请检查网络后重试');
logger.e('|交易记录|查询全部数据失败|error:$error|stack:$stack|');
}
}
/// 远端交易记录映射为本地订单实体;枚举缺码时按语义就近降级。
OrderEntity _toOrderEntity(ServiceTerminalOrderRecord record) {
final orderType = OrderType.values.firstWhere(
(item) => item.code == record.orderType,
orElse: () => OrderType.BELOW,
);
final payType = OrderPayType.values.firstWhere(
(item) => item.code == record.payType,
orElse: () => OrderPayType.WALLET_DEFAULT,
);
final status = OrderStatus.values.firstWhere(
(item) => item.code == record.orderStatus,
orElse: () => OrderStatus.PAY,
);
return OrderEntity(
uniqueCode: record.orderNo,
serviceUniqueCode: '${record.orderId}',
sysType: appSetting.sysType,
userCode: '',
username: record.username,
hourType: record.hourType,
price: record.totalPrice,
extraPrice: record.extraPrice,
payPrice: record.payPrice,
type: orderType,
status: status,
payType: payType,
productDesc: record.productDesc,
count: 0,
weight: 0,
createTime: record.createTime ?? DateTime.now(),
);
}
/// 远端购物车快照映射为本地购物车实体,供展开明细与详情抽屉复用展示。
Future<List<ShopCardEntity>> _loadRemoteShopCards(int orderId) async {
final cars = await HardApi.getCarByOrderId({'orderId': orderId}) ?? [];
return cars
.map(
(car) => ShopCardEntity(
orderId: orderId,
productServiceUniqueCode: car.productId ?? '',
productName: car.productName ?? '未知商品',
productPic: car.productPic ?? '',
productPrice: car.productPrice ?? 0,
nature: car.productNature == ProductNature.WEIGHT.code
? ProductNature.WEIGHT
: ProductNature.DEFAULT,
productNumber: car.productCount ?? 0,
productWidget: car.productWeight ?? 0,
totalPrice: car.totalPrice ?? 0,
isPriceIncreased: false,
),
)
.toList(growable: false);
}
/// 展开列表订单并按需查询购物车;再次点击同一笔订单时收起。
/// 本机订单读本地库,全部数据范围的远端订单在线取购物车快照。
Future<void> toggleExpandedOrder(OrderEntity order) async {
final id = order.id;
if (id == null) {
Toast.error(msg: '订单尚未写入本地数据库,无法查询购物车明细');
if (scope.value != TerminalDataScope.merchant) {
Toast.error(msg: '订单尚未写入本地数据库,无法查询购物车明细');
return;
}
final remoteId = int.tryParse(order.serviceUniqueCode);
if (remoteId == null) {
Toast.error(msg: '订单缺少服务端标识,无法查询购物车明细');
return;
}
if (expandedOrderId.value == remoteId) {
_collapseExpandedOrder();
return;
}
expandedOrderId.value = remoteId;
await _loadExpandedRemoteOrder(remoteId);
return;
}
if (expandedOrderId.value == id) {
@@ -153,9 +309,38 @@ class OrderHistoryController extends GetxController {
await _loadExpandedOrder(id);
}
/// 全部数据范围下从服务端加载展开订单的购物车明细。
Future<void> _loadExpandedRemoteOrder(int orderId) async {
final requestId = ++_expandedDetailRequestId;
expandedDetailStatus.value = OrderRecordDetailLoadStatus.loading;
expandedDetailError.value = '';
expandedShopCardList.clear();
try {
final items = await _loadRemoteShopCards(orderId);
if (requestId != _expandedDetailRequestId ||
expandedOrderId.value != orderId) {
return;
}
expandedShopCardList.assignAll(items);
expandedDetailStatus.value = OrderRecordDetailLoadStatus.success;
} catch (error, stack) {
if (requestId != _expandedDetailRequestId ||
expandedOrderId.value != orderId) {
return;
}
expandedDetailError.value = '服务端购物车读取失败,请检查网络后重试';
expandedDetailStatus.value = OrderRecordDetailLoadStatus.failure;
logger.e('|交易记录|展开远端购物车失败|orderId:$orderId|error:$error|stack:$stack|');
}
}
Future<void> retryExpandedOrder() async {
final id = expandedOrderId.value;
if (id == null) return;
if (scope.value == TerminalDataScope.merchant) {
await _loadExpandedRemoteOrder(id);
return;
}
await _loadExpandedOrder(id);
}
@@ -257,7 +442,10 @@ class OrderHistoryController extends GetxController {
}
Future<void> getTotalList() async {
final total = await _getTotal();
// 全部数据范围没有本机统计口径,状态页签不展示数量。
final total = scope.value == TerminalDataScope.merchant
? <String, dynamic>{}
: await _getTotal();
List<OrderHistoryTableItem> tabs = OrderStatus.visibleList()
.map((v) => OrderHistoryTableItem(status: v))
.toList();
@@ -360,10 +548,12 @@ class OrderHistoryController extends GetxController {
};
final data = await HardApi.timeLimitRefund(pa);
if (!data) throw Error();
// 修改本地订单为退款
// 修改本地订单为退款;远端订单无本地记录,仅刷新列表
v.status = OrderStatus.REFUND;
final orderDao = appC.dataBase.getOrderDao;
await orderDao.edit(v);
if (v.id != null) {
final orderDao = appC.dataBase.getOrderDao;
await orderDao.edit(v);
}
await getTotalList();
await getOrder();
TtsManage.speak("退款成功总金额$price元");
@@ -378,13 +568,31 @@ class OrderHistoryController extends GetxController {
);
}
/// 打开订单详情抽屉,并从本地数据库加载商品明细。
/// 打开订单详情抽屉;本机订单读本地库,远端订单在线取购物车快照。
Future<void> doDetail(OrderEntity v) async {
selectedOrder.value = v;
final id = v.id;
selectedShopCardList.value = id == null
? <ShopCardEntity>[]
: await appC.dataBase.getShopCardDao.findByOrderId(id);
if (id != null) {
selectedShopCardList.value =
await appC.dataBase.getShopCardDao.findByOrderId(id);
return;
}
if (scope.value != TerminalDataScope.merchant) {
selectedShopCardList.value = <ShopCardEntity>[];
return;
}
final remoteId = int.tryParse(v.serviceUniqueCode);
if (remoteId == null) {
selectedShopCardList.value = <ShopCardEntity>[];
return;
}
try {
selectedShopCardList.value = await _loadRemoteShopCards(remoteId);
} catch (error, stack) {
selectedShopCardList.value = <ShopCardEntity>[];
logger.e('|交易记录|远端详情购物车失败|orderId:$remoteId|error:$error|stack:$stack|');
Toast.error(msg: '服务端购物车读取失败,请检查网络后重试');
}
}
void closeDetail() {
+30 -14
View File
@@ -83,6 +83,13 @@ class OrderHistoryPage extends GetView<OrderHistoryController> {
SizedBox(height: 16.h),
Row(
children: [
Obx(
() => TerminalDataScopeTabs(
scope: controller.scope.value,
onChanged: controller.doScope,
),
),
SizedBox(width: 12.w),
Obx(
() => Row(
children: controller.tabList
@@ -90,6 +97,8 @@ class OrderHistoryPage extends GetView<OrderHistoryController> {
(tab) => _StatusFilterButton(
label: tab.status.title,
count: tab.total,
showCount: controller.scope.value ==
TerminalDataScope.device,
selected:
controller.currentStatus.value == tab.status,
onTap: () => controller.doTab(tab.status),
@@ -489,6 +498,7 @@ class _StatusFilterButton extends StatelessWidget {
required this.count,
required this.selected,
required this.onTap,
this.showCount = true,
});
final String label;
@@ -496,6 +506,9 @@ class _StatusFilterButton extends StatelessWidget {
final bool selected;
final VoidCallback onTap;
/// 全部数据范围没有本机统计口径,隐藏数量角标。
final bool showCount;
@override
Widget build(BuildContext context) {
final theme = FTheme.of(context);
@@ -518,22 +531,25 @@ class _StatusFilterButton extends StatelessWidget {
fontWeight: FontWeight.w700,
),
),
SizedBox(width: 8.w),
Container(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h),
decoration: BoxDecoration(
color: selected
? Colors.white.withValues(alpha: 0.2)
: Colors.white,
borderRadius: BorderRadius.circular(999),
),
child: Text(
'$count',
style: theme.typography.sm.copyWith(
color: selected ? Colors.white : XfjDesignTokens.muted,
if (showCount) ...[
SizedBox(width: 8.w),
Container(
padding:
EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h),
decoration: BoxDecoration(
color: selected
? Colors.white.withValues(alpha: 0.2)
: Colors.white,
borderRadius: BorderRadius.circular(999),
),
child: Text(
'$count',
style: theme.typography.sm.copyWith(
color: selected ? Colors.white : XfjDesignTokens.muted,
),
),
),
),
],
],
),
),
@@ -11,6 +11,10 @@ class VerificationRecordsController extends GetxController {
final status = VerificationRecordLoadStatus.loading.obs;
final records = <ServiceVerificationRecord>[].obs;
/// 列表数据范围;本机数据仅当前设备,全部数据按终端所属商户在线查询。
final scope = TerminalDataScope.device.obs;
final selectDateTime = <DateTime>[
DateTime.now(),
DateTime.now(),
@@ -135,6 +139,7 @@ class VerificationRecordsController extends GetxController {
format: DateFormats.y_mo_d,
),
verificationType: verificationRecordReservationType,
scope: scope.value.requestCode,
),
);
if (response == null) throw StateError('服务端未返回核销记录');
@@ -153,6 +158,18 @@ class VerificationRecordsController extends GetxController {
}
}
/// 切换数据范围;全部数据依赖网络,离线时提示并保持本机数据。
Future<void> changeScope(TerminalDataScope target) async {
if (scope.value == target) return;
if (target == TerminalDataScope.merchant &&
!AppNetworkTool.isAutoNetwork()) {
Toast.error(msg: '当前没有网络,无法查询全部数据');
return;
}
scope.value = target;
await loadRecords(resetPage: true);
}
Future<void> changeDateRange(List<DateTime>? dates) async {
if (dates == null || dates.length < 2) return;
selectDateTime.assignAll(dates.take(2));
@@ -100,12 +100,19 @@ class VerificationRecordsPage extends GetView<VerificationRecordsController> {
),
),
SizedBox(width: 10.w),
Text(
'仅显示当前设备已完成的预约核销订单',
style: theme.typography.sm.copyWith(
color: XfjDesignTokens.muted,
),
),
Obx(() => Text(
controller.scope.value == TerminalDataScope.device
? '仅显示当前设备已完成的预约核销订单'
: '按当前终端权限显示全部设备的预约核销订单',
style: theme.typography.sm.copyWith(
color: XfjDesignTokens.muted,
),
)),
SizedBox(width: 10.w),
Obx(() => TerminalDataScopeTabs(
scope: controller.scope.value,
onChanged: controller.changeScope,
)),
SizedBox(width: 10.w),
Obx(
() => Text(
+341 -357
View File
File diff suppressed because it is too large. Load diff