feat 人脸检测

This commit is contained in:
2024-08-26 15:08:30 +08:00
parent f80d36c9b2
commit 7493e5a3a3
29 changed files with 422 additions and 205 deletions

View File

@@ -51,6 +51,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.Middle", "Src\Dlhis.M
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.DataPermission.Model", "Src\Dlhis.DataPermission.Model\Dlhis.DataPermission.Model.csproj", "{CA1427E2-CC70-4489-8653-1C05630C8392}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.DataPermission.Model", "Src\Dlhis.DataPermission.Model\Dlhis.DataPermission.Model.csproj", "{CA1427E2-CC70-4489-8653-1C05630C8392}"
EndProject 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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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}.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.ActiveCfg = Release|Any CPU
{CA1427E2-CC70-4489-8653-1C05630C8392}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -148,6 +154,7 @@ Global
{69E8A91A-5D05-4327-BC24-038523C7628C} = {489252FB-A44B-46EE-B065-21CDCB724441} {69E8A91A-5D05-4327-BC24-038523C7628C} = {489252FB-A44B-46EE-B065-21CDCB724441}
{053BF7B2-B1A0-435F-9C77-2EF5622CC5C5} = {65E76F97-E78A-4C95-B788-4091236B1A79} {053BF7B2-B1A0-435F-9C77-2EF5622CC5C5} = {65E76F97-E78A-4C95-B788-4091236B1A79}
{4D656761-8CE7-4316-A3DF-8C1722D69CCE} = {4EBCE46B-CE3A-4A47-9432-82A1854CA58A} {4D656761-8CE7-4316-A3DF-8C1722D69CCE} = {4EBCE46B-CE3A-4A47-9432-82A1854CA58A}
{A501D16E-638F-4156-989C-2BACCC2FAC2B} = {4EBCE46B-CE3A-4A47-9432-82A1854CA58A}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7439494A-E2FD-4FEA-8ABF-74AE57A4A5A0} SolutionGuid = {7439494A-E2FD-4FEA-8ABF-74AE57A4A5A0}

View File

@@ -25,6 +25,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Dlhis.Entity\Dlhis.Entity.csproj" /> <ProjectReference Include="..\Dlhis.Entity\Dlhis.Entity.csproj" />
<ProjectReference Include="..\Dlhis.InfoCheck.Api\Dlhis.InfoCheck.Api.csproj" />
<ProjectReference Include="..\Dlhis.Scheduled.Api\Dlhis.Scheduled.Api.csproj" /> <ProjectReference Include="..\Dlhis.Scheduled.Api\Dlhis.Scheduled.Api.csproj" />
<ProjectReference Include="..\Dlhis.Sys.Api\Dlhis.Sys.Api.csproj" /> <ProjectReference Include="..\Dlhis.Sys.Api\Dlhis.Sys.Api.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -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.Response;
using Dlhis.Basic.Organization.Services; using Dlhis.Basic.Organization.Services;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop; using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop;
@@ -43,4 +44,15 @@ public class FactorySettingController : ControllerBase
{ {
await _factorySettingService.SaveAsync(request); await _factorySettingService.SaveAsync(request);
} }
/// <summary>
/// 根据factory获取配置
/// </summary>
/// <param name="factory"></param>
/// <returns></returns>
[HttpGet("single")]
public async Task<FactorySettingResponse> GetFactorySettingAsync([Required(ErrorMessage = "厂区不可为空")] string factory)
{
return await _factorySettingService.GetFactorySettingAsync(factory);
}
} }

View File

