Files
biz_xfj_cloud/lib/pages/terminal/card_active/controller.dart
T
2026-08-06 20:55:09 +08:00

374 lines
11 KiB
Dart

import 'package:common_utils/common_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
import 'package:pj_supermarket_cloud/common/index.dart';
class CardActiveController extends GetxController {
final appC = Get.find<AppControl>();
SerialCardManage get serialCardManage => appC.serialCardManage;
// table
RxInt currentPage = 1.obs;
RxInt totalPage = 0.obs;
RxInt pageSize = 10.obs;
RxList<ServiceOpenCard> tableList = <ServiceOpenCard>[].obs;
RxBool isLoading = false.obs;
RxString errorMessage = ''.obs;
Rx<ServiceOpenCard?> detail = Rx(null);
RxBool readLoading = false.obs;
final Rx<SerialMifareScanProgress?> scanProgress = Rx(null);
// 写卡
RxBool writeLoading = false.obs;
// 卡号
final carNumberC = TextEditingController();
_initData() {
update(["card_active"]);
}
@override
void onInit() {
super.onInit();
getTableList();
}
@override
void onReady() {
super.onReady();
_initData();
}
@override
void onClose() {
super.onClose();
carNumberC.dispose();
}
Future<void> doPage({int? page}) async {
if (page != null) currentPage.value = page;
// 收起键盘
FocusManager.instance.primaryFocus?.unfocus();
getTableList();
}
Future<void> doReset() async {
currentPage.value = 1;
carNumberC.clear();
// 收起键盘
FocusManager.instance.primaryFocus?.unfocus();
await getTableList();
}
Future<void> getTableList() async {
isLoading.value = true;
errorMessage.value = '';
EasyLoading.show(
status: '查询中...',
maskType: EasyLoadingMaskType.black,
);
try {
final pa = {
"current": currentPage.value,
"size": pageSize.value,
"deptId": "",
"walletTypeId": "",
"cardNumber": carNumberC.text,
};
final data = await WalletApi.openCardList(pa);
if (data == null) {
tableList.clear();
totalPage.value = 0;
return;
}
totalPage.value = data.total;
final records = data.records;
if (records != null) {
tableList.value = records;
} else {
tableList.clear();
}
} catch (e, stack) {
errorMessage.value = '饭卡数据加载失败,请检查网络后重试';
logger.e('饭卡列表查询失败error:|$e|stack:|$stack|');
} finally {
isLoading.value = false;
EasyLoading.dismiss();
}
}
// 写卡
void doWriteCard(ServiceOpenCard v) async {
if (v.isActiveHardware == true) {
Toast.error(msg: "该卡已经激活,无需重复激活");
return;
}
if (ObjectUtil.isEmpty(v.cardNumber)) {
Toast.error(msg: "没有设置卡号");
return;
}
try {
await serialCardManage.connect();
if (!serialCardManage.isConnect) {
Toast.error(msg: "连接读卡器失败");
return;
}
writeLoading.value = true;
detail.value = null;
cardDialog(
title: "写卡",
loading: writeLoading,
detail: detail,
doSubmit: _closeStatus,
);
serialCardManage.callback = (type, status, res) async {
if (type != SerialCardCmdEnum.write) return;
switch (status) {
case SerialCardResStatus.success:
if (ObjectUtil.isNotEmpty(v.id)) {
await _getOpenCardSuccess(v.id!);
getTableList();
}
detail.value = v;
_closeStatus();
break;
case SerialCardResStatus.warning:
break;
case SerialCardResStatus.error:
final message = res is String && res.trim().isNotEmpty
? res.trim()
: "写卡失败,请重试";
TtsManage.speak("写卡失败");
Toast.error(msg: message);
_closeStatus();
break;
}
};
TtsManage.speak("请在合适区域放置饭卡");
serialCardManage.sendWrite(v.cardNumber!);
} catch (e, stack) {
_closeStatus();
logger.d("写卡失败error:|$e|stack:|$stack|");
Toast.error(msg: "写入失败,请重试");
}
}
// 读卡
void doReadCard() async {
try {
final config = await AppSettingTool.getSerialCardConfig();
await serialCardManage.connect();
if (!serialCardManage.isConnect) {
Toast.error(msg: "连接读卡器失败");
return;
}
readLoading.value = true;
detail.value = null;
scanProgress.value = null;
cardDialog(
title: "读卡",
loading: readLoading,
detail: detail,
scanProgress: scanProgress,
onScanMifareBlocks:
config.showMifareScanButton ? doScanMifareBlocks : null,
doSubmit: _closeStatus,
);
serialCardManage.callback = (type, status, res) async {
if (type != SerialCardCmdEnum.read) return;
switch (status) {
case SerialCardResStatus.success:
await _handleReadCardSuccess(res);
break;
case SerialCardResStatus.warning:
break;
case SerialCardResStatus.error:
final message = res is String && res.trim().isNotEmpty
? res.trim()
: "读卡失败,请重试";
TtsManage.speak("读卡失败");
Toast.error(msg: message);
_closeStatus();
break;
}
};
TtsManage.speak("请在合适区域放置饭卡");
serialCardManage.sendRead();
} catch (e, stack) {
_closeStatus();
logger.d("读卡失败error:|$e|stack:|$stack|");
Toast.error(msg: "读取失败,请重试");
}
}
/// 从当前读卡弹窗切换为 M1 数据块诊断扫描,不改变正常读卡与支付流程。
Future<void> doScanMifareBlocks() async {
final currentProgress = scanProgress.value;
if (currentProgress != null && !currentProgress.completed) return;
try {
if (readLoading.value) {
// 用户主动切换扫描模式时先终止普通读卡,避免两个串口状态机竞争同一设备。
readLoading.value = false;
_closeSerialCardOperation();
}
detail.value = null;
// 点击后先建立扫描状态,连接串口期间按钮也会立即禁用,避免重复启动。
scanProgress.value = SerialMifareScanProgress.initial(
totalBlocks: SerialReadCardTool.mifareSafeDataBlockAddresses().length,
);
await serialCardManage.connect();
if (!serialCardManage.isConnect) {
scanProgress.value = null;
Toast.error(msg: "连接读卡器失败");
return;
}
serialCardManage.callback = (type, status, result) {
if (type != SerialCardCmdEnum.scan) return;
switch (status) {
case SerialCardResStatus.success:
if (result is SerialMifareScanProgress) {
scanProgress.value = result;
if (result.completed) {
final stopReason = result.stopReason;
if (stopReason == null) {
Toast.success(msg: "M1 数据块扫描完成");
} else {
Toast.error(msg: "扫描已提前结束:$stopReason");
}
}
}
break;
case SerialCardResStatus.warning:
break;
case SerialCardResStatus.error:
final message = result is String && result.trim().isNotEmpty
? result.trim()
: "M1 数据块扫描失败";
Toast.error(msg: message);
scanProgress.value = null;
_closeSerialCardOperation();
break;
}
};
TtsManage.speak("请保持饭卡不动,正在扫描数据块");
serialCardManage.scanMifareBlocks();
} catch (e, stack) {
scanProgress.value = null;
_closeSerialCardOperation();
logger.e("扫描 M1 数据块失败error:|$e|stack:|$stack|");
Toast.error(msg: "M1 数据块扫描失败");
}
}
/// 串口读卡成功后先更新弹窗,再查询绑定用户。
///
/// 读卡与网络查询是两个阶段,不能让接口等待、空列表或异常使界面一直停留在“扫描中”。
Future<void> _handleReadCardSuccess(dynamic result) async {
final cardNumber =
(result?.toString() ?? '').replaceAll(RegExp(r'[^a-zA-Z0-9]'), '');
if (cardNumber.isEmpty) {
TtsManage.speak("未读取到有效卡号");
Toast.error(msg: "未读取到有效卡号,请重新刷卡");
_closeStatus();
return;
}
// 先把串口结果写入当前弹窗的 Rx,网络查询期间不再错误显示为仍在读卡。
readLoading.value = false;
detail.value = ServiceOpenCard(
username: "用户信息查询中",
cardNumber: cardNumber,
);
TtsManage.speak("读取成功");
try {
final data = await WalletApi.openCardList({"cardNumber": cardNumber});
final records = data?.records;
if (records == null || records.isEmpty) {
detail.value = ServiceOpenCard(
username: "未绑定用户",
cardNumber: cardNumber,
);
TtsManage.speak("此饭卡未绑定用户");
Toast.error(msg: "此饭卡未绑定用户");
return;
}
detail.value = records.first;
} catch (e, stack) {
detail.value = ServiceOpenCard(
username: "用户信息查询失败",
cardNumber: cardNumber,
);
logger.e("读卡成功但查询绑定用户失败error:|$e|stack:|$stack|");
Toast.error(msg: "卡号读取成功,用户信息查询失败");
} finally {
// 用户可能已从普通读卡切换到块扫描,旧网络查询不得关闭新的串口操作。
if (serialCardManage.currentCmd != SerialCardCmdEnum.scan) {
_closeStatus();
}
}
}
Future<void> _getOpenCardSuccess(String id) async {
try {
EasyLoading.show(
status: '激活饭卡中...',
maskType: EasyLoadingMaskType.black,
);
final pa = {"id": id};
final data = await WalletApi.openCardSuccess(pa);
if (data == false) throw Error();
EasyLoading.dismiss();
TtsManage.speak("激活成功");
Toast.success(msg: "激活成功");
} catch (e, stack) {
logger.e("激活饭卡请求失败error:|$e|stack:|$stack|");
EasyLoading.dismiss();
Toast.error(msg: "激活失败");
}
}
// 重新激活
Future<void> doRefreshAvatar(ServiceOpenCard v) async {
if (v.isActiveHardware == false) {
Toast.error(msg: "该卡为激活状态,不能重新激活");
return;
}
try {
final isSure = await appMessageDialog(Get.context!, "是否重新激活");
if (!isSure) return;
final pa = {"id": v.id};
final data = await WalletApi.refreshAvatar(pa);
if (data == false) return;
TtsManage.speak("重新激活成功");
Toast.success(msg: "重新激活成功");
getTableList();
} catch (e, stack) {
logger.d("重新激活失败error:|$e|stack:|$stack|");
}
}
void _closeStatus() {
_closeSerialCardOperation();
readLoading.value = false;
writeLoading.value = false;
}
void _closeSerialCardOperation() {
serialCardManage.callback = null;
serialCardManage.close();
}
}