Files
biz_xfj_cloud/lib/common/utils/sync/sync_face_tool.dart
T
2026-07-28 21:34:12 +08:00

267 lines
8.4 KiB
Dart

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> delEmptyFace() async {
final app = Get.find<AppControl>();
final faceDao = app.dataBase.getFaceDao;
final faceList = await faceDao.getEmptyFaceList();
if (ObjectUtil.isEmptyList(faceList)) return;
for (final v in faceList!) {
if (ObjectUtil.isNotEmpty(v.path)) {
await delFaceByStorage(filePath: v.path!);
}
await faceDao.delById(v.id!);
}
}
// 同步人脸
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,
required String storagePath,
String? userId,
bool? isGlobalFace,
}) async {
final app = Get.find<AppControl>();
final faceDao = app.dataBase.getFaceDao;
const size = 100;
var pa = {
"current": pageNo,
"size": size,
"userId": userId,
"merchantDeptId": merchantDeptId,
};
if (isGlobalFace != null && isGlobalFace) pa["merchantDeptId"] = null;
logger.i("|$_tag|同步人脸api参数:|$pa|");
try {
final data = await UserApi.getFaceListV2(pa);
if (data == null) throw Error();
if (ObjectUtil.isEmptyList(data)) {
if (ObjectUtil.isEmpty(userId)) {
// 全量同步第 1 页为空时,服务端没有任何人脸,必须同步清空本地库和原生人脸库。
if (pageNo == 1 && ObjectUtil.isEmpty(merchantDeptId)) {
await faceDao.delAll();
await AppFaceTool.removeFace(sampleId: '-1');
}
return false;
}
// 删除人脸图片
final faceList = await faceDao.findByUserId(userId!);
if (!ObjectUtil.isEmptyList(faceList)) {
for (final v in faceList!) {
if (ObjectUtil.isNotEmpty(v.path)) {
await delFaceByStorage(filePath: v.path!);
await AppFaceTool.removeFace(sampleId: v.sampleId);
}
}
}
// 删除数据库
await faceDao.delByUserId(userId);
return false;
}
if (isGlobalFace != null && !isGlobalFace) return false;
if (userId != null) {
final dbUserList = await faceDao.findByUserId(userId);
if (!ObjectUtil.isEmptyList(dbUserList)) {
for (final v in dbUserList!) {
final target = data.firstWhereOrNull((i) => i.id == v.sampleId);
if (target == null) {
if (ObjectUtil.isNotEmpty(v.path)) {
await delFaceByStorage(filePath: v.path!);
await AppFaceTool.removeFace(sampleId: v.sampleId);
}
await faceDao.delById(v.id!);
}
}
}
}
for (final v in data) {
if (ObjectUtil.isEmpty(v.autoCode) || ObjectUtil.isEmpty(v.userId)) {
logger.e(
"|$_tag|同步人脸跳过无效数据:|autoCode=${v.autoCode}|userId=${v.userId}|deptId=${v.deptId}|username=${v.username}|",
);
continue;
}
final sampleId = v.autoCode!;
final userId = v.userId!;
// 删除人脸
if (v.delFlag == true) {
// 先查询数据库是否存在
final detail = await faceDao.findBySampleId(sampleId);
if (detail == null) {
continue;
}
if (ObjectUtil.isNotEmpty(detail.path)) {
await delFaceByStorage(filePath: detail.path!);
}
await AppFaceTool.removeFace(sampleId: sampleId);
await faceDao.delBySampleId(sampleId);
continue;
}
final faceEntity = await faceDao.findBySampleId(sampleId);
if (faceEntity == null) {
final add = FaceEntity(
userId: userId,
sampleId: sampleId,
userName: v.username ?? "",
deptId: v.deptId,
deptName: v.deptName ?? "",
imagePath: v.faceImg ?? "",
createTime: DateTime.now(),
);
final addId = await faceDao.save(add);
if (addId != null) {
String? fileName = generateFaceFileName(
userId: add.userId,
sampleId: add.sampleId,
username: add.userName,
facePath: add.imagePath,
);
final filePath = await writeFaceByStorage(
storagePath: storagePath,
fileName: fileName,
facePath: add.imagePath,
);
if (ObjectUtil.isNotEmpty(filePath)) {
add.id = addId;
add.updateTime = DateTime.now();
add.path = filePath;
await faceDao.edit(add);
}
}
await AppFaceTool.removeFace(sampleId: add.sampleId);
await AppFaceTool.faceRegister(
userId: add.userId.toString(),
forceRegister: true,
);
continue;
}
final edit = FaceEntity(
id: faceEntity.id!,
userId: userId,
sampleId: sampleId,
userName: v.username ?? "",
deptId: v.deptId,
deptName: v.deptName ?? "",
imagePath: v.faceImg ?? "",
createTime: DateTime.now(),
);
if (edit == faceEntity) {
continue;
}
String? fileName = generateFaceFileName(
userId: edit.userId,
sampleId: edit.sampleId,
username: edit.userName,
facePath: edit.imagePath,
);
final filePath = await writeFaceByStorage(
storagePath: storagePath,
facePath: edit.imagePath,
fileName: fileName,
);
if (ObjectUtil.isNotEmpty(filePath)) {
if (ObjectUtil.isNotEmpty(edit.path)) {
await delFaceByStorage(filePath: edit.path!);
}
edit.path = filePath;
}
await faceDao.edit(edit);
// 重新生成人脸模型
await AppFaceTool.removeFace(sampleId: edit.sampleId);
await AppFaceTool.faceRegister(
userId: edit.userId.toString(),
forceRegister: true,
);
}
if (data.length >= size) return true;
} catch (e, stack) {
logger.e("|$_tag|同步人脸意外的错误error:|$e|stack:|$stack|");
}
return false;
}
/// 删除人脸图片
static Future<void> delFaceByStorage({
required String filePath,
}) async {
try {
final file = File(filePath);
if (await file.exists()) {
await file.delete();
}
} catch (e) {
logger.e("|$_tag|删除人脸图片意外的错误error:|$e|");
}
}
static String? generateFaceFileName({
required String userId,
required String sampleId,
required String username,
required String facePath,
}) {
if (ObjectUtil.isEmpty(facePath)) return null;
return "${userId}_${sampleId}_$username${AppFileTool.getFileExtension(facePath)}";
}
/// 写入人脸头像到本地磁盘
static Future<String?> writeFaceByStorage({
required String storagePath,
required String? fileName,
required String facePath,
}) async {
if (ObjectUtil.isEmpty(fileName)) return null;
final storageDirectory = Directory(storagePath);
final file = File('${storageDirectory.path}/$fileName');
if (await file.exists()) {
await file.delete();
}
final bytesImg = await AppNetworkTool.downloadImage(facePath);
if (bytesImg == null) return null;
final writeFile = await file.writeAsBytes(bytesImg);
if (await writeFile.exists()) {
return file.path;
}
return null;
}
}