@@ -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;
/// <summary>
/// 外包人员配置
/// </summary>
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class GainfoOutsourceSettingController : ControllerBase
{
private readonly IGainfoOutsourceSettingService _gainfoOutSourceService;
public GainfoOutsourceSettingController(IGainfoOutsourceSettingService gainfoOutSourceService)
{
_gainfoOutSourceService = gainfoOutSourceService;
}
/// <summary>
/// 保存配置
/// </summary>
/// <param name="request"></param>
[HttpPost("save")]
[AssignPermissionLimit]
[Transactional]
[CrossTenant]
public async Task SaveAsync(GainfoOutsourceSettingSaveRequest request)
{
await _gainfoOutSourceService.SaveAsync(request);
}
/// <summary>
/// 获取当前厂区配置
/// </summary>
/// <returns></returns>
[HttpGet("current")]
public async Task<object> GetSettingAsync()
{
return await _gainfoOutSourceService.GetSettingAsync();
}
}

View File

@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Dlhis.Entity.Basic.Dto;
namespace Dlhis.Basic.Organization.Request; namespace Dlhis.Basic.Organization.Request;
@@ -16,4 +17,9 @@ public class FactorySettingSaveRequest
/// 档案二维码过期时间 /// 档案二维码过期时间
/// </summary> /// </summary>
public int? UserQrCodeExpiration { get; set; } public int? UserQrCodeExpiration { get; set; }
/// <summary>
/// 人脸检测配置
/// </summary>
public FaceImageDetectionDto FaceImageDetection { get; set; }
} }

View File

@@ -1,3 +1,5 @@
using Dlhis.Entity.Basic.Dto;
namespace Dlhis.Basic.Organization.Response; namespace Dlhis.Basic.Organization.Response;
public class FactorySettingResponse public class FactorySettingResponse
@@ -15,4 +17,9 @@ public class FactorySettingResponse
/// 档案二维码过期时间 /// 档案二维码过期时间
/// </summary> /// </summary>
public int? UserQrCodeExpiration { get; set; } public int? UserQrCodeExpiration { get; set; }
/// <summary>
/// 人脸检测
/// </summary>
public FaceImageDetectionDto FaceImageDetection { get; set; }
} }

View File

@@ -8,4 +8,6 @@ public interface IFactorySettingService : IScopeDependency
Task<List<FactorySettingResponse>> GetListAsync(); Task<List<FactorySettingResponse>> GetListAsync();
Task SaveAsync(FactorySettingSaveRequest request); Task SaveAsync(FactorySettingSaveRequest request);
Task<FactorySettingResponse> GetFactorySettingAsync(string factory);
} }

View File

@@ -1,10 +0,0 @@
using Dlhis.Basic.Organization.Request;
namespace Dlhis.Basic.Organization.Services;
public interface IGainfoOutsourceSettingService : IScopeDependency
{
Task SaveAsync(GainfoOutsourceSettingSaveRequest request);
Task<object> GetSettingAsync();
}

View File

@@ -1,8 +1,13 @@
using System.Reflection;
using Dlhis.Basic.Organization.Request; using Dlhis.Basic.Organization.Request;
using Dlhis.Basic.Organization.Response; using Dlhis.Basic.Organization.Response;
using Dlhis.Entity.Basic.Dto;
using Dlhis.Entity.Basic.Enums;
using Dlhis.Entity.Sys.Entities; using Dlhis.Entity.Sys.Entities;
using Dlhis.Sys.Api; using Dlhis.Sys.Api;
using Dlhis.Sys.Api.Response;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
using Kurisu.AspNetCore.Utils.Extensions;
using Mapster; using Mapster;
namespace Dlhis.Basic.Organization.Services.Implements; namespace Dlhis.Basic.Organization.Services.Implements;
@@ -20,24 +25,7 @@ public class FactorySettingService : IFactorySettingService
public async Task<List<FactorySettingResponse>> GetListAsync() public async Task<List<FactorySettingResponse>> GetListAsync()
{ {
var apiResult = await _tenantApi.GetMyTenantsAsync(); return await GetFactorySettingsAsync();
var factories = apiResult.Data;
var factoryCodes = factories.Select(x => x.Code).ToList();
var settings = await _dbContext.Queryable<FactorySettingEntity>().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();
} }
public async Task SaveAsync(FactorySettingSaveRequest request) public async Task SaveAsync(FactorySettingSaveRequest request)
@@ -58,4 +46,60 @@ public class FactorySettingService : IFactorySettingService
await _dbContext.UpdateAsync(setting); await _dbContext.UpdateAsync(setting);
} }
} }
public async Task<FactorySettingResponse> 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<FaceQualityTypeEnumType>(x!.GetValue(null)!.ToString()!),
Level = FaceQualityLevelEnumType.Medium
}).ToList()
};
return setting;
}
//************************************************************************************************************************************************************
private async Task<List<FactorySettingResponse>> GetFactorySettingsAsync(string factory = null)
{
List<TenantResponse> factories;
if (factory.IsPresent())
{
factories = new List<TenantResponse> { 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<FactorySettingEntity>()
.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();
}
} }

