Files
biz_xfj_cloud/lib/pages/setting/widgets/setting_face.dart
T

387 lines
11 KiB
Dart

import 'dart:async';
import 'package:common_utils/common_utils.dart';
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:forui/forui.dart';
import 'package:get/get.dart';
import 'package:pj_supermarket_cloud/common/index.dart';
import 'setting_components.dart';
class FaceManageController extends GetxController {
final appC = Get.find<AppControl>();
late SysSetting sysSetting;
Rx<SysType> sysType = SysType.CANTEEN.obs;
RxList<FaceEntity> faceList = RxList();
RxInt currentPage = RxInt(1);
RxInt totalPage = RxInt(0);
RxInt pageSize = RxInt(15);
RxBool isLoading = false.obs;
RxString errorMessage = ''.obs;
final usernameC = TextEditingController();
StreamSubscription? mqUpdateListen;
@override
void onInit() async {
super.onInit();
sysSetting = await AppSettingTool.getSysSetting();
sysType.value = sysSetting.sysType;
getFaceList();
_listenMqCallback();
}
@override
void onClose() {
mqUpdateListen?.cancel();
usernameC.dispose();
}
Future<void> getFaceList({bool isLoading = false}) async {
this.isLoading.value = true;
errorMessage.value = '';
if (isLoading) {
EasyLoading.show(
status: '查询中...',
maskType: EasyLoadingMaskType.black,
);
}
try {
final faceDao = appC.dataBase.getFaceDao;
String userName = usernameC.text;
if (ObjectUtil.isEmpty(userName)) userName = "-1";
final findCount = await faceDao.findCount(userName);
totalPage.value = findCount ?? 0;
final list = await faceDao.findAll(
userName,
pageSize.value,
(currentPage.value - 1) * pageSize.value,
);
faceList.value = list;
} catch (e, stack) {
errorMessage.value = '人脸数据加载失败,请稍后重试';
logger.e('|人脸管理|加载失败error:|$e|stack:|$stack|');
} finally {
this.isLoading.value = false;
if (isLoading) {
Future.delayed(const Duration(seconds: 1), () {
EasyLoading.dismiss();
});
}
}
}
// 同步人脸
Future<void> asyncFace({bool isAll = false}) async {
final isNetwork = AppNetworkTool.isAutoNetworkMsg();
if (!isNetwork) return;
final setting = await AppSettingTool.getSysSetting();
final serviceMerchantId = setting.serviceMerchantId;
if (ObjectUtil.isEmpty(serviceMerchantId)) {
Toast.error(msg: "请先绑定设备");
return;
}
if (AppSysTool.isProd()) {
final isActive = await AppFaceTool.isActiveSdk();
if (!isActive) {
Toast.error(msg: "人脸sdk激活失败");
return;
}
}
final isSure = await appMessageDialog(
Get.context!,
"是否同步所有人脸,这个过程可能比较长",
);
if (!isSure) return;
EasyLoading.show(
status: '同步中...',
maskType: EasyLoadingMaskType.black,
);
try {
await SyncFaceTool.delEmptyFace();
await SyncFaceTool.syncFace(
isAll: isAll,
onSyncGroup: () {
currentPage.value = 1;
getFaceList();
},
);
await getFaceList();
Toast.success(msg: '同步成功');
} catch (e, stack) {
Toast.error(msg: '同步人脸失败,请稍后重试');
logger.e('|人脸管理|同步失败error:|$e|stack:|$stack|');
} finally {
currentPage.value = 1;
EasyLoading.dismiss();
}
}
Future<void> delAllFace() async {
final isSure = await appMessageDialog(
Get.context!,
"是否删除全部人脸",
);
if (!isSure) return;
EasyLoading.show(
status: '删除中...',
maskType: EasyLoadingMaskType.black,
);
try {
final faceDao = appC.dataBase.getFaceDao;
await faceDao.delAll();
await AppFaceTool.removeFace(sampleId: '-1');
await getFaceList();
Toast.success(msg: '删除成功');
} catch (e, stack) {
Toast.error(msg: '删除全部人脸失败');
logger.e('|人脸管理|删除全部失败error:|$e|stack:|$stack|');
} finally {
EasyLoading.dismiss();
}
}
_listenMqCallback() {
mqUpdateListen =
appC.mqUpdateEventBus.on<MqtActionEnum>().listen((event) async {
switch (event) {
case MqtActionEnum.FACE:
getFaceList(isLoading: true);
break;
default:
}
});
}
/// 搜索
Future<void> doPage({int? page}) async {
if (page != null) currentPage.value = page;
// 收起键盘
FocusManager.instance.primaryFocus?.unfocus();
await getFaceList(isLoading: true);
}
/// 重置
Future<void> doReset() async {
currentPage.value = 1;
usernameC.clear();
// 收起键盘
FocusManager.instance.primaryFocus?.unfocus();
await getFaceList(isLoading: true);
}
// 删除人脸
Future<void> deleteFace(FaceEntity v) async {
final isSure = await appMessageDialog(Get.context!, "是否删除人脸");
if (!isSure) return;
EasyLoading.show(
status: '删除中...',
maskType: EasyLoadingMaskType.black,
);
try {
final faceDao = appC.dataBase.getFaceDao;
if (ObjectUtil.isNotEmpty(v.path)) {
await SyncFaceTool.delFaceByStorage(filePath: v.path!);
}
await faceDao.delById(v.id!);
await AppFaceTool.removeFace(sampleId: v.sampleId);
await getFaceList();
Toast.success(msg: '删除成功');
} catch (e, stack) {
Toast.error(msg: '删除人脸失败');
logger.e('|人脸管理|删除失败error:|$e|stack:|$stack|');
} finally {
EasyLoading.dismiss();
}
}
}
/// 搜索
Widget buildFaceSearch(BuildContext context) {
final faceC = Get.find<FaceManageController>();
final theme = FTheme.of(context);
return <Widget>[
Obx(
() => FTextField(
textInputAction: faceC.sysType.value == SysType.SUPERMARKET
? TextInputAction.none
: TextInputAction.newline,
keyboardType: faceC.sysType.value == SysType.SUPERMARKET
? TextInputType.none
: TextInputType.multiline,
controller: faceC.usernameC,
hint: '请输入姓名',
maxLines: 1,
onSubmit: (_) => faceC.doPage(),
),
).width(300.w),
FButton(
prefix: FIcon(
FAssets.icons.ban,
size: theme.typography.base.fontSize,
),
label: Text(
'重置',
style: theme.typography.base.copyWith(
color: theme.colorScheme.secondary,
),
),
onPress: () => faceC.doReset(),
),
FButton(
prefix: FIcon(
FAssets.icons.search,
size: theme.typography.base.fontSize,
),
label: Text(
'搜索',
style: theme.typography.base.copyWith(
color: theme.colorScheme.secondary,
),
),
onPress: () => faceC.doPage(),
),
FButton(
label: Text(
'同步本部门人脸',
style: theme.typography.base.copyWith(
color: theme.colorScheme.primary,
),
),
style: FButtonStyle.outline,
onPress: () => faceC.asyncFace(isAll: false),
),
FButton(
label: Text(
'同步全部人脸',
style: theme.typography.base.copyWith(
color: theme.colorScheme.primary,
),
),
style: FButtonStyle.outline,
onPress: () => faceC.asyncFace(isAll: true),
),
const Spacer(),
FButton(
label: Text(
'删除全部人脸',
style: theme.typography.base.copyWith(color: Colors.white),
),
style: FButtonStyle.destructive,
onPress: () => faceC.delAllFace(),
),
].toRowSpace(space: 20.w);
}
/// 列表
Widget buildFaceList(context) {
final theme = FTheme.of(context);
final productC = Get.find<FaceManageController>();
return Obx(
() {
if (productC.isLoading.value) {
return const Center(child: CircularProgressIndicator());
}
if (productC.errorMessage.isNotEmpty) {
return SettingEmpty(message: productC.errorMessage.value);
}
if (productC.faceList.isEmpty) {
return const SettingEmpty(message: '暂无本地人脸样本');
}
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 5,
mainAxisSpacing: XfjDesignTokens.cardGap.h,
crossAxisSpacing: XfjDesignTokens.cardGap.w,
childAspectRatio: 1.2,
),
itemCount: productC.faceList.length,
itemBuilder: (BuildContext context, int index) {
final v = productC.faceList[index];
return InkWell(
onTap: () => productC.deleteFace(v),
borderRadius: BorderRadius.circular(XfjDesignTokens.cardRadius),
child: Container(
padding: EdgeInsets.all(14.w),
decoration: BoxDecoration(
color: XfjDesignTokens.surface,
border: Border.all(color: XfjDesignTokens.line),
borderRadius: BorderRadius.circular(XfjDesignTokens.cardRadius),
boxShadow: XfjDesignTokens.surfaceShadow,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ClipOval(
child: appImg(v.path, width: 72.w, height: 72.w),
),
SizedBox(height: 10.h),
Text(
v.userName,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: theme.typography.base.copyWith(
color: XfjDesignTokens.ink,
fontWeight: FontWeight.w800,
),
),
SizedBox(height: 5.h),
Text(
'用户编号:${_maskFaceId(v.userId.toString())}',
style: theme.typography.xs.copyWith(
color: XfjDesignTokens.muted,
),
),
SizedBox(height: 3.h),
Text(
'样本编号:${_maskFaceId(v.sampleId)}',
style: theme.typography.xs.copyWith(
color: XfjDesignTokens.muted,
),
),
],
),
),
);
},
);
},
);
}
Widget settingFace(BuildContext context) {
final faceC = Get.isRegistered<FaceManageController>()
? Get.find<FaceManageController>()
: Get.put(FaceManageController());
return <Widget>[
buildFaceSearch(context),
buildFaceList(context).expanded(),
Obx(
() => appPage(
context,
pageNo: faceC.currentPage.value,
pageSize: faceC.pageSize.value,
total: faceC.totalPage.value,
onPageChanged: (pageNo) => faceC.doPage(page: pageNo),
),
),
].toColumnSpace(space: XfjDesignTokens.cardGap.h);
}
String _maskFaceId(String value) {
if (value.length <= 4) return '***$value';
return '${value.substring(0, 1)}***${value.substring(value.length - 3)}';
}