From 7493e5a3a37ebca0ea8d370d76cba59b62360718 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Mon, 26 Aug 2024 15:08:30 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E4=BA=BA=E8=84=B8=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dlhis.Jinko.Face.sln | 7 ++ Src/Dlhis.Basic/Dlhis.Basic.csproj | 1 + .../Controllers/FactorySettingController.cs | 14 +++- .../GainfoOutsourceSettingController.cs | 48 ----------- .../Request/FactorySettingSaveRequest.cs | 6 ++ .../Response/FactorySettingResponse.cs | 7 ++ .../Services/IFactorySettingService.cs | 2 + .../IGainfoOutsourceSettingService.cs | 10 --- .../Implements/FactorySettingService.cs | 80 ++++++++++++++----- .../Services/Implements/GainfoFaceService.cs | 69 ++++++++++++---- .../GainfoOutsourceSettingService.cs | 71 ---------------- .../Implements/GainfoQrCodeService.cs | 10 ++- Src/Dlhis.Basic/Program.cs | 1 - Src/Dlhis.Basic/appsettings.Development.json | 3 +- Src/Dlhis.Basic/appsettings.json | 3 +- .../Basic/Dto/FaceImageDetectionDto.cs | 29 +++++++ .../Basic/Enums/FaceQualityLevelEnumType.cs | 23 ++++++ .../Basic/Enums/FaceQualityTypeEnumType.cs | 46 +++++++++++ .../Sys/Entities/FactorySettingEntity.cs | 7 ++ .../Dlhis.InfoCheck.Api.csproj | 13 +++ Src/Dlhis.InfoCheck.Api/IInfoCheckApi.cs | 20 +++++ .../Requests/FaceDetectRequest.cs | 17 ++++ .../Controllers/FaceController.cs | 49 +++++------- Src/Dlhis.InfoCheck/Dlhis.InfoCheck.csproj | 2 +- .../Request/FaceDetectRequest.cs | 11 ++- .../Request/FaceRecognizeRequest.cs | 6 ++ .../Response/FacialDetectionResponse.cs | 36 +++++++++ Src/Dlhis.InfoCheck/faceQualityExtensions.cs | 27 +++++++ .../BalanceRecordCheckBackgroundService.cs | 9 ++- 29 files changed, 422 insertions(+), 205 deletions(-) delete mode 100644 Src/Dlhis.Basic/Organization/Controllers/GainfoOutsourceSettingController.cs delete mode 100644 Src/Dlhis.Basic/Organization/Services/IGainfoOutsourceSettingService.cs delete mode 100644 Src/Dlhis.Basic/Organization/Services/Implements/GainfoOutsourceSettingService.cs create mode 100644 Src/Dlhis.Entity/Basic/Dto/FaceImageDetectionDto.cs create mode 100644 Src/Dlhis.Entity/Basic/Enums/FaceQualityLevelEnumType.cs create mode 100644 Src/Dlhis.Entity/Basic/Enums/FaceQualityTypeEnumType.cs create mode 100644 Src/Dlhis.InfoCheck.Api/Dlhis.InfoCheck.Api.csproj create mode 100644 Src/Dlhis.InfoCheck.Api/IInfoCheckApi.cs create mode 100644 Src/Dlhis.InfoCheck.Api/Requests/FaceDetectRequest.cs create mode 100644 Src/Dlhis.InfoCheck/Response/FacialDetectionResponse.cs create mode 100644 Src/Dlhis.InfoCheck/faceQualityExtensions.cs diff --git a/Dlhis.Jinko.Face.sln b/Dlhis.Jinko.Face.sln index b7e65f3f..dc9198be 100644 --- a/Dlhis.Jinko.Face.sln +++ b/Dlhis.Jinko.Face.sln @@ -51,6 +51,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.Middle", "Src\Dlhis.M EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.DataPermission.Model", "Src\Dlhis.DataPermission.Model\Dlhis.DataPermission.Model.csproj", "{CA1427E2-CC70-4489-8653-1C05630C8392}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dlhis.InfoCheck.Api", "Src\Dlhis.InfoCheck.Api\Dlhis.InfoCheck.Api.csproj", "{A501D16E-638F-4156-989C-2BACCC2FAC2B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -129,6 +131,10 @@ Global {CA1427E2-CC70-4489-8653-1C05630C8392}.Debug|Any CPU.Build.0 = Debug|Any CPU {CA1427E2-CC70-4489-8653-1C05630C8392}.Release|Any CPU.ActiveCfg = Release|Any CPU {CA1427E2-CC70-4489-8653-1C05630C8392}.Release|Any CPU.Build.0 = Release|Any CPU + {A501D16E-638F-4156-989C-2BACCC2FAC2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A501D16E-638F-4156-989C-2BACCC2FAC2B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A501D16E-638F-4156-989C-2BACCC2FAC2B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A501D16E-638F-4156-989C-2BACCC2FAC2B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -148,6 +154,7 @@ Global {69E8A91A-5D05-4327-BC24-038523C7628C} = {489252FB-A44B-46EE-B065-21CDCB724441} {053BF7B2-B1A0-435F-9C77-2EF5622CC5C5} = {65E76F97-E78A-4C95-B788-4091236B1A79} {4D656761-8CE7-4316-A3DF-8C1722D69CCE} = {4EBCE46B-CE3A-4A47-9432-82A1854CA58A} + {A501D16E-638F-4156-989C-2BACCC2FAC2B} = {4EBCE46B-CE3A-4A47-9432-82A1854CA58A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7439494A-E2FD-4FEA-8ABF-74AE57A4A5A0} diff --git a/Src/Dlhis.Basic/Dlhis.Basic.csproj b/Src/Dlhis.Basic/Dlhis.Basic.csproj index 9528dadc..2d2370fa 100644 --- a/Src/Dlhis.Basic/Dlhis.Basic.csproj +++ b/Src/Dlhis.Basic/Dlhis.Basic.csproj @@ -25,6 +25,7 @@ + diff --git a/Src/Dlhis.Basic/Organization/Controllers/FactorySettingController.cs b/Src/Dlhis.Basic/Organization/Controllers/FactorySettingController.cs index e6074b1f..985c0a40 100644 --- a/Src/Dlhis.Basic/Organization/Controllers/FactorySettingController.cs +++ b/Src/Dlhis.Basic/Organization/Controllers/FactorySettingController.cs @@ -1,4 +1,5 @@ -using Dlhis.Basic.Organization.Request; +using System.ComponentModel.DataAnnotations; +using Dlhis.Basic.Organization.Request; using Dlhis.Basic.Organization.Response; using Dlhis.Basic.Organization.Services; using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop; @@ -43,4 +44,15 @@ public class FactorySettingController : ControllerBase { await _factorySettingService.SaveAsync(request); } + + /// + /// 根据factory获取配置 + /// + /// + /// + [HttpGet("single")] + public async Task GetFactorySettingAsync([Required(ErrorMessage = "厂区不可为空")] string factory) + { + return await _factorySettingService.GetFactorySettingAsync(factory); + } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/Organization/Controllers/GainfoOutsourceSettingController.cs b/Src/Dlhis.Basic/Organization/Controllers/GainfoOutsourceSettingController.cs deleted file mode 100644 index 84676457..00000000 --- a/Src/Dlhis.Basic/Organization/Controllers/GainfoOutsourceSettingController.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Dlhis.Basic.Device.Filters; -using Dlhis.Basic.Organization.Request; -using Dlhis.Basic.Organization.Services; -using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; - -namespace Dlhis.Basic.Organization.Controllers; - -/// -/// 外包人员配置 -/// -[Authorize] -[Route("api/[controller]")] -[ApiController] -public class GainfoOutsourceSettingController : ControllerBase -{ - private readonly IGainfoOutsourceSettingService _gainfoOutSourceService; - - public GainfoOutsourceSettingController(IGainfoOutsourceSettingService gainfoOutSourceService) - { - _gainfoOutSourceService = gainfoOutSourceService; - } - - - /// - /// 保存配置 - /// - /// - [HttpPost("save")] - [AssignPermissionLimit] - [Transactional] - [CrossTenant] - public async Task SaveAsync(GainfoOutsourceSettingSaveRequest request) - { - await _gainfoOutSourceService.SaveAsync(request); - } - - /// - /// 获取当前厂区配置 - /// - /// - [HttpGet("current")] - public async Task GetSettingAsync() - { - return await _gainfoOutSourceService.GetSettingAsync(); - } -} \ No newline at end of file diff --git a/Src/Dlhis.Basic/Organization/Request/FactorySettingSaveRequest.cs b/Src/Dlhis.Basic/Organization/Request/FactorySettingSaveRequest.cs index b2003fd0..9756b0b2 100644 --- a/Src/Dlhis.Basic/Organization/Request/FactorySettingSaveRequest.cs +++ b/Src/Dlhis.Basic/Organization/Request/FactorySettingSaveRequest.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using Dlhis.Entity.Basic.Dto; namespace Dlhis.Basic.Organization.Request; @@ -16,4 +17,9 @@ public class FactorySettingSaveRequest /// 档案二维码过期时间 /// public int? UserQrCodeExpiration { get; set; } + + /// + /// 人脸检测配置 + /// + public FaceImageDetectionDto FaceImageDetection { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/Organization/Response/FactorySettingResponse.cs b/Src/Dlhis.Basic/Organization/Response/FactorySettingResponse.cs index f60f17be..3e6a9661 100644 --- a/Src/Dlhis.Basic/Organization/Response/FactorySettingResponse.cs +++ b/Src/Dlhis.Basic/Organization/Response/FactorySettingResponse.cs @@ -1,3 +1,5 @@ +using Dlhis.Entity.Basic.Dto; + namespace Dlhis.Basic.Organization.Response; public class FactorySettingResponse @@ -15,4 +17,9 @@ public class FactorySettingResponse /// 档案二维码过期时间 /// public int? UserQrCodeExpiration { get; set; } + + /// + /// 人脸检测 + /// + public FaceImageDetectionDto FaceImageDetection { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/Organization/Services/IFactorySettingService.cs b/Src/Dlhis.Basic/Organization/Services/IFactorySettingService.cs index 0aee4dc4..4d5bd54e 100644 --- a/Src/Dlhis.Basic/Organization/Services/IFactorySettingService.cs +++ b/Src/Dlhis.Basic/Organization/Services/IFactorySettingService.cs @@ -8,4 +8,6 @@ public interface IFactorySettingService : IScopeDependency Task> GetListAsync(); Task SaveAsync(FactorySettingSaveRequest request); + + Task GetFactorySettingAsync(string factory); } \ No newline at end of file diff --git a/Src/Dlhis.Basic/Organization/Services/IGainfoOutsourceSettingService.cs b/Src/Dlhis.Basic/Organization/Services/IGainfoOutsourceSettingService.cs deleted file mode 100644 index 6c933100..00000000 --- a/Src/Dlhis.Basic/Organization/Services/IGainfoOutsourceSettingService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Dlhis.Basic.Organization.Request; - -namespace Dlhis.Basic.Organization.Services; - -public interface IGainfoOutsourceSettingService : IScopeDependency -{ - Task SaveAsync(GainfoOutsourceSettingSaveRequest request); - - Task GetSettingAsync(); -} \ No newline at end of file diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/FactorySettingService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/FactorySettingService.cs index e4bf8180..84fb2d8f 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/FactorySettingService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/FactorySettingService.cs @@ -1,8 +1,13 @@ +using System.Reflection; using Dlhis.Basic.Organization.Request; using Dlhis.Basic.Organization.Response; +using Dlhis.Entity.Basic.Dto; +using Dlhis.Entity.Basic.Enums; using Dlhis.Entity.Sys.Entities; using Dlhis.Sys.Api; +using Dlhis.Sys.Api.Response; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.Utils.Extensions; using Mapster; namespace Dlhis.Basic.Organization.Services.Implements; @@ -20,24 +25,7 @@ public class FactorySettingService : IFactorySettingService public async Task> GetListAsync() { - var apiResult = await _tenantApi.GetMyTenantsAsync(); - var factories = apiResult.Data; - - var factoryCodes = factories.Select(x => x.Code).ToList(); - var settings = await _dbContext.Queryable().Where(x => factoryCodes.Contains(x.TenantId)) - .ToListAsync(); - - return factories.Select(item => - { - var factory = factories.FirstOrDefault(x => x.Code == item.Code); - return new FactorySettingResponse - { - Factory = factory?.Code, - FactoryName = factory?.Name, - EnableOutsourceDown = settings.FirstOrDefault(x => x.TenantId == item.Code)?.EnableOutsourceDown ?? false, - UserQrCodeExpiration = settings.FirstOrDefault(x => x.TenantId == item.Code)?.UserQrCodeExpiration - }; - }).ToList(); + return await GetFactorySettingsAsync(); } public async Task SaveAsync(FactorySettingSaveRequest request) @@ -58,4 +46,60 @@ public class FactorySettingService : IFactorySettingService await _dbContext.UpdateAsync(setting); } } + + public async Task GetFactorySettingAsync(string factory) + { + var settings = await GetFactorySettingsAsync(factory); + var setting = settings.FirstOrDefault() ?? new FactorySettingResponse(); + + setting.UserQrCodeExpiration ??= 60 * 1000 * 60; + setting.FaceImageDetection ??= new FaceImageDetectionDto + { + Enable = true, + Detections = typeof(FaceQualityTypeEnumType).GetFields(BindingFlags.Public | BindingFlags.Static).Select(x => new FaceImageDetection + { + Type = Enum.Parse(x!.GetValue(null)!.ToString()!), + Level = FaceQualityLevelEnumType.Medium + }).ToList() + }; + + return setting; + } + + //************************************************************************************************************************************************************ + + private async Task> GetFactorySettingsAsync(string factory = null) + { + List factories; + + + if (factory.IsPresent()) + { + factories = new List { new() { Code = factory } }; + } + else + { + var apiResult = await _tenantApi.GetMyTenantsAsync(); + factories = apiResult.Data; + } + + var factoryCodes = factories.Select(x => x.Code).ToList(); + var settings = await _dbContext.Queryable() + .Where(x => factoryCodes.Contains(x.TenantId)) + .ToListAsync(); + + return factories.Select(item => + { + var currentFactory = factories.FirstOrDefault(x => x.Code == item.Code); + var currentSetting = settings.FirstOrDefault(x => x.TenantId == item.Code); + return new FactorySettingResponse + { + Factory = currentFactory?.Code, + FactoryName = currentFactory?.Name, + EnableOutsourceDown = currentSetting?.EnableOutsourceDown ?? false, + UserQrCodeExpiration = currentSetting?.UserQrCodeExpiration, + FaceImageDetection = currentSetting?.FaceImageDetection + }; + }).ToList(); + } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoFaceService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoFaceService.cs index 9bbc8ee3..496a0e32 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoFaceService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoFaceService.cs @@ -1,9 +1,12 @@ using Dlhis.Basic.Device.Services; using Dlhis.Basic.Organization.Request; using Dlhis.Basic.Organization.Response; +using Dlhis.Entity.Basic.Dto; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Basic.Enums; using Dlhis.Entity.Device.Enums; +using Dlhis.InfoCheck.Api; +using Dlhis.InfoCheck.Api.Requests; using Dlhis.Scheduled.Api; using Dlhis.Scheduled.Api.Request; using Kurisu.AspNetCore.Authentication.Abstractions; @@ -26,6 +29,8 @@ public class GainfoFaceService : IGainfoFaceService private readonly ICurrentUser _currentUser; private readonly IHangfireApi _hangfireApi; private readonly IDevicePermissionService _devicePermissionService; + private readonly IFactorySettingService _factorySettingService; + private readonly IInfoCheckApi _infoCheckApi; private readonly IDataProtectionProvider _dataProtectionProvider; public GainfoFaceService(IGainfoStore gainfoStore, @@ -35,6 +40,8 @@ public class GainfoFaceService : IGainfoFaceService ICurrentUser currentUser, IHangfireApi hangfireApi, IDevicePermissionService devicePermissionService, + IFactorySettingService factorySettingService, + IInfoCheckApi infoCheckApi, IDataProtectionProvider dataProtectionProvider) { _gainfoStore = gainfoStore; @@ -45,10 +52,11 @@ public class GainfoFaceService : IGainfoFaceService _currentUser = currentUser; _hangfireApi = hangfireApi; _devicePermissionService = devicePermissionService; + _factorySettingService = factorySettingService; + _infoCheckApi = infoCheckApi; _dataProtectionProvider = dataProtectionProvider; } - public async Task GetPageAsync(GainfoFacePageRequest request) { var factories = request.Factories; @@ -96,11 +104,12 @@ public class GainfoFaceService : IGainfoFaceService var gainfo = await _gainfoStore.Queryable(GainfoStatusEnumType.External) .Where(x => x.IdNo == request.UserNo) - .FirstAsync(); + .SingleAsync(); gainfo ??= await _gainfoStore.Queryable(GainfoStatusEnumType.Working) .Where(x => x.IdNo == request.UserNo) - .FirstAsync(); + .SingleAsync(); + gainfo.ThrowIfNull("人员信息不存在"); var face = await _faceDbContext.Queryable().Where(x => x.UserCode == gainfo.Code).SingleAsync(); @@ -186,25 +195,20 @@ public class GainfoFaceService : IGainfoFaceService public async Task UploadFaceAsync(GainfoUploadFaceRequest request) { - var gainfo = await _gainfoStore.Queryable().Where(x => x.No == request.UserNo).FirstAsync(); + var gainfo = await _gainfoStore.Queryable().Where(x => x.No == request.UserNo || x.Code == request.UserNo).SingleAsync(); gainfo.ThrowIfNull("人员档案信息不存在"); - var userId = _currentUser.GetIntSubjectId(); + await DetectFaceImageQualityAsync(request.Face); var face = await _faceDbContext.Queryable().Where(x => x.UserCode == gainfo.Code).SingleAsync(); var taskType = face == null ? DeviceTaskEnumType.Add : DeviceTaskEnumType.Update; - if (face == null) { face = new GainfoFaceEntity { UserCode = gainfo.Code, - Face = request.Face, - CreateTime = DateTime.Now, - ModifiedTime = DateTime.Now, - CreatedBy = userId, - ModifiedBy = userId + Face = request.Face }; await _faceDbContext.InsertAsync(face); @@ -218,8 +222,6 @@ public class GainfoFaceService : IGainfoFaceService } face.Face = request.Face; - face.ModifiedBy = userId; - face.ModifiedTime = DateTime.Now; await _faceDbContext.UpdateAsync(face); } @@ -236,9 +238,6 @@ public class GainfoFaceService : IGainfoFaceService _logger.LogError(e, "上传face数据到sap失败:{message}", e.Message); } - // var prefix = gainfo.Factory == "501" ? "jschuneng" : "jingke"; - // var url = $"https://pay.aizhuhotel.com/{prefix}/api/face"; - //生成任务 await _devicePermissionService.GenerateDeviceTasksAsync(gainfo.No, taskType, DeviceTaskSourceEnumType.Photo); } @@ -328,4 +327,42 @@ public class GainfoFaceService : IGainfoFaceService return faceDictionary; } + + //********************************************************************************************************************************************* + + /// + /// 人脸质量检测 + /// + /// + /// + /// + private async Task DetectFaceImageQualityAsync(string base64Image, string factory = null) + { + var currentFactory = factory ?? _currentUser.GetStringTenantId(); + var factorySetting = await _factorySettingService.GetFactorySettingAsync(currentFactory); + if (factorySetting.FaceImageDetection.Enable) + { + List r; + + try + { + var result = await _infoCheckApi.FaceDetectAsync(new FaceDetectRequest + { + Base64 = base64Image, + CheckList = factorySetting.FaceImageDetection.Detections.Select(x => new FaceDetectCheckRequest + { + Type = (int)x.Type, + Level = (int)x.Level + }).ToList() + }); + r = result.Data; + } + catch (Exception) + { + return; + } + + r.IsPresent().ThrowIfTrue($"{r.Join("\r\n")}"); + } + } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoOutsourceSettingService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoOutsourceSettingService.cs deleted file mode 100644 index f8f4e151..00000000 --- a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoOutsourceSettingService.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Dlhis.Basic.Device.Services; -using Dlhis.Basic.Organization.Request; -using Dlhis.Entity.Basic.Entity; -using Dlhis.Entity.Sys.Entities; -using Kurisu.AspNetCore.Authentication.Abstractions; -using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; -using Kurisu.AspNetCore.Utils.Extensions; -using SqlSugar; - -namespace Dlhis.Basic.Organization.Services.Implements; - -public class GainfoOutsourceSettingService : IGainfoOutsourceSettingService -{ - private readonly IDbContext _dbContext; - private readonly ICurrentUser _currentUser; - private readonly IDevicePermissionService _devicePermissionService; - - public GainfoOutsourceSettingService(IDbContext dbContext, ICurrentUser currentUser, IDevicePermissionService devicePermissionService) - { - _dbContext = dbContext; - _currentUser = currentUser; - _devicePermissionService = devicePermissionService; - } - - public async Task SaveAsync(GainfoOutsourceSettingSaveRequest request) - { - var userNos = await _dbContext.Queryable() - .Where(x => SqlFunc.Subqueryable().Where(p => p.Code == x.Code).Any()) - .Select(x => x.No) - .ToListAsync(); - - await _devicePermissionService.GenerateDeviceTasksAsync(async () => - { - var currentTenantId = _currentUser.GetStringTenantId(); - - (!request.Id.HasValue && await _dbContext.Queryable() - .Where(x => x.TenantId == currentTenantId) - .AnyAsync()).ThrowIfTrue("保存失败,请检查参数"); - - if (!request.Id.HasValue) - { - var entity = new FactorySettingEntity - { - EnableOutsourceDown = request.EnableFactory, - TenantId = currentTenantId - }; - - await _dbContext.InsertAsync(entity); - } - else - { - var entity = await _dbContext.Queryable().Where(x => x.Id == request.Id).SingleAsync(); - entity.ThrowIfNull("数据不存在,保存失败"); - - entity.EnableOutsourceDown = request.EnableFactory; - - await _dbContext.UpdateAsync(entity); - } - }, userNos); - } - - - public async Task GetSettingAsync() - { - var currentTenantId = _currentUser.GetStringTenantId(); - return await _dbContext.Queryable().Where(x => x.TenantId == currentTenantId).Select(x => new - { - x.Id, EnableFactory = x.EnableOutsourceDown - }).SingleAsync(); - } -} \ No newline at end of file diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoQrCodeService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoQrCodeService.cs index a2f3fc84..55c995ff 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoQrCodeService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoQrCodeService.cs @@ -10,21 +10,26 @@ public class GainfoQrCodeService : IGainfoQrCodeService { private readonly IDbContext _dbContext; private readonly ICurrentUser _currentUser; + private readonly IFactorySettingService _factorySettingService; - public GainfoQrCodeService(IDbContext dbContext, ICurrentUser currentUser) + public GainfoQrCodeService(IDbContext dbContext, ICurrentUser currentUser, IFactorySettingService factorySettingService) { _dbContext = dbContext; _currentUser = currentUser; + _factorySettingService = factorySettingService; } public async Task GetMyQrCodeAsync(bool isNeedRefresh = false) { var jinkoCode = _currentUser.GetUserClaim("jinko-code"); + jinkoCode = "0123456"; if (jinkoCode.IsEmpty()) { return null; } + var factory = _currentUser.GetStringTenantId(); + var now = DateTime.Now; var gainfoQrCode = await _dbContext.Queryable().SingleAsync(x => x.UserCode == jinkoCode); @@ -39,7 +44,8 @@ public class GainfoQrCodeService : IGainfoQrCodeService await _dbContext.InsertAsync(gainfoQrCode); } - if (gainfoQrCode.ModifiedTime.AddMinutes(60) >= now && !isNeedRefresh) + var setting = await _factorySettingService.GetFactorySettingAsync(factory); + if (gainfoQrCode.ModifiedTime.AddMinutes(setting.UserQrCodeExpiration!.Value) >= now && !isNeedRefresh) { return gainfoQrCode.QrCode; } diff --git a/Src/Dlhis.Basic/Program.cs b/Src/Dlhis.Basic/Program.cs index 6bd00925..882db25c 100644 --- a/Src/Dlhis.Basic/Program.cs +++ b/Src/Dlhis.Basic/Program.cs @@ -22,7 +22,6 @@ public class Startup : DefaultStartup public override void ConfigureServices(IServiceCollection services) { base.ConfigureServices(services); - services.AddHttpContextAccessor(); services.AddRedis(); } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/appsettings.Development.json b/Src/Dlhis.Basic/appsettings.Development.json index 8af9df4f..c22992e5 100644 --- a/Src/Dlhis.Basic/appsettings.Development.json +++ b/Src/Dlhis.Basic/appsettings.Development.json @@ -8,7 +8,8 @@ "InternalRequest": { "CommonRequestUrl": "http://localhost:5001", "SysRequestUrl": "http://localhost:5003", - "ScheduledRequestUrl": "http://localhost:5010" + "ScheduledRequestUrl": "http://localhost:5010", + "InfoCheckRequestUrl":"http://localhost:5048" }, "FaceUrlOptions": { "Url": "http://localhost:5002/api/gainfos/face?token=", diff --git a/Src/Dlhis.Basic/appsettings.json b/Src/Dlhis.Basic/appsettings.json index 785906ef..d6137a66 100644 --- a/Src/Dlhis.Basic/appsettings.json +++ b/Src/Dlhis.Basic/appsettings.json @@ -9,7 +9,8 @@ "InternalRequest": { "CommonRequestUrl": "http://common", "SysRequestUrl": "http://sys", - "ScheduledRequestUrl": "http://Scheduled" + "ScheduledRequestUrl": "http://Scheduled", + "InfoCheckRequestUrl": "http://192.168.199.115:5048" }, "FaceUrlOptions": { "Url": "https://yikatong.isawesome.cn/api/basic/gainfos/face?token=", diff --git a/Src/Dlhis.Entity/Basic/Dto/FaceImageDetectionDto.cs b/Src/Dlhis.Entity/Basic/Dto/FaceImageDetectionDto.cs new file mode 100644 index 00000000..3b4c3557 --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Dto/FaceImageDetectionDto.cs @@ -0,0 +1,29 @@ +using Dlhis.Entity.Basic.Enums; + +namespace Dlhis.Entity.Basic.Dto; + +public class FaceImageDetectionDto +{ + /// + /// 开关 + /// + public bool Enable { get; set; } + + /// + /// 检查项 + /// + public List Detections { get; set; } +} + +public class FaceImageDetection +{ + /// + /// 检查类型 + /// + public FaceQualityTypeEnumType Type { get; set; } + + /// + /// 要求登记 + /// + public FaceQualityLevelEnumType Level { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Basic/Enums/FaceQualityLevelEnumType.cs b/Src/Dlhis.Entity/Basic/Enums/FaceQualityLevelEnumType.cs new file mode 100644 index 00000000..4ceb61f8 --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Enums/FaceQualityLevelEnumType.cs @@ -0,0 +1,23 @@ +using System.ComponentModel; + +namespace Dlhis.Entity.Basic.Enums; + +[Description("质量评估等级")] +public enum FaceQualityLevelEnumType +{ + /// 错误 + [Description("错误")] + Error = -1, + + /// 质量差 + [Description("质量差")] + Low = 0, + + /// 质量一般 + [Description("质量一般")] + Medium = 1, + + /// 质量高 + [Description("质量高")] + High = 2 +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Basic/Enums/FaceQualityTypeEnumType.cs b/Src/Dlhis.Entity/Basic/Enums/FaceQualityTypeEnumType.cs new file mode 100644 index 00000000..69d3d5b6 --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Enums/FaceQualityTypeEnumType.cs @@ -0,0 +1,46 @@ +using System.ComponentModel; + +namespace Dlhis.Entity.Basic.Enums; + +/// +/// 人脸照片检测类型 +/// +[Description("人脸照片质量类型类型")] +public enum FaceQualityTypeEnumType +{ + /// + /// 亮度评估 + /// + [Description("亮度")] + Brightness = 0, + + /// + /// 完整度评估 + /// + [Description("完整度")] + Integrity = 2, + + /// + /// 姿态评估(深度) + /// + [Description("姿态")] + PoseEx = 4, + + /// + /// 分辨率评估 + /// + [Description("分辨率")] + Resolution = 5, + + /// + /// 清晰度评估(深度 + /// + [Description("清晰度")] + ClarityEx = 6, + + /// + /// 遮挡评估 + /// + [Description("遮挡")] + Structure = 7 +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Sys/Entities/FactorySettingEntity.cs b/Src/Dlhis.Entity/Sys/Entities/FactorySettingEntity.cs index 2c8abf8e..a3b747ef 100644 --- a/Src/Dlhis.Entity/Sys/Entities/FactorySettingEntity.cs +++ b/Src/Dlhis.Entity/Sys/Entities/FactorySettingEntity.cs @@ -1,3 +1,4 @@ +using Dlhis.Entity.Basic.Dto; using Kurisu.AspNetCore.DataAccess.Entity; using Kurisu.AspNetCore.DataAccess.SqlSugar; using SqlSugar; @@ -28,5 +29,11 @@ public class FactorySettingEntity : SugarBaseEntity, ITenantId [SugarColumn(ColumnDescription = "电子餐券二维码过期时间", IsNullable = true)] public int? EMealVoucherQrCodeExpiration { get; set; } + /// + /// 人脸检测配置 + /// + [SugarColumn(ColumnDescription = "人脸检测配置", IsNullable = true, IsJson = true)] + public FaceImageDetectionDto FaceImageDetection { get; set; } + public string TenantId { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.InfoCheck.Api/Dlhis.InfoCheck.Api.csproj b/Src/Dlhis.InfoCheck.Api/Dlhis.InfoCheck.Api.csproj new file mode 100644 index 00000000..cf75c67b --- /dev/null +++ b/Src/Dlhis.InfoCheck.Api/Dlhis.InfoCheck.Api.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/Src/Dlhis.InfoCheck.Api/IInfoCheckApi.cs b/Src/Dlhis.InfoCheck.Api/IInfoCheckApi.cs new file mode 100644 index 00000000..8a015a57 --- /dev/null +++ b/Src/Dlhis.InfoCheck.Api/IInfoCheckApi.cs @@ -0,0 +1,20 @@ +using Dlhis.InfoCheck.Api.Requests; +using Kurisu.RemoteCall.Attributes; +using Kurisu.RemoteCall.Default; + +namespace Dlhis.InfoCheck.Api; + +/// +/// 信息检查 +/// +[EnableRemoteClient(Name = "infocheck-service", BaseUrl = "${InternalRequest:InfoCheckRequestUrl}")] +public interface IInfoCheckApi +{ + /// + /// 检测人脸质量 + /// + /// + /// + [Post("/api/face/detection")] + Task>> FaceDetectAsync(FaceDetectRequest request); +} \ No newline at end of file diff --git a/Src/Dlhis.InfoCheck.Api/Requests/FaceDetectRequest.cs b/Src/Dlhis.InfoCheck.Api/Requests/FaceDetectRequest.cs new file mode 100644 index 00000000..3d7e3c42 --- /dev/null +++ b/Src/Dlhis.InfoCheck.Api/Requests/FaceDetectRequest.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dlhis.InfoCheck.Api.Requests; + +public class FaceDetectRequest +{ + [Required] + public string Base64 { get; set; } + + public List CheckList { get; set; } +} + +public class FaceDetectCheckRequest +{ + public int Type { get; set; } + public int Level { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.InfoCheck/Controllers/FaceController.cs b/Src/Dlhis.InfoCheck/Controllers/FaceController.cs index 0223f4d7..cf5fd689 100644 --- a/Src/Dlhis.InfoCheck/Controllers/FaceController.cs +++ b/Src/Dlhis.InfoCheck/Controllers/FaceController.cs @@ -2,30 +2,25 @@ using Microsoft.AspNetCore.Mvc; using SkiaSharp; using ViewFaceCore.Core; using ViewFaceCore.Model; -using ViewFaceCore.Exceptions; using ViewFaceCore; using ViewFaceCore.Configs; -using Microsoft.AspNetCore.Authorization; using Dlhis.InfoCheck.Request; using Dlhis.InfoCheck.Response; +using Kurisu.AspNetCore.Utils.Extensions; namespace Dlhis.InfoCheck.Controllers; -/// -/// ÈËÁ³¼ì²â -/// -[Authorize] [ApiController] [Route("api/[controller]")] public class FaceController : ControllerBase { /// - /// ÈËÁ³ÖÊÁ¿¼ì²â + /// 人脸质量检测 /// /// /// [HttpPost("detection")] - public object FacialDetection(FaceDetectRequest request) + public IEnumerable FacialDetection(FaceDetectRequest request) { var base64Bytes = Convert.FromBase64String(request.Base64); using var stream = new MemoryStream(base64Bytes); @@ -37,34 +32,30 @@ public class FaceController : ControllerBase MarkType = MarkType.Light }); - //todo ¶àÈËÇé¿ö var info = faceDetector.Detect(bitmap).First(); var markPoints = faceMark.Mark(bitmap, info); using var faceQuality = new FaceQuality(); - var brightnessResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Brightness); - var resolutionResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Resolution); - //var clarityResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Clarity); - var clarityExResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.ClarityEx); - var integrityExResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Integrity); - var structureeResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Structure); - //var poseResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Pose); - var poseExeResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.PoseEx); + var qualityResult = new List(6); + qualityResult.Add(faceQuality.DetectEx(bitmap, info, markPoints, QualityType.Brightness)); - return new + qualityResult.Add(faceQuality.DetectEx(bitmap, info, markPoints, QualityType.Resolution)); + //var clarityResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Clarity); + qualityResult.Add(faceQuality.DetectEx(bitmap, info, markPoints, QualityType.ClarityEx)); + qualityResult.Add(faceQuality.DetectEx(bitmap, info, markPoints, QualityType.Integrity)); + qualityResult.Add(faceQuality.DetectEx(bitmap, info, markPoints, QualityType.Structure)); + //var poseResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Pose); + qualityResult.Add(faceQuality.DetectEx(bitmap, info, markPoints, QualityType.PoseEx)); + + return request.CheckList.Where(x => { - Brightness = brightnessResult, - Resolution = resolutionResult, - Clarity = clarityExResult, - Integrity = integrityExResult, - Structure = structureeResult, - Pose = poseExeResult - }; + var r = qualityResult.First(item => item.Type == x.Type); + return r.Level < x.Level; + }).Select(x => x.Type.GetDescription().Replace("评估", string.Empty) + "不符合"); } - /// - /// ÈËÁ³¶ԱÈ + /// 图片识别对比 /// /// /// @@ -79,9 +70,7 @@ public class FaceController : ControllerBase using var secondStream = new MemoryStream(secondBase64Bytes); using var secondBitmap = SKBitmap.Decode(secondStream); - //¶ÔӦãÐֵ FaceType.Normal£º0.62¡¢FaceType.Mask£º0.4¡¢FaceType.Light£º0.55 - //FaceType = FaceType.Normal, - using var recognizer = new FaceRecognizer(); + using var recognizer = new FaceRecognizer(new FaceRecognizeConfig()); using var faceDetector = new FaceDetector(); using var faceMark = new FaceLandmarker(); diff --git a/Src/Dlhis.InfoCheck/Dlhis.InfoCheck.csproj b/Src/Dlhis.InfoCheck/Dlhis.InfoCheck.csproj index 3892e1f5..6d17ab49 100644 --- a/Src/Dlhis.InfoCheck/Dlhis.InfoCheck.csproj +++ b/Src/Dlhis.InfoCheck/Dlhis.InfoCheck.csproj @@ -10,7 +10,7 @@ - + diff --git a/Src/Dlhis.InfoCheck/Request/FaceDetectRequest.cs b/Src/Dlhis.InfoCheck/Request/FaceDetectRequest.cs index 5593cc4e..d014709b 100644 --- a/Src/Dlhis.InfoCheck/Request/FaceDetectRequest.cs +++ b/Src/Dlhis.InfoCheck/Request/FaceDetectRequest.cs @@ -1,6 +1,15 @@ -namespace Dlhis.InfoCheck.Request; +using ViewFaceCore.Model; + +namespace Dlhis.InfoCheck.Request; public class FaceDetectRequest { public string Base64 { get; set; } + public List CheckList { get; set; } } + +public class FaceDetectCheckRequest +{ + public QualityType Type { get; set; } + public QualityLevel Level { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.InfoCheck/Request/FaceRecognizeRequest.cs b/Src/Dlhis.InfoCheck/Request/FaceRecognizeRequest.cs index 126df29c..bc8ce58d 100644 --- a/Src/Dlhis.InfoCheck/Request/FaceRecognizeRequest.cs +++ b/Src/Dlhis.InfoCheck/Request/FaceRecognizeRequest.cs @@ -2,7 +2,13 @@ public class FaceRecognizeRequest { + /// + /// 第一张图片 + /// public string FirstBase64 { get; set; } + /// + /// 第二张图片 + /// public string SecondBase64 { get; set; } } diff --git a/Src/Dlhis.InfoCheck/Response/FacialDetectionResponse.cs b/Src/Dlhis.InfoCheck/Response/FacialDetectionResponse.cs new file mode 100644 index 00000000..786ec228 --- /dev/null +++ b/Src/Dlhis.InfoCheck/Response/FacialDetectionResponse.cs @@ -0,0 +1,36 @@ +using ViewFaceCore.Model; + +namespace Dlhis.InfoCheck.Response; + +public class FacialDetectionResponse +{ + /// + /// 亮度 + /// + public QualityResult Brightness { get; set; } + + /// + /// 分辨率 + /// + public QualityResult Resolution { get; set; } + + /// + /// 清晰度 + /// + public QualityResult Clarity { get; set; } + + /// + /// 完整度 + /// + public QualityResult Integrity { get; set; } + + /// + /// 遮挡 + /// + public QualityResult Structure { get; set; } + + /// + /// 姿态 + /// + public QualityResult Pose { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.InfoCheck/faceQualityExtensions.cs b/Src/Dlhis.InfoCheck/faceQualityExtensions.cs new file mode 100644 index 00000000..9933fe02 --- /dev/null +++ b/Src/Dlhis.InfoCheck/faceQualityExtensions.cs @@ -0,0 +1,27 @@ +using ViewFaceCore; +using ViewFaceCore.Core; +using ViewFaceCore.Model; + +namespace Dlhis.InfoCheck; + +public class QualityResultEx : QualityResult +{ + public QualityType Type { get; set; } +} + +public static class FaceQualityExtensions +{ + public static QualityResultEx DetectEx(this FaceQuality faceQuality, T image, + FaceInfo info, + FaceMarkPoint[] points, + QualityType type) where T : class + { + var result = faceQuality.Detect(image, info, points, type); + return new QualityResultEx + { + Level = result.Level, + Score = result.Score, + Type = type + }; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Middle/Services/Implements/BalanceRecordCheckBackgroundService.cs b/Src/Dlhis.Middle/Services/Implements/BalanceRecordCheckBackgroundService.cs index 5acade41..99b71a3c 100644 --- a/Src/Dlhis.Middle/Services/Implements/BalanceRecordCheckBackgroundService.cs +++ b/Src/Dlhis.Middle/Services/Implements/BalanceRecordCheckBackgroundService.cs @@ -64,9 +64,6 @@ public class BalanceRecordCheckBackgroundService : BackgroundService await db.Client.Ado.BeginTranAsync(); try { - //设置为已同步 - balanceRecord.IsSync = true; - await db.UpdateAsync(balanceRecord); var r = await UploadAsync(balanceRecord); if (r.Code != ApiStateCode.Success) { @@ -79,7 +76,11 @@ public class BalanceRecordCheckBackgroundService : BackgroundService .SetColumns(x => x.Balance == d.Balance) .Where(x => x.UserCode == d.UserCode) .ExecuteCommandAsync(stoppingToken); - + + //eg:一定要在此处更新为已同步 + balanceRecord.IsSync = true; + await db.UpdateAsync(balanceRecord); + await db.Client.Ado.CommitTranAsync(); } catch (Exception e)