View File

@@ -1,9 +1,12 @@
using Dlhis.Basic.Device.Services; using Dlhis.Basic.Device.Services;
using Dlhis.Basic.Organization.Request; using Dlhis.Basic.Organization.Request;
using Dlhis.Basic.Organization.Response; using Dlhis.Basic.Organization.Response;
using Dlhis.Entity.Basic.Dto;
using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Basic.Enums; using Dlhis.Entity.Basic.Enums;
using Dlhis.Entity.Device.Enums; using Dlhis.Entity.Device.Enums;
using Dlhis.InfoCheck.Api;
using Dlhis.InfoCheck.Api.Requests;
using Dlhis.Scheduled.Api; using Dlhis.Scheduled.Api;
using Dlhis.Scheduled.Api.Request; using Dlhis.Scheduled.Api.Request;
using Kurisu.AspNetCore.Authentication.Abstractions; using Kurisu.AspNetCore.Authentication.Abstractions;
@@ -26,6 +29,8 @@ public class GainfoFaceService : IGainfoFaceService
private readonly ICurrentUser _currentUser; private readonly ICurrentUser _currentUser;
private readonly IHangfireApi _hangfireApi; private readonly IHangfireApi _hangfireApi;
private readonly IDevicePermissionService _devicePermissionService; private readonly IDevicePermissionService _devicePermissionService;
private readonly IFactorySettingService _factorySettingService;
private readonly IInfoCheckApi _infoCheckApi;
private readonly IDataProtectionProvider _dataProtectionProvider; private readonly IDataProtectionProvider _dataProtectionProvider;
public GainfoFaceService(IGainfoStore gainfoStore, public GainfoFaceService(IGainfoStore gainfoStore,
@@ -35,6 +40,8 @@ public class GainfoFaceService : IGainfoFaceService
ICurrentUser currentUser, ICurrentUser currentUser,
IHangfireApi hangfireApi, IHangfireApi hangfireApi,
IDevicePermissionService devicePermissionService, IDevicePermissionService devicePermissionService,
IFactorySettingService factorySettingService,
IInfoCheckApi infoCheckApi,
IDataProtectionProvider dataProtectionProvider) IDataProtectionProvider dataProtectionProvider)
{ {
_gainfoStore = gainfoStore; _gainfoStore = gainfoStore;
@@ -45,10 +52,11 @@ public class GainfoFaceService : IGainfoFaceService
_currentUser = currentUser; _currentUser = currentUser;
_hangfireApi = hangfireApi; _hangfireApi = hangfireApi;
_devicePermissionService = devicePermissionService; _devicePermissionService = devicePermissionService;
_factorySettingService = factorySettingService;
_infoCheckApi = infoCheckApi;
_dataProtectionProvider = dataProtectionProvider; _dataProtectionProvider = dataProtectionProvider;
} }
public async Task<GainfoFacePageSummaryResponse> GetPageAsync(GainfoFacePageRequest request) public async Task<GainfoFacePageSummaryResponse> GetPageAsync(GainfoFacePageRequest request)
{ {
var factories = request.Factories; var factories = request.Factories;
@@ -96,11 +104,12 @@ public class GainfoFaceService : IGainfoFaceService
var gainfo = await _gainfoStore.Queryable(GainfoStatusEnumType.External) var gainfo = await _gainfoStore.Queryable(GainfoStatusEnumType.External)
.Where(x => x.IdNo == request.UserNo) .Where(x => x.IdNo == request.UserNo)
.FirstAsync(); .SingleAsync();
gainfo ??= await _gainfoStore.Queryable(GainfoStatusEnumType.Working) gainfo ??= await _gainfoStore.Queryable(GainfoStatusEnumType.Working)
.Where(x => x.IdNo == request.UserNo) .Where(x => x.IdNo == request.UserNo)
.FirstAsync(); .SingleAsync();
gainfo.ThrowIfNull("人员信息不存在"); gainfo.ThrowIfNull("人员信息不存在");
var face = await _faceDbContext.Queryable<GainfoFaceEntity>().Where(x => x.UserCode == gainfo.Code).SingleAsync(); var face = await _faceDbContext.Queryable<GainfoFaceEntity>().Where(x => x.UserCode == gainfo.Code).SingleAsync();
@@ -186,25 +195,20 @@ public class GainfoFaceService : IGainfoFaceService
public async Task UploadFaceAsync(GainfoUploadFaceRequest request) 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("人员档案信息不存在"); gainfo.ThrowIfNull("人员档案信息不存在");
var userId = _currentUser.GetIntSubjectId(); await DetectFaceImageQualityAsync(request.Face);
var face = await _faceDbContext.Queryable<GainfoFaceEntity>().Where(x => x.UserCode == gainfo.Code).SingleAsync(); var face = await _faceDbContext.Queryable<GainfoFaceEntity>().Where(x => x.UserCode == gainfo.Code).SingleAsync();
var taskType = face == null ? DeviceTaskEnumType.Add : DeviceTaskEnumType.Update; var taskType = face == null ? DeviceTaskEnumType.Add : DeviceTaskEnumType.Update;
if (face == null) if (face == null)
{ {
face = new GainfoFaceEntity face = new GainfoFaceEntity
{ {
UserCode = gainfo.Code, UserCode = gainfo.Code,
Face = request.Face, Face = request.Face
CreateTime = DateTime.Now,
ModifiedTime = DateTime.Now,
CreatedBy = userId,
ModifiedBy = userId
}; };
await _faceDbContext.InsertAsync(face); await _faceDbContext.InsertAsync(face);
@@ -218,8 +222,6 @@ public class GainfoFaceService : IGainfoFaceService
} }
face.Face = request.Face; face.Face = request.Face;
face.ModifiedBy = userId;
face.ModifiedTime = DateTime.Now;
await _faceDbContext.UpdateAsync(face); await _faceDbContext.UpdateAsync(face);
} }
@@ -236,9 +238,6 @@ public class GainfoFaceService : IGainfoFaceService
_logger.LogError(e, "上传face数据到sap失败:{message}", e.Message); _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); await _devicePermissionService.GenerateDeviceTasksAsync(gainfo.No, taskType, DeviceTaskSourceEnumType.Photo);
} }
@@ -328,4 +327,42 @@ public class GainfoFaceService : IGainfoFaceService
return faceDictionary; return faceDictionary;
} }
//*********************************************************************************************************************************************
/// <summary>
/// 人脸质量检测
/// </summary>
/// <param name="base64Image"></param>
/// <param name="factory"></param>
/// <exception cref="UserFriendlyException"></exception>
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<string> 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")}");
}
}
} }

