feat:消费机更新
feat:人员调用钱包部门不调动的bug
This commit is contained in:
1 parent
842402e364
commit
60d9380a65
144 files changed
+27832
-1666
No files matched your search
@@ -1,13 +1,24 @@
|
||||
import 'package:dio/dio.dart' as dio;
|
||||
|
||||
import 'package:pj_supermarket_cloud/common/index.dart';
|
||||
|
||||
/// 终端 App 配置与版本接口入口,统一复用 HttpManage 的鉴权、租户和错误处理。
|
||||
abstract class AppApi {
|
||||
/// 获取所有版本列表
|
||||
///
|
||||
/// 分页获取匹配 App 编码和平台的已发布版本。
|
||||
///
|
||||
/// [pa] 包含 appUniqueCode、platform、current 和 size;[silent] 为 true 时后台任务
|
||||
/// 只记录异常,不弹业务 Toast。
|
||||
static Future<ServiceAppVersionPage?> openCardList(
|
||||
dynamic pa,
|
||||
) async {
|
||||
dynamic pa, {
|
||||
bool silent = false,
|
||||
}) async {
|
||||
final res = await HttpManage().dio.get(
|
||||
"/integrated/app-version/ad/page",
|
||||
queryParameters: pa,
|
||||
options: dio.Options(
|
||||
extra: {if (silent) HttpManage.silentRequestKey: true},
|
||||
),
|
||||
);
|
||||
if (res.data == null) return null;
|
||||
return ServiceAppVersionPage.fromJson(res.data);
|
||||
|
||||
@@ -1,6 +1,88 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dio/dio.dart' as dio;
|
||||
|
||||
import 'package:pj_supermarket_cloud/common/index.dart';
|
||||
|
||||
abstract class HardApi {
|
||||
/// 按终端订单号或服务端订单 ID 对账识别证据状态;后台任务失败不弹业务 Toast。
|
||||
static Future<ServiceOrderEvidenceResolve?> resolveOrderEvidence({
|
||||
required String hardId,
|
||||
String? androidOrderCode,
|
||||
String? orderId,
|
||||
}) async {
|
||||
final res = await HttpManage().dio.get(
|
||||
'/hard/hard-order-evidence/ad/resolve',
|
||||
queryParameters: {
|
||||
if (androidOrderCode != null) 'androidOrderCode': androidOrderCode,
|
||||
if (orderId != null) 'orderId': orderId,
|
||||
},
|
||||
options: dio.Options(
|
||||
headers: {'DEVICE-ID': hardId},
|
||||
extra: {HttpManage.silentRequestKey: true},
|
||||
),
|
||||
);
|
||||
if (res.data == null) return null;
|
||||
return ServiceOrderEvidenceResolve.fromJson(res.data);
|
||||
}
|
||||
|
||||
/// 提交识别元数据、触发参考图复制或报告本地图片永久缺失。
|
||||
static Future<ServiceOrderEvidenceUploadResult?> submitOrderEvidence({
|
||||
required String hardId,
|
||||
required OrderEvidenceRequest request,
|
||||
}) async {
|
||||
final res = await HttpManage().dio.post(
|
||||
'/hard/hard-order-evidence/ad/submit',
|
||||
data: request.toJson(),
|
||||
options: dio.Options(
|
||||
headers: {'DEVICE-ID': hardId},
|
||||
extra: {HttpManage.silentRequestKey: true},
|
||||
),
|
||||
);
|
||||
if (res.data == null) return null;
|
||||
return ServiceOrderEvidenceUploadResult.fromJson(res.data);
|
||||
}
|
||||
|
||||
/// 使用统一 Dio 鉴权和租户头上传现场图片,multipart 文件名不包含终端完整路径。
|
||||
static Future<ServiceOrderEvidenceUploadResult?> uploadOrderEvidence({
|
||||
required String hardId,
|
||||
required OrderEvidenceRequest request,
|
||||
required String filePath,
|
||||
}) async {
|
||||
final file = File(filePath);
|
||||
final fileName = file.uri.pathSegments.last;
|
||||
final form = dio.FormData.fromMap({
|
||||
...request.toJson(),
|
||||
'file': await dio.MultipartFile.fromFile(filePath, filename: fileName),
|
||||
});
|
||||
final res = await HttpManage().dio.post(
|
||||
'/hard/hard-order-evidence/ad/upload',
|
||||
data: form,
|
||||
options: dio.Options(
|
||||
headers: {'DEVICE-ID': hardId},
|
||||
contentType: 'multipart/form-data',
|
||||
extra: {HttpManage.silentRequestKey: true},
|
||||
),
|
||||
);
|
||||
if (res.data == null) return null;
|
||||
return ServiceOrderEvidenceUploadResult.fromJson(res.data);
|
||||
}
|
||||
|
||||
/// 静默上报食堂、超市 Android 终端最新运行状态;后台失败不得弹出业务 Toast。
|
||||
static Future<void> terminalHeartbeat({
|
||||
required String hardId,
|
||||
required Map<String, dynamic> data,
|
||||
}) async {
|
||||
await HttpManage().dio.post(
|
||||
'/hard/hard-api/ad/terminal-heartbeat',
|
||||
data: data,
|
||||
options: dio.Options(
|
||||
headers: {'DEVICE-ID': hardId},
|
||||
extra: {HttpManage.silentRequestKey: true},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 获取硬件配置信息
|
||||
static Future<ServiceHardware?> bind(dynamic pa) async {
|
||||
final res = await HttpManage().dio.post(
|
||||
@@ -45,11 +127,92 @@ abstract class HardApi {
|
||||
return ServiceUser.fromJson(res.data);
|
||||
}
|
||||
|
||||
/// 仅按当前终端和识别身份查询本人预约,调用方不得补充商户或其他用户参数。
|
||||
static Future<ServiceReservationMenuQuery?> queryReservationMenu(
|
||||
ReservationMenuQueryRequest request,
|
||||
) async {
|
||||
final res = await HttpManage().dio.post(
|
||||
"/hard/hard-api/ad/reservation-menu/query",
|
||||
data: request.toJson(),
|
||||
);
|
||||
if (res.data == null) return null;
|
||||
return ServiceReservationMenuQuery.fromJson(res.data);
|
||||
}
|
||||
|
||||
/// 只按查询结果中的订单 ID 核销一笔预约订单。
|
||||
static Future<bool> cancelReservationOrder({
|
||||
required int orderId,
|
||||
}) async {
|
||||
final setting = await AppSettingTool.getSysSetting();
|
||||
final res = await HttpManage().dio.post(
|
||||
'/hard/hard-api/ad/reservation-menu/cancel',
|
||||
data: {'orderId': orderId},
|
||||
options: dio.Options(
|
||||
headers: {
|
||||
if (setting.serviceId != null) 'DEVICE-ID': setting.serviceId,
|
||||
},
|
||||
),
|
||||
);
|
||||
return res.data == true;
|
||||
}
|
||||
|
||||
/// 一次提交多笔同一用户预约订单,服务端在同一事务内核销并合并生成一张兑换券。
|
||||
static Future<bool> cancelReservationOrders({
|
||||
required List<int> orderIds,
|
||||
}) async {
|
||||
final setting = await AppSettingTool.getSysSetting();
|
||||
final hardId = setting.serviceId;
|
||||
if (hardId == null || hardId.isEmpty) {
|
||||
throw StateError('当前业务终端尚未绑定');
|
||||
}
|
||||
final res = await HttpManage().dio.post(
|
||||
'/hard/hard-api/ad/reservation-menu/cancel-batch',
|
||||
data: {'orderIds': orderIds},
|
||||
options: dio.Options(headers: {'DEVICE-ID': hardId}),
|
||||
);
|
||||
return res.data == true;
|
||||
}
|
||||
|
||||
/// 分页查询当前设备的预约核销记录,设备范围由服务端再次校验。
|
||||
static Future<ServiceVerificationRecordPage?> verificationRecordPage({
|
||||
required int current,
|
||||
required int size,
|
||||
required VerificationRecordQueryRequest request,
|
||||
}) async {
|
||||
final res = await HttpManage().dio.post(
|
||||
'/hard/hard-api/ad/verification-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 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(
|
||||
"/hard/hard-api/ad/create-order",
|
||||
data: formData,
|
||||
options: dio.Options(
|
||||
extra: {HttpManage.rejectBusinessErrorKey: true},
|
||||
),
|
||||
);
|
||||
if (res.data == null) return null;
|
||||
return res.data;
|
||||
@@ -61,11 +224,45 @@ abstract class HardApi {
|
||||
final res = await HttpManage().dio.post(
|
||||
"/hard/hard-api/ad/create-hard-qr-code-order",
|
||||
data: formData,
|
||||
options: dio.Options(
|
||||
extra: {HttpManage.rejectBusinessErrorKey: true},
|
||||
),
|
||||
);
|
||||
if (res.data == null) return null;
|
||||
return ServiceHardCreateHardQrCodeScanOrder.fromJson(res.data);
|
||||
}
|
||||
|
||||
/// 创建与 Hardware 业务订单绑定的支付宝、微信聚合订单码。
|
||||
static Future<ServiceHardAggregateOrderCodePay?> createAggregateOrderCodePay(
|
||||
dynamic formData) async {
|
||||
final res = await HttpManage().dio.post(
|
||||
"/hard/hard-api/ad/create-aggregate-order-code-pay",
|
||||
data: formData,
|
||||
options: dio.Options(
|
||||
extra: {HttpManage.rejectBusinessErrorKey: true},
|
||||
),
|
||||
);
|
||||
if (res.data == null) return null;
|
||||
return ServiceHardAggregateOrderCodePay.fromJson(res.data);
|
||||
}
|
||||
|
||||
/// 查询聚合支付状态;成功响应表示 Hardware 业务订单已同步完成结算。
|
||||
static Future<ServiceHardAggregateOrderCodePayStatus?>
|
||||
getAggregateOrderCodePayStatus({
|
||||
required String orderId,
|
||||
required String aggregateNo,
|
||||
}) async {
|
||||
final res = await HttpManage().dio.get(
|
||||
"/hard/hard-api/ad/aggregate-order-code-pay/status",
|
||||
queryParameters: {
|
||||
"orderId": orderId,
|
||||
"aggregateNo": aggregateNo,
|
||||
},
|
||||
);
|
||||
if (res.data == null) return null;
|
||||
return ServiceHardAggregateOrderCodePayStatus.fromJson(res.data);
|
||||
}
|
||||
|
||||
/// 根据订单id,获取订单详情
|
||||
static Future<ServiceHardOrder?> getOrder(dynamic formData) async {
|
||||
final res = await HttpManage().dio.get(
|
||||
@@ -120,6 +317,69 @@ abstract class HardApi {
|
||||
return ServiceGenerateInvoice.fromJson(res.data);
|
||||
}
|
||||
|
||||
/// 业务终端按 DEVICE-ID 创建打印任务,目标打印机只由服务端绑定关系决定。
|
||||
static Future<bool> createPrinterTask({
|
||||
required String orderId,
|
||||
String printType = '1',
|
||||
}) async {
|
||||
final setting = await AppSettingTool.getSysSetting();
|
||||
final hardId = setting.serviceId;
|
||||
if (hardId == null || hardId.isEmpty) throw StateError('当前业务终端尚未绑定');
|
||||
final res = await HttpManage().dio.post(
|
||||
'/hard/hard-api/ad/printer/task',
|
||||
data: {
|
||||
'orderId': int.parse(orderId),
|
||||
'printType': printType,
|
||||
},
|
||||
options: dio.Options(headers: {'DEVICE-ID': hardId}),
|
||||
);
|
||||
return res.data != null;
|
||||
}
|
||||
|
||||
/// 在线查询当前业务终端为指定订单生成的打印凭证,不读取终端本地打印记录。
|
||||
static Future<List<ServicePrintRecord>> getPrinterRecords({
|
||||
required String orderId,
|
||||
}) async {
|
||||
final setting = await AppSettingTool.getSysSetting();
|
||||
final hardId = setting.serviceId;
|
||||
if (hardId == null || hardId.isEmpty) throw StateError('当前业务终端尚未绑定');
|
||||
final res = await HttpManage().dio.get(
|
||||
'/hard/hard-api/ad/printer/records',
|
||||
queryParameters: {'orderId': int.parse(orderId)},
|
||||
options: dio.Options(headers: {'DEVICE-ID': hardId}),
|
||||
);
|
||||
if (res.data == null) return const [];
|
||||
if (res.data is! List) throw const FormatException('打印凭证记录格式错误');
|
||||
return (res.data as List)
|
||||
.map((item) => ServicePrintRecord.fromJson(
|
||||
Map<String, dynamic>.from(item as Map),
|
||||
))
|
||||
.toList(growable: false);
|
||||
}
|
||||
|
||||
/// 提交当前业务终端已打印兑换券的人工重打原因并取得新任务。
|
||||
static Future<ServicePrintRecord?> reprintVoucher({
|
||||
required String historyId,
|
||||
required String reason,
|
||||
}) async {
|
||||
final setting = await AppSettingTool.getSysSetting();
|
||||
final hardId = setting.serviceId;
|
||||
if (hardId == null || hardId.isEmpty) throw StateError('当前业务终端尚未绑定');
|
||||
final res = await HttpManage().dio.post(
|
||||
'/hard/hard-api/ad/printer/reprint',
|
||||
data: {
|
||||
'historyId': int.parse(historyId),
|
||||
'reprintReason': reason,
|
||||
},
|
||||
options: dio.Options(headers: {'DEVICE-ID': hardId}),
|
||||
);
|
||||
if (res.data == null) return null;
|
||||
if (res.data is! Map) throw const FormatException('兑换券重打任务格式错误');
|
||||
return ServicePrintRecord.fromJson(
|
||||
Map<String, dynamic>.from(res.data as Map),
|
||||
);
|
||||
}
|
||||
|
||||
/// 打印成功
|
||||
static Future<bool> printInvoice(dynamic formData) async {
|
||||
final res = await HttpManage().dio.get(
|
||||
@@ -130,6 +390,85 @@ abstract class HardApi {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 读取当前食堂或超市终端绑定的逻辑打印机及 USB/ESC-POS 参数。
|
||||
static Future<Map<String, dynamic>?> getPrinterBinding() async {
|
||||
final setting = await AppSettingTool.getSysSetting();
|
||||
final hardId = setting.serviceId;
|
||||
if (hardId == null || hardId.isEmpty) throw StateError('当前业务终端尚未绑定设备 ID');
|
||||
final res = await HttpManage().dio.get(
|
||||
'/hard/hard-api/ad/printer/bootstrap',
|
||||
options: dio.Options(headers: {'DEVICE-ID': hardId}),
|
||||
);
|
||||
if (res.data == null) return null;
|
||||
if (res.data is! Map) throw const FormatException('打印机绑定配置格式错误');
|
||||
return Map<String, dynamic>.from(res.data as Map);
|
||||
}
|
||||
|
||||
/// 由当前业务终端把实际枚举到的 USB 打印机型号和 VID/PID 上报到绑定的 EY_PRINT 配置。
|
||||
static Future<Map<String, dynamic>> reportPrinterInfo({
|
||||
required String hardId,
|
||||
required PrinterInfoReportRequest request,
|
||||
}) async {
|
||||
final res = await HttpManage().dio.post(
|
||||
'/hard/hard-api/ad/printer/info',
|
||||
data: request.toJson(),
|
||||
options: dio.Options(headers: {'DEVICE-ID': hardId}),
|
||||
);
|
||||
if (res.data is! Map) throw const FormatException('打印机信息上报响应格式错误');
|
||||
return Map<String, dynamic>.from(res.data as Map);
|
||||
}
|
||||
|
||||
/// 拉取当前业务终端所绑定打印机的未完成任务,补偿 MQTT 离线窗口。
|
||||
static Future<List<MqttInvoiceMsg>> getPrinterTasks() async {
|
||||
final setting = await AppSettingTool.getSysSetting();
|
||||
final hardId = setting.serviceId;
|
||||
if (hardId == null || hardId.isEmpty) return const <MqttInvoiceMsg>[];
|
||||
final res = await HttpManage().dio.get(
|
||||
'/hard/hard-api/ad/printer/tasks',
|
||||
options: dio.Options(
|
||||
headers: {'DEVICE-ID': hardId},
|
||||
extra: {HttpManage.silentRequestKey: true},
|
||||
),
|
||||
);
|
||||
if (res.data is! List) return const <MqttInvoiceMsg>[];
|
||||
return (res.data as List).whereType<Map>().map((item) {
|
||||
final json = Map<String, dynamic>.from(item);
|
||||
json['historyId'] ??= json['id'];
|
||||
return MqttInvoiceMsg.fromJson(json);
|
||||
}).toList(growable: false);
|
||||
}
|
||||
|
||||
/// 由当前业务终端上报完整 USB 写入结果;请求失败由本地队列保留并在网络恢复后补报。
|
||||
static Future<bool> reportPrinterResult({
|
||||
required String taskId,
|
||||
required String orderId,
|
||||
required int retryVersion,
|
||||
required bool success,
|
||||
required int attemptCount,
|
||||
String? errorMessage,
|
||||
}) async {
|
||||
final setting = await AppSettingTool.getSysSetting();
|
||||
final hardId = setting.serviceId;
|
||||
if (hardId == null || hardId.isEmpty) throw StateError('业务终端设备 ID 缺失');
|
||||
final res = await HttpManage().dio.post(
|
||||
'/hard/hard-api/ad/printer/result',
|
||||
data: {
|
||||
'taskId': int.parse(taskId),
|
||||
'orderId': int.parse(orderId),
|
||||
'retryVersion': retryVersion,
|
||||
'success': success,
|
||||
'attemptCount': attemptCount,
|
||||
if (errorMessage != null && errorMessage.isNotEmpty)
|
||||
'errorMessage': errorMessage,
|
||||
},
|
||||
options: dio.Options(
|
||||
headers: {'DEVICE-ID': hardId},
|
||||
extra: {HttpManage.silentRequestKey: true},
|
||||
),
|
||||
);
|
||||
return res.data == true;
|
||||
}
|
||||
|
||||
/// 离线同步
|
||||
static Future<List<String>?> syncOfflineOrder(dynamic formData) async {
|
||||
final res = await HttpManage().dio.post(
|
||||
|
||||
@@ -75,6 +75,104 @@ abstract class UserApi {
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// 按固定主键上界游标读取本部门及子部门的 V3 人脸权威快照。
|
||||
static Future<ServiceFaceSyncSnapshot> getFaceSyncSnapshot(
|
||||
Map<String, dynamic> requestBody,
|
||||
) async {
|
||||
final res = await HttpManage().dio.post(
|
||||
"/admin/user-face/ad/v3/sync-snapshot",
|
||||
data: requestBody,
|
||||
);
|
||||
if (res.data is! Map) {
|
||||
throw const FormatException('服务端未返回有效的人脸快照');
|
||||
}
|
||||
return ServiceFaceSyncSnapshot.fromJson(
|
||||
Map<String, dynamic>.from(res.data as Map),
|
||||
);
|
||||
}
|
||||
|
||||
/// 由当前设备请求删除服务端部门范围内的人脸,单批最多 500 条。
|
||||
///
|
||||
/// 服务端会以 DEVICE-ID 解析真实绑定部门;业务错误必须抛给调用方,确保终端
|
||||
/// 在未得到 deleted 或 alreadyAbsent 确认前不清理本地数据。
|
||||
static Future<ServiceTerminalFaceDeleteResult> deleteTerminalFaces(
|
||||
List<String> sampleIds,
|
||||
) async {
|
||||
final setting = await AppSettingTool.getSysSetting();
|
||||
final hardId = setting.serviceId;
|
||||
if (hardId == null) throw StateError('终端尚未绑定设备');
|
||||
final res = await HttpManage().dio.post(
|
||||
'/hard/hard-api/ad/face/delete',
|
||||
data: {'sampleIds': sampleIds},
|
||||
options: dio.Options(
|
||||
headers: {'DEVICE-ID': hardId},
|
||||
extra: {HttpManage.rejectBusinessErrorKey: true},
|
||||
),
|
||||
);
|
||||
if (res.data is! Map) {
|
||||
throw const FormatException('服务端未返回有效的人脸删除结果');
|
||||
}
|
||||
return ServiceTerminalFaceDeleteResult.fromJson(
|
||||
Map<String, dynamic>.from(res.data as Map),
|
||||
);
|
||||
}
|
||||
|
||||
/// 由当前设备批量上报在库人脸静态图片质量,单批最多 500 条。
|
||||
///
|
||||
/// 服务端通过 DEVICE-ID 解析可信设备和部门;业务失败必须抛出,但调用方应将
|
||||
/// 质量上报与既有人脸同步、注册和识别结果隔离,网络失败不得回滚本地质量。
|
||||
static Future<ServiceFaceQualityReportResult> reportTerminalFaceQuality(
|
||||
List<ServiceFaceQualityReportItem> items,
|
||||
) async {
|
||||
if (items.isEmpty) throw ArgumentError.value(items, 'items', '质量结果不能为空');
|
||||
if (items.length > 500) {
|
||||
throw ArgumentError.value(items.length, 'items', '单批最多上报500条质量结果');
|
||||
}
|
||||
final setting = await AppSettingTool.getSysSetting();
|
||||
final hardId = setting.serviceId;
|
||||
if (hardId == null) throw StateError('终端尚未绑定设备');
|
||||
final res = await HttpManage().dio.post(
|
||||
'/hard/hard-api/ad/face/quality/report',
|
||||
data: {
|
||||
'items': items.map((item) => item.toJson()).toList(growable: false),
|
||||
},
|
||||
options: dio.Options(
|
||||
headers: {'DEVICE-ID': hardId},
|
||||
extra: {HttpManage.rejectBusinessErrorKey: true},
|
||||
),
|
||||
);
|
||||
if (res.data is! Map) {
|
||||
throw const FormatException('服务端未返回有效的人脸质量上报结果');
|
||||
}
|
||||
return ServiceFaceQualityReportResult.fromJson(
|
||||
Map<String, dynamic>.from(res.data as Map),
|
||||
);
|
||||
}
|
||||
|
||||
/// 竞争当前商户部门的人脸质量上报租约。
|
||||
///
|
||||
/// Hardware 仍会在实际上报时二次验证租约;未取得租约不是业务失败,调用方应
|
||||
/// 直接跳过本轮质量批次,避免同一单位的多台终端重复发送相同在库结果。
|
||||
static Future<ServiceFaceQualityLease>
|
||||
acquireTerminalFaceQualityLease() async {
|
||||
final setting = await AppSettingTool.getSysSetting();
|
||||
final hardId = setting.serviceId;
|
||||
if (hardId == null) throw StateError('终端尚未绑定设备');
|
||||
final res = await HttpManage().dio.post(
|
||||
'/hard/hard-api/ad/face/quality/lease',
|
||||
options: dio.Options(
|
||||
headers: {'DEVICE-ID': hardId},
|
||||
extra: {HttpManage.rejectBusinessErrorKey: true},
|
||||
),
|
||||
);
|
||||
if (res.data is! Map) {
|
||||
throw const FormatException('服务端未返回有效的人脸质量租约');
|
||||
}
|
||||
return ServiceFaceQualityLease.fromJson(
|
||||
Map<String, dynamic>.from(res.data as Map),
|
||||
);
|
||||
}
|
||||
|
||||
/// 获取租户列表
|
||||
static Future<List<ServiceTenant>?> getTenantList() async {
|
||||
final res = await HttpManage().dio.get("/admin/tenant/list");
|
||||
|
||||
Reference in new issue
Block a user