267 lines
8.4 KiB
Dart
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;
|
|
}
|
|
}
|