View File

@@ -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<GainfoEntity>()
.Where(x => SqlFunc.Subqueryable<OutsourceEntity>().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<FactorySettingEntity>()
.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<FactorySettingEntity>().Where(x => x.Id == request.Id).SingleAsync();
entity.ThrowIfNull("数据不存在,保存失败");
entity.EnableOutsourceDown = request.EnableFactory;
await _dbContext.UpdateAsync(entity);
}
}, userNos);
}
public async Task<object> GetSettingAsync()
{
var currentTenantId = _currentUser.GetStringTenantId();
return await _dbContext.Queryable<FactorySettingEntity>().Where(x => x.TenantId == currentTenantId).Select(x => new
{
x.Id, EnableFactory = x.EnableOutsourceDown
}).SingleAsync();
}
}

View File

@@ -10,21 +10,26 @@ public class GainfoQrCodeService : IGainfoQrCodeService
{ {
private readonly IDbContext _dbContext; private readonly IDbContext _dbContext;
private readonly ICurrentUser _currentUser; private readonly ICurrentUser _currentUser;
private readonly IFactorySettingService _factorySettingService;
public GainfoQrCodeService(IDbContext dbContext, ICurrentUser currentUser) public GainfoQrCodeService(IDbContext dbContext, ICurrentUser currentUser, IFactorySettingService factorySettingService)
{ {
_dbContext = dbContext; _dbContext = dbContext;
_currentUser = currentUser; _currentUser = currentUser;
_factorySettingService = factorySettingService;
} }
public async Task<string> GetMyQrCodeAsync(bool isNeedRefresh = false) public async Task<string> GetMyQrCodeAsync(bool isNeedRefresh = false)
{ {
var jinkoCode = _currentUser.GetUserClaim("jinko-code"); var jinkoCode = _currentUser.GetUserClaim("jinko-code");
jinkoCode = "0123456";
if (jinkoCode.IsEmpty()) if (jinkoCode.IsEmpty())
{ {
return null; return null;
} }
var factory = _currentUser.GetStringTenantId();
var now = DateTime.Now; var now = DateTime.Now;
var gainfoQrCode = await _dbContext.Queryable<GainfoQrCodeEntity>().SingleAsync(x => x.UserCode == jinkoCode); var gainfoQrCode = await _dbContext.Queryable<GainfoQrCodeEntity>().SingleAsync(x => x.UserCode == jinkoCode);
@@ -39,7 +44,8 @@ public class GainfoQrCodeService : IGainfoQrCodeService
await _dbContext.InsertAsync(gainfoQrCode); 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; return gainfoQrCode.QrCode;
} }

View File

@@ -22,7 +22,6 @@ public class Startup : DefaultStartup
public override void ConfigureServices(IServiceCollection services) public override void ConfigureServices(IServiceCollection services)
{ {
base.ConfigureServices(services); base.ConfigureServices(services);
services.AddHttpContextAccessor();
services.AddRedis(); services.AddRedis();
} }
} }

