diff --git a/Src/Dlhis.Basic/Organization/Controllers/GainfoIdCardFaceCompareController.cs b/Src/Dlhis.Basic/Organization/Controllers/GainfoIdCardFaceCompareController.cs new file mode 100644 index 00000000..94a3e27a --- /dev/null +++ b/Src/Dlhis.Basic/Organization/Controllers/GainfoIdCardFaceCompareController.cs @@ -0,0 +1,46 @@ +using Dlhis.Basic.Organization.Request; +using Dlhis.Basic.Organization.Response; +using Dlhis.Basic.Organization.Services; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop; +using Kurisu.AspNetCore.UnifyResultAndValidation.Aop; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Dlhis.Basic.Organization.Controllers; + +/// +/// 人证人脸对比 +/// +[Authorize] +[Route("api/[controller]")] +[ApiController] +public class GainfoIdCardFaceCompareController : ControllerBase +{ + private readonly IGainfoIdCardFaceCompareService _service; + + public GainfoIdCardFaceCompareController(IGainfoIdCardFaceCompareService service) + { + _service = service; + } + + /// + /// 人证人脸对比记录分页 + /// + [DisableApiLog] + [HttpPost("page")] + public async Task> GetPageAsync(IdCardFaceComparePageRequest request) + { + return await _service.GetPageAsync(request); + } + + /// + /// 人证人脸对比 + /// + [HttpPost("compare")] + [Transactional] + public async Task CompareAsync(IdCardFaceCompareRequest request) + { + return await _service.CompareAsync(request); + } +} diff --git a/Src/Dlhis.Basic/Organization/Request/IdCardFaceComparePageRequest.cs b/Src/Dlhis.Basic/Organization/Request/IdCardFaceComparePageRequest.cs new file mode 100644 index 00000000..f61c0b8c --- /dev/null +++ b/Src/Dlhis.Basic/Organization/Request/IdCardFaceComparePageRequest.cs @@ -0,0 +1,22 @@ +using Dlhis.Entity.Basic.Enums; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Basic.Organization.Request; + +public class IdCardFaceComparePageRequest : PageDto +{ + /// + /// 厂区 + /// + public List Factories { get; set; } + + /// + /// 人员类型 + /// + public GainfoUserTypeEnumType? UserType { get; set; } + + /// + /// 对比结果 + /// + public IdCardFaceCompareResultEnumType? CompareResult { get; set; } +} diff --git a/Src/Dlhis.Basic/Organization/Request/IdCardFaceCompareRequest.cs b/Src/Dlhis.Basic/Organization/Request/IdCardFaceCompareRequest.cs new file mode 100644 index 00000000..81574cbd --- /dev/null +++ b/Src/Dlhis.Basic/Organization/Request/IdCardFaceCompareRequest.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dlhis.Basic.Organization.Request; + +public class IdCardFaceCompareRequest +{ + /// + /// 用户code + /// + [Required(ErrorMessage = "用户code不可为空")] + public string UserCode { get; set; } +} diff --git a/Src/Dlhis.Basic/Organization/Response/AliyunId3MetaVerifyResponse.cs b/Src/Dlhis.Basic/Organization/Response/AliyunId3MetaVerifyResponse.cs new file mode 100644 index 00000000..82803563 --- /dev/null +++ b/Src/Dlhis.Basic/Organization/Response/AliyunId3MetaVerifyResponse.cs @@ -0,0 +1,39 @@ +namespace Dlhis.Basic.Organization.Response; + +public class AliyunId3MetaVerifyResponse +{ + /// + /// 请求ID + /// + public string RequestId { get; set; } + + /// + /// 接口调用返回码,200表示接口调用成功 + /// + public string Code { get; set; } + + /// + /// 接口调用返回信息,仅表示接口是否异常 + /// + public string Message { get; set; } + + /// + /// 业务核验结果,1一致、2不一致、3查无记录 + /// + public string BizCode { get; set; } + + /// + /// 业务核验是否通过,来源于BizCode + /// + public bool? Passed { get; set; } + + /// + /// 人像比对分值,来源于FaceDetail.verifyScore,可能为空 + /// + public double? Similarity { get; set; } + + /// + /// 阿里云原始响应 + /// + public string RawResponse { get; set; } +} diff --git a/Src/Dlhis.Basic/Organization/Response/IdCardFaceCompareRecordResponse.cs b/Src/Dlhis.Basic/Organization/Response/IdCardFaceCompareRecordResponse.cs new file mode 100644 index 00000000..f32e5be1 --- /dev/null +++ b/Src/Dlhis.Basic/Organization/Response/IdCardFaceCompareRecordResponse.cs @@ -0,0 +1,81 @@ +using Dlhis.Entity.Basic.Enums; + +namespace Dlhis.Basic.Organization.Response; + +public class IdCardFaceCompareRecordResponse +{ + /// + /// 记录ID + /// + public long Id { get; set; } + + /// + /// 用户code + /// + public string UserCode { get; set; } + + /// + /// 姓名 + /// + public string UserName { get; set; } + + /// + /// 人员类型 + /// + public GainfoUserTypeEnumType UserType { get; set; } + + /// + /// 证件号 + /// + public string IdNo { get; set; } + + /// + /// 部门名称 + /// + public string DepartmentName { get; set; } + + /// + /// 厂区 + /// + public string Factory { get; set; } + + /// + /// 对比结果 + /// + public IdCardFaceCompareResultEnumType CompareResult { get; set; } + + /// + /// 业务核验是否通过,来源于阿里云ResultObject.BizCode + /// + public bool? IsPassed { get; set; } + + /// + /// 人像比对分值,来源于阿里云ResultObject.FaceDetail.verifyScore,可能为空 + /// + public double? Similarity { get; set; } + + /// + /// 当前用户累计对比次数 + /// + public int CompareCount { get; set; } + + /// + /// 最近对比时间 + /// + public DateTime? LastCompareTime { get; set; } + + /// + /// 阿里云原始响应 + /// + public string ApiResponse { get; set; } + + /// + /// 对比异常信息 + /// + public string ErrorMessage { get; set; } + + /// + /// 记录创建时间 + /// + public DateTime CreateTime { get; set; } +} diff --git a/Src/Dlhis.Basic/Organization/Services/IAliyunClient.cs b/Src/Dlhis.Basic/Organization/Services/IAliyunClient.cs new file mode 100644 index 00000000..3ee539f4 --- /dev/null +++ b/Src/Dlhis.Basic/Organization/Services/IAliyunClient.cs @@ -0,0 +1,218 @@ +using System.Security.Cryptography; +using System.Text; +using Dlhis.Basic.Organization.Response; +using Kurisu.AspNetCore.CustomClass; +using Newtonsoft.Json; + +namespace Dlhis.Basic.Organization.Services; + +public interface IAliyunClient : IScopeDependency +{ + Task Id3MetaVerifyAsync( + string identifyNum, + string userName, + string faceBase64, + string crop = "F"); +} + +public class AliyunClient : IAliyunClient +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly IConfiguration _configuration; + private readonly string _accessKeyId; + private readonly string _accessKeySecret; + + private const string Endpoint = "cloudauth.aliyuncs.com"; + private const string ApiVersion = "2019-03-07"; + + public AliyunClient(IHttpClientFactory httpClientFactory, IConfiguration configuration, ILogger logger) + { + _httpClientFactory = httpClientFactory; + _configuration = configuration; + } + + public AliyunClient(string accessKeyId, string accessKeySecret) + { + _accessKeyId = accessKeyId ?? "LTAI5tAqyWKcBcSvzpc1ZM72"; + _accessKeySecret = accessKeySecret ?? "YZMSqsmMGlGZuHw5WU2tqt0mmIBX6h"; + } + + /// + /// 使用 Base64 图片进行三要素核验 + /// + public async Task Id3MetaVerifyAsync( + string identifyNum, + string userName, + string faceBase64, + string crop = "F") + { + var accessKeyId = _accessKeyId ?? GetRequiredConfig("AliyunOptions:AccessKeyId", "Aliyun:AccessKeyId"); + var accessKeySecret = _accessKeySecret ?? GetRequiredConfig("AliyunOptions:AccessKeySecret", "Aliyun:AccessKeySecret"); + + if (faceBase64.Contains(",")) + { + faceBase64 = faceBase64[(faceBase64.IndexOf(',') + 1)..]; + } + + var parameters = new SortedDictionary + { + { "Action", "Id3MetaVerify" }, + { "Format", "JSON" }, + { "Version", ApiVersion }, + { "AccessKeyId", accessKeyId }, + { "SignatureMethod", "HMAC-SHA1" }, + { "SignatureVersion", "1.0" }, + { "SignatureNonce", Guid.NewGuid().ToString("N") }, + { "Timestamp", DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ") }, + { "ParamType", "normal" }, + { "IdentifyNum", identifyNum }, + { "UserName", userName }, + { "FacePicture", faceBase64 }, + { "Crop", crop } + }; + + var signature = ComputeSignature(parameters, "POST", accessKeySecret); + var url = $"https://{Endpoint}/?Signature={PercentEncode(signature)}"; + var bodyString = BuildBodyString(parameters); + + using var fallbackClient = _httpClientFactory == null ? new HttpClient() : null; + var client = _httpClientFactory?.CreateClient() ?? fallbackClient; + client.DefaultRequestHeaders.Add("Host", Endpoint); + var content = new StringContent(bodyString, Encoding.UTF8, "application/x-www-form-urlencoded"); + var response = await client.PostAsync(url, content); + var rawResponse = await response.Content.ReadAsStringAsync(); + + return ParseResponse(rawResponse); + } + + private string GetRequiredConfig(params string[] keys) + { + foreach (var key in keys) + { + var value = _configuration.GetSection(key).Value; + if (!string.IsNullOrWhiteSpace(value)) + { + return value; + } + } + + throw new UserFriendlyException($"阿里云配置缺失:{string.Join("或", keys)}"); + } + + private static AliyunId3MetaVerifyResponse ParseResponse(string rawResponse) + { + var result = new AliyunId3MetaVerifyResponse + { + RawResponse = rawResponse + }; + + if (string.IsNullOrWhiteSpace(rawResponse)) + { + return result; + } + + try + { + var response = JsonConvert.DeserializeObject(rawResponse); + result.RequestId = response?.RequestId; + result.Code = response?.Code; + result.Message = response?.Message; + result.BizCode = response?.ResultObject?.BizCode; + result.Similarity = ParseVerifyScore(response?.ResultObject?.FaceDetail); + result.Passed = response?.ResultObject?.BizCode switch + { + "1" => true, + "2" or "3" => false, + _ => null + }; + } + catch + { + result.Message = "阿里云响应不是合法JSON"; + } + + return result; + } + + private static double? ParseVerifyScore(string faceDetail) + { + if (string.IsNullOrWhiteSpace(faceDetail)) + { + return null; + } + + var detail = JsonConvert.DeserializeObject(faceDetail); + return detail?.VerifyScore; + } + + private static string ComputeSignature(SortedDictionary parameters, string httpMethod, string accessKeySecret) + { + var canonicalized = new StringBuilder(); + foreach (var kv in parameters) + { + if (kv.Key == "Signature") + { + continue; + } + + if (canonicalized.Length > 0) + { + canonicalized.Append('&'); + } + + canonicalized.Append(PercentEncode(kv.Key)) + .Append('=') + .Append(PercentEncode(kv.Value)); + } + + var stringToSign = httpMethod + "&" + PercentEncode("/") + "&" + PercentEncode(canonicalized.ToString()); + var signKey = accessKeySecret + "&"; + using var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(signKey)); + var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)); + return Convert.ToBase64String(hash); + } + + private static string BuildBodyString(SortedDictionary parameters) + { + return string.Join("&", parameters + .Where(x => x.Key != "Signature") + .Select(x => PercentEncode(x.Key) + "=" + PercentEncode(x.Value))); + } + + private static string PercentEncode(string value) + { + if (string.IsNullOrEmpty(value)) + { + return string.Empty; + } + + return Uri.EscapeDataString(value) + .Replace("+", "%20") + .Replace("*", "%2A") + .Replace("%7E", "~"); + } + + private class AliyunId3MetaVerifyApiResponse + { + public string RequestId { get; set; } + + public string Message { get; set; } + + public string Code { get; set; } + + public AliyunId3MetaVerifyResultObject ResultObject { get; set; } + } + + private class AliyunId3MetaVerifyResultObject + { + public string BizCode { get; set; } + + public string FaceDetail { get; set; } + } + + private class AliyunId3MetaVerifyFaceDetail + { + [JsonProperty("verifyScore")] + public double? VerifyScore { get; set; } + } +} diff --git a/Src/Dlhis.Basic/Organization/Services/IGainfoIdCardFaceCompareService.cs b/Src/Dlhis.Basic/Organization/Services/IGainfoIdCardFaceCompareService.cs new file mode 100644 index 00000000..307860a1 --- /dev/null +++ b/Src/Dlhis.Basic/Organization/Services/IGainfoIdCardFaceCompareService.cs @@ -0,0 +1,22 @@ +using Dlhis.Basic.Organization.Request; +using Dlhis.Basic.Organization.Response; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Basic.Organization.Services; + +public interface IGainfoIdCardFaceCompareService : IScopeDependency +{ + /// + /// 人证人脸对比记录分页查询 + /// + /// 分页查询条件 + /// 人证人脸对比记录分页结果 + Task> GetPageAsync(IdCardFaceComparePageRequest request); + + /// + /// 执行人证人脸对比 + /// + /// 人证人脸对比请求 + /// 人证人脸对比记录 + Task CompareAsync(IdCardFaceCompareRequest request); +} diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoIdCardFaceCompareService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoIdCardFaceCompareService.cs new file mode 100644 index 00000000..90170693 --- /dev/null +++ b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoIdCardFaceCompareService.cs @@ -0,0 +1,191 @@ +using Dlhis.Basic.Organization.Request; +using Dlhis.Basic.Organization.Response; +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Basic.Enums; +using Kurisu.AspNetCore.Authentication.Abstractions; +using Kurisu.AspNetCore.CustomClass; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.Utils.Extensions; +using SqlSugar; + +namespace Dlhis.Basic.Organization.Services.Implements; + +public class GainfoIdCardFaceCompareService : IGainfoIdCardFaceCompareService +{ + private readonly IDbContext _dbContext; + private readonly IDbContext _faceDbContext; + private readonly IAliyunClient _aliyunClient; + private readonly ICurrentUser _currentUser; + + public GainfoIdCardFaceCompareService( + IDbContext dbContext, + IAliyunClient aliyunClient, + ICurrentUser currentUser) + { + _dbContext = dbContext; + _faceDbContext = dbContext.ChangeDb("face"); + _aliyunClient = aliyunClient; + _currentUser = currentUser; + } + + public async Task> GetPageAsync(IdCardFaceComparePageRequest request) + { + var factories = GetFactories(request.Factories); + + return await _dbContext.Queryable() + .LeftJoin((record, gainfo) => record.UserCode == gainfo.Code) + .LeftJoin((record, gainfo, department) => gainfo.DepartmentNo == department.No) + .WhereIF(factories.Any(), (record, gainfo) => factories.Contains(gainfo.Factory)) + .WhereIF(request.UserType.HasValue, record => record.UserType == request.UserType.Value) + .WhereIF(request.CompareResult.HasValue, record => record.CompareResult == request.CompareResult.Value) + .WhereIF(request.Search.IsPresent(), (record, gainfo) => + record.UserCode == request.Search + || record.IdNo == request.Search + || record.UserName.Contains(request.Search) + || gainfo.Name.Contains(request.Search)) + .OrderBy(record => record.CreateTime, OrderByType.Desc) + .Select((record, gainfo, department) => new IdCardFaceCompareRecordResponse + { + Id = record.Id, + UserCode = record.UserCode, + UserName = record.UserName, + UserType = record.UserType, + IdNo = record.IdNo, + DepartmentName = department.Name, + Factory = gainfo.Factory, + CompareResult = record.CompareResult, + IsPassed = record.IsPassed, + Similarity = record.Similarity, + CompareCount = record.CompareCount, + LastCompareTime = record.LastCompareTime, + ApiResponse = record.ApiResponse, + ErrorMessage = record.ErrorMessage, + CreateTime = record.CreateTime + }) + .ToPageListAsync(request); + } + + public async Task CompareAsync(IdCardFaceCompareRequest request) + { + var gainfo = await _dbContext.Queryable() + .Where(x => x.Code == request.UserCode) + .SingleAsync(); + gainfo.ThrowIfNull("人员档案信息不存在"); + gainfo.IdNo.IsPresent().ThrowIfFalse("人员证件号为空,无法对比"); + + var now = DateTime.Now; + var userId = _currentUser.GetIntSubjectId(); + var record = await _dbContext.Queryable() + .Where(x => x.UserCode == gainfo.Code) + .SingleAsync(); + + if (record == null) + { + record = new IdCardFaceCompareRecordEntity + { + UserCode = gainfo.Code, + UserType = gainfo.Type, + UserName = gainfo.Name, + IdNo = gainfo.IdNo, + CompareResult = IdCardFaceCompareResultEnumType.NotCompared, + CompareCount = 0, + CreateTime = now, + ModifiedTime = now, + CreatedBy = userId, + ModifiedBy = userId + }; + + await _dbContext.InsertAsync(record); + } + else + { + record.UserType = gainfo.Type; + record.UserName = gainfo.Name; + record.IdNo = gainfo.IdNo; + record.CompareResult = IdCardFaceCompareResultEnumType.NotCompared; + record.ErrorMessage = null; + record.ModifiedTime = now; + record.ModifiedBy = userId; + await _dbContext.UpdateAsync(record); + } + + var face = await _faceDbContext.Queryable() + .Where(x => x.UserCode == gainfo.Code) + .Select(x => x.Face) + .SingleAsync(); + + if (!face.IsPresent()) + { + record.ErrorMessage = "人脸照片尚未录入"; + record.ModifiedTime = DateTime.Now; + record.ModifiedBy = userId; + await _dbContext.UpdateAsync(record); + throw new UserFriendlyException(record.ErrorMessage); + } + + try + { + var response = await _aliyunClient.Id3MetaVerifyAsync(gainfo.IdNo, gainfo.Name, face); + record.CompareResult = IdCardFaceCompareResultEnumType.Compared; + record.ApiResponse = response.RawResponse; + record.IsPassed = response.Passed; + record.Similarity = response.Similarity; + record.CompareCount += 1; + record.LastCompareTime = now; + record.ModifiedTime = DateTime.Now; + record.ModifiedBy = userId; + } + catch (Exception ex) + { + record.ErrorMessage = ex.Message; + record.ModifiedTime = DateTime.Now; + record.ModifiedBy = userId; + await _dbContext.UpdateAsync(record); + throw; + } + + await _dbContext.UpdateAsync(record); + + return await GetRecordAsync(record.Id); + } + + private async Task GetRecordAsync(long id) + { + return await _dbContext.Queryable() + .LeftJoin((record, gainfo) => record.UserCode == gainfo.Code) + .LeftJoin((record, gainfo, department) => gainfo.DepartmentNo == department.No) + .Where(record => record.Id == id) + .Select((record, gainfo, department) => new IdCardFaceCompareRecordResponse + { + Id = record.Id, + UserCode = record.UserCode, + UserName = record.UserName, + UserType = record.UserType, + IdNo = record.IdNo, + DepartmentName = department.Name, + Factory = gainfo.Factory, + CompareResult = record.CompareResult, + IsPassed = record.IsPassed, + Similarity = record.Similarity, + CompareCount = record.CompareCount, + LastCompareTime = record.LastCompareTime, + ApiResponse = record.ApiResponse, + ErrorMessage = record.ErrorMessage, + CreateTime = record.CreateTime + }) + .SingleAsync(); + } + + private List GetFactories(List requestFactories) + { + var currentFactories = _currentUser.GetUserClaim("tenants")?.Split(",").Where(x => x.IsPresent()).ToList() ?? new List(); + if (requestFactories == null || !requestFactories.Any()) + { + return currentFactories; + } + + return requestFactories.Where(x => currentFactories.Contains(x)).ToList(); + } +} diff --git a/Src/Dlhis.Entity/Basic/Entity/IdCardFaceCompareRecordEntity.cs b/Src/Dlhis.Entity/Basic/Entity/IdCardFaceCompareRecordEntity.cs new file mode 100644 index 00000000..436021c7 --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Entity/IdCardFaceCompareRecordEntity.cs @@ -0,0 +1,79 @@ +using Dlhis.Entity.Basic.Enums; +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using SqlSugar; +using SqlSugar.DbConvert; + +namespace Dlhis.Entity.Basic.Entity; + +/// +/// 人证人脸对比记录 +/// +[SugarTable(TableName = "IdCardFaceCompareRecord", TableDescription = "人证人脸对比记录表")] +public class IdCardFaceCompareRecordEntity : SugarBaseEntity +{ + /// + /// 用户code + /// + [SugarColumn(IsNullable = false, ColumnDescription = "用户code", UniqueGroupNameList = new[] { "idx_IdCardFaceCompareRecord_UserCode" })] + public string UserCode { get; set; } + + /// + /// 人员类型 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "人员类型", ColumnDataType = "varchar(50)", SqlParameterDbType = typeof(EnumToStringConvert))] + public GainfoUserTypeEnumType UserType { get; set; } + + /// + /// 姓名 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "姓名")] + public string UserName { get; set; } + + /// + /// 证件号 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "证件号", UniqueGroupNameList = new[] { "idx_IdCardFaceCompareRecord_IdNo" })] + public string IdNo { get; set; } + + /// + /// 对比结果 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "对比结果", ColumnDataType = "varchar(50)", SqlParameterDbType = typeof(EnumToStringConvert))] + public IdCardFaceCompareResultEnumType CompareResult { get; set; } + + /// + /// api响应结果 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "api响应结果", ColumnDataType = "longtext")] + public string ApiResponse { get; set; } + + /// + /// 是否通过 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "是否通过", ColumnDataType = "bit")] + public bool? IsPassed { get; set; } + + /// + /// 相似度 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "相似度")] + public double? Similarity { get; set; } + + /// + /// 对比次数 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "对比次数")] + public int CompareCount { get; set; } + + /// + /// 最近对比时间 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "最近对比时间")] + public DateTime? LastCompareTime { get; set; } + + /// + /// 错误消息 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "错误消息", ColumnDataType = "text")] + public string ErrorMessage { get; set; } +} diff --git a/Src/Dlhis.Entity/Basic/Enums/IdCardFaceCompareResultEnumType.cs b/Src/Dlhis.Entity/Basic/Enums/IdCardFaceCompareResultEnumType.cs new file mode 100644 index 00000000..9e624c91 --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Enums/IdCardFaceCompareResultEnumType.cs @@ -0,0 +1,22 @@ +using System.ComponentModel; + +namespace Dlhis.Entity.Basic.Enums; + +/// +/// 人证人脸对比结果 +/// +[Description("人证人脸对比结果")] +public enum IdCardFaceCompareResultEnumType +{ + /// + /// 未对比 + /// + [Description("未对比")] + NotCompared = 0, + + /// + /// 已对比 + /// + [Description("已对比")] + Compared = 1 +}