feat:人脸管理优化

This commit is contained in:
dzc committed 2025-03-11 21:31:35 +08:00
1 parent 88e73ad950
commit 2490d4f9a0
9 files changed
+175 -40

No files matched your search

@@ -1,5 +1,17 @@
package com.example.pj_supermarket_cloud
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.facediscern.flutter.FlutterFaceDiscernPlugin
class MainActivity: FlutterActivity()
class MainActivity : FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
// 人脸识别插件
val flutterFaceDiscernPlugin = FlutterFaceDiscernPlugin()
flutterEngine.plugins.add(flutterFaceDiscernPlugin)
// tts插件
// 箭头全局键盘插件
}
}
+1 -1
View File
@@ -21,7 +21,7 @@ class MainApp extends StatelessWidget {
final fTheme = appTheme.theme.value;
final sizeScalar = appTheme.sizeScalar.value;
final themeData = FThemeData.inherit(
colorScheme: fTheme.colorScheme.copyWith(),
colorScheme: fTheme.colorScheme,
typography: fTheme.typography.scale(sizeScalar: sizeScalar),
style: fTheme.style.copyWith(
borderRadius: BorderRadius.all(
+12 -1
View File
@@ -164,5 +164,16 @@ abstract class AppFileTool {
}
}
// 备份日志
// 获取文件后缀
static String getFileExtension(String url) {
int lastDotIndex = url.lastIndexOf('.');
if (lastDotIndex == -1) {
return '';
}
int lastSlashIndex = url.lastIndexOf('/');
if (lastDotIndex > lastSlashIndex) {
return url.substring(lastDotIndex);
}
return '';
}
}
@@ -8,10 +8,11 @@ abstract class FaceDiscernPlugs {
static const String _tag = "人脸识别plug";
static const MethodChannel _channel = MethodChannel(
"local/face_discern",
Constants.facePlugsMethodChannel,
);
static const EventChannel _eventChannel = EventChannel(
"local/face_discern_event",
Constants.facePlugsEventChannel,
);
static MethodChannel get getChannel => _channel;
+33 -2
View File
@@ -1,12 +1,43 @@
import 'dart:io';
import 'package:common_utils/common_utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pj_supermarket_cloud/common/index.dart';
class SyncFaceTool {
static const _tag = "sync人脸工具";
// 同步人脸
static Future<void> syncFace({
bool isAll = false,
VoidCallback? onSyncGroup,
}) async {
final appSetting = await AppSettingTool.getSysSetting();
final merchantDeptId = appSetting.merchantDeptId;
// 人脸存储路径
final storagePath = await AppFileTool.getFacePath();
if (ObjectUtil.isEmpty(storagePath)) {
logger.e("|$_tag|同步人脸错误,创建人脸存储路径错误");
return;
}
// 同步没有的人脸
int pageNo = 1;
bool isNext = true;
while (isNext) {
final bool = await syncGroupFace(
pageNo: pageNo,
merchantDeptId: isAll ? "" : merchantDeptId!,
storagePath: storagePath!,
);
if (isNext != bool) isNext = bool;
if (!bool) break;
pageNo += 1;
onSyncGroup?.call();
}
}
static Future<bool> syncGroupFace({
required int pageNo,
required String merchantDeptId,
@@ -16,7 +47,7 @@ class SyncFaceTool {
}) async {
final app = Get.find<AppControl>();
final faceDao = app.dataBase.getFaceDao;
const size = 20;
const size = 50;
var pa = {
"current": pageNo,
"size": size,
@@ -166,7 +197,7 @@ class SyncFaceTool {
required String facePath,
}) {
if (ObjectUtil.isEmpty(facePath)) return null;
return "${userId}_${sampleId}_$username$facePath";
return "${userId}_${sampleId}_$username${AppFileTool.getFileExtension(facePath)}";
}
/// 写入人脸头像到本地磁盘
+6
View File
@@ -20,6 +20,12 @@ class Constants {
/// ttl android 插件方法管道
static const localTTSPlugsMethodChannel = 'local/tts';
/// 人脸识别 插件方法管道
static const facePlugsMethodChannel = 'local/face_discern';
/// 人脸识别 插件回调管道
static const facePlugsEventChannel = 'local/face_discern_event';
/// 数据库名字
static const databaseName = 'cash_register.db';
}
+4 -2
View File
@@ -56,8 +56,10 @@ class PanelController extends GetxController {
Get.toNamed(RouteNames.orderHistory);
break;
case PanelType.setting:
final flag = await settingPasswordDialog(Get.context!);
if (!flag) return;
if (AppSysTool.isProd()) {
final flag = await settingPasswordDialog(Get.context!);
if (!flag) return;
}
Get.toNamed(RouteNames.setting);
break;
case PanelType.cardActive:
@@ -15,7 +15,7 @@ Future<void> _bindServiceDialog(BuildContext context, SysSetting sys) async {
if (ObjectUtil.isNotEmpty(sys.serviceId)) {
uniqueCodeC.text = sys.serviceId ?? "";
} else if (AppSysTool.isDev()) {
uniqueCodeC.text = "1896157295523049473";
uniqueCodeC.text = "1894303392833716226";
}
await showAdaptiveDialog(
context: context,
+102 -30
View File
@@ -12,6 +12,8 @@ import 'package:pj_supermarket_cloud/common/index.dart';
class FaceManageController extends GetxController {
static const String _tag = "人脸管理 Controller";
final appC = Get.find<AppControl>();
RxList<FaceEntity> faceList = RxList();
RxInt currentPage = RxInt(1);
@@ -45,19 +47,16 @@ class FaceManageController extends GetxController {
);
}
try {
final app = Get.find<AppControl>();
final faceDao = app.dataBase.getFaceDao;
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,
);
if (findCount != null) {
totalPage.value = (findCount / pageSize.value).ceil();
}
faceList.value = list;
} finally {
if (isLoading) {
@@ -78,14 +77,14 @@ class FaceManageController extends GetxController {
Toast.error(msg: "请先绑定设备");
return;
}
final isActive = await AppFaceTool.isActiveSdk();
if (!isActive) {
Toast.error(msg: "人脸sdk激活失败");
return;
}
// final isActive = await AppFaceTool.isActiveSdk();
// if (!isActive) {
// Toast.error(msg: "人脸sdk激活失败");
// return;
// }
final isSure = await appMessageDialog(
Get.context!,
"是否同步所有人脸,这个过程肯能比较长",
"是否同步所有人脸,这个过程可能比较长",
);
if (!isSure) return;
EasyLoading.show(
@@ -93,10 +92,18 @@ class FaceManageController extends GetxController {
maskType: EasyLoadingMaskType.black,
);
try {
// await SyncFaceTool.syncFace(isAll: isAll);
await SyncFaceTool.syncFace(
isAll: isAll,
onSyncGroup: () {
currentPage.value = 1;
getFaceList();
},
);
} finally {
currentPage.value = 1;
getFaceList();
await AppFaceTool.faceRegister(forceRegister: true);
Toast.success(msg: "同步成功");
EasyLoading.dismiss();
}
}
@@ -112,23 +119,22 @@ class FaceManageController extends GetxController {
maskType: EasyLoadingMaskType.black,
);
try {
final app = Get.find<AppControl>();
final faceDao = app.dataBase.getFaceDao;
final faceDao = appC.dataBase.getFaceDao;
await faceDao.delAll();
final bool = await AppFaceTool.removeFace(sampleId: "-1");
logger.i(bool);
} finally {
Future.delayed(const Duration(seconds: 1), () {
getFaceList();
Toast.success(msg: "同步成功");
EasyLoading.dismiss();
});
}
}
_listenMqCallback() {
final app = Get.find<AppControl>();
mqUpdateListen =
app.mqUpdateEventBus.on<MqtActionEnum>().listen((event) async {
appC.mqUpdateEventBus.on<MqtActionEnum>().listen((event) async {
switch (event) {
case MqtActionEnum.face:
getFaceList(isLoading: true);
@@ -142,6 +148,30 @@ class FaceManageController extends GetxController {
if (page != null) currentPage.value = page;
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);
} finally {
Future.delayed(const Duration(seconds: 1), () {
getFaceList();
Toast.success(msg: "删除成功");
EasyLoading.dismiss();
});
}
}
}
/// 搜索
@@ -202,28 +232,70 @@ Widget buildFaceSearch(BuildContext context) {
/// 列表
Widget buildFaceList(context) {
return <Widget>[].toRow();
}
/// 分页
Widget buildFacePage(context) {
final faceC = Get.find<FaceManageController>();
return appPage(
context,
pageNo: faceC.currentPage.value,
pageSize: faceC.pageSize.value,
total: faceC.totalPage.value,
onPageChanged: (pageNo) => faceC.doPage(page: pageNo),
final theme = FTheme.of(context);
final productC = Get.find<FaceManageController>();
return Obx(
() => GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 5,
mainAxisSpacing: 10.w,
crossAxisSpacing: 10.w,
childAspectRatio: 1.2,
),
itemCount: productC.faceList.length,
itemBuilder: (BuildContext context, int index) {
final v = productC.faceList[index];
return FCard(
style: theme.cardStyle.copyWith(
contentStyle: theme.cardStyle.contentStyle.copyWith(
padding: EdgeInsets.all(0),
),
),
image: appImg(v.path, width: 120.w, height: 120.w)
.center()
.marginOnly(top: 5.h),
title: Text(
v.userName,
maxLines: 1,
style: theme.typography.sm,
).center(),
subtitle: <Widget>[
Text(
"用户编号:${v.userId}",
style: theme.typography.xs.copyWith(height: 1),
),
Text(
"样本编号:${v.sampleId}",
style: theme.typography.xs.copyWith(height: 1),
),
]
.toColumnSpace(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
)
.width(double.infinity)
.marginOnly(top: 5.h),
).onTap(() => productC.deleteFace(v));
},
),
);
}
Widget settingFace(BuildContext context) {
Get.put<FaceManageController>(
final faceC = Get.put<FaceManageController>(
FaceManageController(),
);
return <Widget>[
buildFaceSearch(context),
buildFaceList(context).expanded(),
buildFacePage(context),
Obx(
() => appPage(
context,
pageNo: faceC.currentPage.value,
pageSize: faceC.pageSize.value,
total: faceC.totalPage.value,
onPageChanged: (pageNo) => faceC.doPage(page: pageNo),
),
),
].toColumn();
}