View File

@@ -8,7 +8,8 @@
"InternalRequest": { "InternalRequest": {
"CommonRequestUrl": "http://localhost:5001", "CommonRequestUrl": "http://localhost:5001",
"SysRequestUrl": "http://localhost:5003", "SysRequestUrl": "http://localhost:5003",
"ScheduledRequestUrl": "http://localhost:5010" "ScheduledRequestUrl": "http://localhost:5010",
"InfoCheckRequestUrl":"http://localhost:5048"
}, },
"FaceUrlOptions": { "FaceUrlOptions": {
"Url": "http://localhost:5002/api/gainfos/face?token=", "Url": "http://localhost:5002/api/gainfos/face?token=",

View File

@@ -9,7 +9,8 @@
"InternalRequest": { "InternalRequest": {
"CommonRequestUrl": "http://common", "CommonRequestUrl": "http://common",
"SysRequestUrl": "http://sys", "SysRequestUrl": "http://sys",
"ScheduledRequestUrl": "http://Scheduled" "ScheduledRequestUrl": "http://Scheduled",
"InfoCheckRequestUrl": "http://192.168.199.115:5048"
}, },
"FaceUrlOptions": { "FaceUrlOptions": {
"Url": "https://yikatong.isawesome.cn/api/basic/gainfos/face?token=", "Url": "https://yikatong.isawesome.cn/api/basic/gainfos/face?token=",

View File

@@ -0,0 +1,29 @@
using Dlhis.Entity.Basic.Enums;
namespace Dlhis.Entity.Basic.Dto;
public class FaceImageDetectionDto
{
/// <summary>
/// 开关
/// </summary>
public bool Enable { get; set; }
/// <summary>
/// 检查项
/// </summary>
public List<FaceImageDetection> Detections { get; set; }
}
public class FaceImageDetection
{
/// <summary>
/// 检查类型
/// </summary>
public FaceQualityTypeEnumType Type { get; set; }
/// <summary>
/// 要求登记
/// </summary>
public FaceQualityLevelEnumType Level { get; set; }
}

View File

@@ -0,0 +1,23 @@
using System.ComponentModel;
namespace Dlhis.Entity.Basic.Enums;
[Description("质量评估等级")]
public enum FaceQualityLevelEnumType
{
/// <summary>错误</summary>
[Description("错误")]
Error = -1,
/// <summary>质量差</summary>
[Description("质量差")]
Low = 0,
/// <summary>质量一般</summary>
[Description("质量一般")]
Medium = 1,
/// <summary>质量高</summary>
[Description("质量高")]
High = 2
}

View File

@@ -0,0 +1,46 @@
using System.ComponentModel;
namespace Dlhis.Entity.Basic.Enums;
/// <summary>
/// 人脸照片检测类型
/// </summary>
[Description("人脸照片质量类型类型")]
public enum FaceQualityTypeEnumType
{
/// <summary>
/// 亮度评估
/// </summary>
[Description("亮度")]
Brightness = 0,
/// <summary>
/// 完整度评估
/// </summary>
[Description("完整度")]
Integrity = 2,
/// <summary>
/// 姿态评估(深度)
/// </summary>
[Description("姿态")]
PoseEx = 4,
/// <summary>
/// 分辨率评估
/// </summary>
[Description("分辨率")]
Resolution = 5,
/// <summary>
/// 清晰度评估(深度
/// </summary>
[Description("清晰度")]
ClarityEx = 6,
/// <summary>
/// 遮挡评估
/// </summary>
[Description("遮挡")]
Structure = 7
}

View File

@@ -1,3 +1,4 @@
using Dlhis.Entity.Basic.Dto;
using Kurisu.AspNetCore.DataAccess.Entity; using Kurisu.AspNetCore.DataAccess.Entity;
using Kurisu.AspNetCore.DataAccess.SqlSugar; using Kurisu.AspNetCore.DataAccess.SqlSugar;
using SqlSugar; using SqlSugar;
@@ -28,5 +29,11 @@ public class FactorySettingEntity : SugarBaseEntity, ITenantId
[SugarColumn(ColumnDescription = "电子餐券二维码过期时间", IsNullable = true)] [SugarColumn(ColumnDescription = "电子餐券二维码过期时间", IsNullable = true)]
public int? EMealVoucherQrCodeExpiration { get; set; } public int? EMealVoucherQrCodeExpiration { get; set; }
/// <summary>
/// 人脸检测配置
/// </summary>
[SugarColumn(ColumnDescription = "人脸检测配置", IsNullable = true, IsJson = true)]
public FaceImageDetectionDto FaceImageDetection { get; set; }
public string TenantId { get; set; } public string TenantId { get; set; }
} }

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Kurisu.RemoteCall" Version="0.4.2" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,20 @@
using Dlhis.InfoCheck.Api.Requests;
using Kurisu.RemoteCall.Attributes;
using Kurisu.RemoteCall.Default;
namespace Dlhis.InfoCheck.Api;
/// <summary>
/// 信息检查
/// </summary>
[EnableRemoteClient(Name = "infocheck-service", BaseUrl = "${InternalRequest:InfoCheckRequestUrl}")]
public interface IInfoCheckApi
{
/// <summary>
/// 检测人脸质量
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[Post("/api/face/detection")]
Task<DefaultApiResult<List<string>>> FaceDetectAsync(FaceDetectRequest request);
}

View File

@@ -0,0 +1,17 @@
using System.ComponentModel.DataAnnotations;
namespace Dlhis.InfoCheck.Api.Requests;
public class FaceDetectRequest
{
[Required]
public string Base64 { get; set; }
public List<FaceDetectCheckRequest> CheckList { get; set; }
}
public class FaceDetectCheckRequest
{
public int Type { get; set; }
public int Level { get; set; }
}

View File

@@ -2,30 +2,25 @@ using Microsoft.AspNetCore.Mvc;
using SkiaSharp; using SkiaSharp;
using ViewFaceCore.Core; using ViewFaceCore.Core;
using ViewFaceCore.Model; using ViewFaceCore.Model;
using ViewFaceCore.Exceptions;
using ViewFaceCore; using ViewFaceCore;
using ViewFaceCore.Configs; using ViewFaceCore.Configs;
using Microsoft.AspNetCore.Authorization;
using Dlhis.InfoCheck.Request; using Dlhis.InfoCheck.Request;
using Dlhis.InfoCheck.Response; using Dlhis.InfoCheck.Response;
using Kurisu.AspNetCore.Utils.Extensions;
namespace Dlhis.InfoCheck.Controllers; namespace Dlhis.InfoCheck.Controllers;
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
[Authorize]
[ApiController] [ApiController]
[Route("api/[controller]")] [Route("api/[controller]")]
public class FaceController : ControllerBase public class FaceController : ControllerBase
{ {
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 人脸质量检测
/// </summary> /// </summary>
/// <param name="request"></param> /// <param name="request"></param>
/// <returns></returns> /// <returns></returns>
[HttpPost("detection")] [HttpPost("detection")]
public object FacialDetection(FaceDetectRequest request) public IEnumerable<string> FacialDetection(FaceDetectRequest request)
{ {
var base64Bytes = Convert.FromBase64String(request.Base64); var base64Bytes = Convert.FromBase64String(request.Base64);
using var stream = new MemoryStream(base64Bytes); using var stream = new MemoryStream(base64Bytes);
@@ -37,34 +32,30 @@ public class FaceController : ControllerBase
MarkType = MarkType.Light MarkType = MarkType.Light
}); });
//todo <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
var info = faceDetector.Detect(bitmap).First(); var info = faceDetector.Detect(bitmap).First();
var markPoints = faceMark.Mark(bitmap, info); var markPoints = faceMark.Mark(bitmap, info);
using var faceQuality = new FaceQuality(); using var faceQuality = new FaceQuality();
var brightnessResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Brightness); var qualityResult = new List<QualityResultEx>(6);
var resolutionResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Resolution); qualityResult.Add(faceQuality.DetectEx(bitmap, info, markPoints, QualityType.Brightness));
//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);
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, var r = qualityResult.First(item => item.Type == x.Type);
Resolution = resolutionResult, return r.Level < x.Level;
Clarity = clarityExResult, }).Select(x => x.Type.GetDescription().Replace("评估", string.Empty) + "不符合");
Integrity = integrityExResult,
Structure = structureeResult,
Pose = poseExeResult
};
} }
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ա<EFBFBD> /// 图片识别对比
/// </summary> /// </summary>
/// <param name="request"></param> /// <param name="request"></param>
/// <returns></returns> /// <returns></returns>
@@ -79,9 +70,7 @@ public class FaceController : ControllerBase
using var secondStream = new MemoryStream(secondBase64Bytes); using var secondStream = new MemoryStream(secondBase64Bytes);
using var secondBitmap = SKBitmap.Decode(secondStream); using var secondBitmap = SKBitmap.Decode(secondStream);
//<2F><>Ӧ<EFBFBD><D3A6>ֵ FaceType.Normal<61><6C>0.62<EFBFBD><EFBFBD>FaceType.Mask<73><6B>0.4<EFBFBD><EFBFBD>FaceType.Light<68><74>0.55 using var recognizer = new FaceRecognizer(new FaceRecognizeConfig());
//FaceType = FaceType.Normal,
using var recognizer = new FaceRecognizer();
using var faceDetector = new FaceDetector(); using var faceDetector = new FaceDetector();
using var faceMark = new FaceLandmarker(); using var faceMark = new FaceLandmarker();

View File

@@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Kurisu.AspNetCore" Version="0.9.11" /> <PackageReference Include="Kurisu.AspNetCore" Version="0.9.25" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.0" /> <PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.0" />
<PackageReference Include="ViewFaceCore" Version="0.3.8" /> <PackageReference Include="ViewFaceCore" Version="0.3.8" />
<PackageReference Include="ViewFaceCore.all_models" Version="6.0.7" /> <PackageReference Include="ViewFaceCore.all_models" Version="6.0.7" />

View File

@@ -1,6 +1,15 @@
namespace Dlhis.InfoCheck.Request; using ViewFaceCore.Model;
namespace Dlhis.InfoCheck.Request;
public class FaceDetectRequest public class FaceDetectRequest
{ {
public string Base64 { get; set; } public string Base64 { get; set; }
public List<FaceDetectCheckRequest> CheckList { get; set; }
}
public class FaceDetectCheckRequest
{
public QualityType Type { get; set; }
public QualityLevel Level { get; set; }
} }

View File

@@ -2,7 +2,13 @@
public class FaceRecognizeRequest public class FaceRecognizeRequest
{ {
/// <summary>
/// 第一张图片
/// </summary>
public string FirstBase64 { get; set; } public string FirstBase64 { get; set; }
/// <summary>
/// 第二张图片
/// </summary>
public string SecondBase64 { get; set; } public string SecondBase64 { get; set; }
} }

View File

@@ -0,0 +1,36 @@
using ViewFaceCore.Model;
namespace Dlhis.InfoCheck.Response;
public class FacialDetectionResponse
{
/// <summary>
/// 亮度
/// </summary>
public QualityResult Brightness { get; set; }
/// <summary>
/// 分辨率
/// </summary>
public QualityResult Resolution { get; set; }
/// <summary>
/// 清晰度
/// </summary>
public QualityResult Clarity { get; set; }
/// <summary>
/// 完整度
/// </summary>
public QualityResult Integrity { get; set; }
/// <summary>
/// 遮挡
/// </summary>
public QualityResult Structure { get; set; }
/// <summary>
/// 姿态
/// </summary>
public QualityResult Pose { get; set; }
}

View File

@@ -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<T>(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
};
}
}

View File

@@ -64,9 +64,6 @@ public class BalanceRecordCheckBackgroundService : BackgroundService
await db.Client.Ado.BeginTranAsync(); await db.Client.Ado.BeginTranAsync();
try try
{ {
//设置为已同步
balanceRecord.IsSync = true;
await db.UpdateAsync(balanceRecord);
var r = await UploadAsync(balanceRecord); var r = await UploadAsync(balanceRecord);
if (r.Code != ApiStateCode.Success) if (r.Code != ApiStateCode.Success)
{ {
@@ -80,6 +77,10 @@ public class BalanceRecordCheckBackgroundService : BackgroundService
.Where(x => x.UserCode == d.UserCode) .Where(x => x.UserCode == d.UserCode)
.ExecuteCommandAsync(stoppingToken); .ExecuteCommandAsync(stoppingToken);
//eg:一定要在此处更新为已同步
balanceRecord.IsSync = true;
await db.UpdateAsync(balanceRecord);
await db.Client.Ado.CommitTranAsync(); await db.Client.Ado.CommitTranAsync();
} }
catch (Exception e) catch (Exception e)