feat 访客强制离场,更新照片

This commit is contained in:
2024-12-16 17:08:33 +08:00
parent f25deabed6
commit 2a49266851
7 changed files with 160 additions and 71 deletions

View File

@@ -61,13 +61,26 @@ public class AppointmentsController : ControllerBase
await _appointmentService.ConfirmAsync(request);
}
[AllowAnonymous]
/// <summary>
/// 强制离场
/// </summary>
/// <param name="request"></param>
[HttpPost("focusleave")]
[Transactional]
public async Task FocusLeaveAsync(AppointmentFocusLeaveRequest request)
{
await _appointmentService.FocusLeaveAsync(request.Id, request.Reason);
}
/// <summary>
/// 人脸更新
/// </summary>
/// <param name="request"></param>
[HttpPost("face/update")]
[Transactional]
[IgnoreTenant]
public async Task GenerateTaskAndUpdateFaceAsync(AppointmentConfirmRequest request)
public async Task UpdateFaceAsync(AppointmentConfirmRequest request)
{
await _appointmentService.GenerateTaskAndUpdateFaceAsync(request.Id, request.Base64Image, DeviceTaskEnumType.Update);
await _appointmentService.UpdateFaceAsync(request.Id, request.Base64Image);
}
/// <summary>

View File

@@ -1,4 +1,6 @@
namespace Dlhis.Basic.Appointment.Request;
using System.ComponentModel.DataAnnotations;
namespace Dlhis.Basic.Appointment.Request;
public class AppointmentConfirmRequest
{
@@ -10,5 +12,6 @@ public class AppointmentConfirmRequest
/// <summary>
/// base64 image
/// </summary>
[Required]
public string Base64Image { get; set; }
}

View File

@@ -0,0 +1,11 @@
using System.ComponentModel.DataAnnotations;
namespace Dlhis.Basic.Appointment.Request;
public class AppointmentFocusLeaveRequest
{
public long Id { get; set; }
[Required(ErrorMessage = "原因不可为空")]
public string Reason { get; set; }
}

View File

@@ -38,6 +38,14 @@ public interface IAppointmentService : IScopeDependency
/// <returns></returns>
Task<AppointmentDetailResponse> GetTodayByIdNoAsync(string idNo, string factory);
/// <summary>
/// 强制离开
/// </summary>
/// <param name="id"></param>
/// <param name="reason"></param>
/// <returns></returns>
Task FocusLeaveAsync(long id, string reason);
/// <summary>
/// 获取记录列表
/// </summary>
@@ -53,5 +61,5 @@ public interface IAppointmentService : IScopeDependency
Task<AppointmentSummaryResponse> GetSummaryAsync(string factory, DateTime start, DateTime end);
Task GenerateTaskAndUpdateFaceAsync(long detailId, string base64, DeviceTaskEnumType deviceTaskType);
Task UpdateFaceAsync(long detailId, string base64);
}

View File

@@ -16,7 +16,6 @@ using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
using Kurisu.AspNetCore.Utils.Extensions;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
namespace Dlhis.Basic.Appointment.Services.Implements;
@@ -97,16 +96,26 @@ public class AppointmentService : IAppointmentService
var detail = await _dbContext.Queryable<VisitorAppointmentDetailEntity>().Where(x => x.Id == request.Id).SingleAsync();
detail.ThrowIfNull("预约信息不存在");
await GenerateTaskAndUpdateFaceAsync(detail.Id, request.Base64Image, DeviceTaskEnumType.Add);
if (detail.DoorStatus == VisitorAppointmentDetailStatusEnumType.Wait)
{
detail.DoorStatus = VisitorAppointmentDetailStatusEnumType.Arrived;
}
else
{
true.ThrowIfTrue($"数据有误:{detail.DoorStatus.GetDescription()}");
}
detail.ArrivedTime = DateTime.Now;
await _dbContext.UpdateAsync(detail);
await _gainfoFaceService.UploadExternalFaceAsync(new GainfoUploadFaceRequest
{
UserNo = detail.IdNo,
Face = request.Base64Image
});
await GenerateDeviceTasksAsync(detail, false, DeviceTaskEnumType.Add);
try
{
await _dhApi.SendFaceAsync(new FaceRequest
@@ -121,53 +130,6 @@ public class AppointmentService : IAppointmentService
}
}
public async Task GenerateTaskAndUpdateFaceAsync(long detailId, string base64, DeviceTaskEnumType deviceTaskType)
{
var detail = await _dbContext.Queryable<VisitorAppointmentDetailEntity>().Where(x => x.Id == detailId).SingleAsync();
detail.ThrowIfNull("预约信息不存在");
var areaCodes = GetValidAreaCodes(detail);
var existsAreaCodes = await _dbContext.Queryable<AppointmentAreaEntity>().Where(x => areaCodes.Contains(x.CustomCode)).Select(x => x.CustomCode).ToListAsync();
//当前分配的设备组code
var deviceGroupCodes = await _dbContext.Queryable<AppointmentAreaAssignmentEntity>()
.Where(x => existsAreaCodes.Contains(x.CustomCode))
.Select(x => x.DeviceGroupCode)
.ToListAsync();
var deviceCodes = await _dbContext.Queryable<DeviceGroupRelationshipEntity>().Where(x => deviceGroupCodes.Contains(x.GroupCode)).Select(x => x.DeviceCode).ToListAsync();
var deviceUniqueNos = await _dbContext.Queryable<DeviceEntity>().Where(x => deviceCodes.Contains(x.Code)).Select(x => new { x.UniqueNo, x.TenantId }).ToListAsync();
await _dbContext.InsertAsync(deviceUniqueNos.Select(x => new DeviceTaskEntity
{
DeviceType = DeviceTypeEnumType.Door,
DeviceUniqueNo = x.UniqueNo,
Status = DeviceTaskStatusEnumType.Wait,
UserNo = detail.UserNo,
Type = deviceTaskType,
Priority = 100,
TenantId = x.TenantId,
Source = DeviceTaskSourceEnumType.Appointment,
Version = 0
}).ToList());
await _gainfoFaceService.UploadExternalFaceAsync(new GainfoUploadFaceRequest
{
UserNo = detail.IdNo,
Face = base64
});
}
private static IEnumerable<string> GetValidAreaCodes(VisitorAppointmentDetailEntity detail)
{
if (detail.IsEnterDoorArea)
{
yield return detail.ApplyDoorArea;
}
}
public async Task<AppointmentDetailResponse> GetTodayByIdNoAsync(string idNo, string factory)
{
var protector = _dataProtectionProvider.CreateProtector("gainfo:external:idno");
@@ -185,7 +147,7 @@ public class AppointmentService : IAppointmentService
.LeftJoin<GainfoEntity>((x, ga) => ga.IdNo == x.IdNo)
.Where((x, ga) => ga.IdNo == idNo)
.Where(x => x.IsEnterDoorArea && now >= x.DoorStart && now <= x.DoorEnd && x.DoorStatus == VisitorAppointmentDetailStatusEnumType.Wait)
.Where(x => SqlFunc.Subqueryable<VisitorAppointmentEntity>().Where(p => p.Factory == factory).Where(p => p.No == x.No).Any())
.Where(x => SqlFunc.Subqueryable<VisitorAppointmentEntity>().Where(p => p.No == x.No).Where(p => p.Factory == factory).Any())
.Select(x => new AppointmentDetailResponse
{
No = x.No,
@@ -208,7 +170,29 @@ public class AppointmentService : IAppointmentService
.FirstAsync();
}
public async Task<Pagination<AppointmentDetailResponse>> GetRecordPageByIdNoAsync([FromQuery] AppointmentIdNoPageRequest request)
public async Task FocusLeaveAsync(long id, string reason)
{
var detail = await _dbContext.Queryable<VisitorAppointmentDetailEntity>().Where(x => x.Id == id).SingleAsync();
detail.ThrowIfNull("数据不存在");
if (detail.IsEnterDoorArea && detail.DoorStatus == VisitorAppointmentDetailStatusEnumType.Arrived)
{
detail.DoorStatus = VisitorAppointmentDetailStatusEnumType.FocusLeave;
}
if (detail.IsEnterWorkplace && detail.WorkplaceStatus == VisitorAppointmentDetailStatusEnumType.Arrived)
{
detail.WorkplaceStatus = VisitorAppointmentDetailStatusEnumType.FocusLeave;
}
detail.FocusLeaveDateTime = DateTime.Now;
detail.Remark += "强制离场原因:" + reason;
await GenerateDeviceTasksAsync(detail, true, DeviceTaskEnumType.Delete);
}
public async Task<Pagination<AppointmentDetailResponse>> GetRecordPageByIdNoAsync(AppointmentIdNoPageRequest request)
{
var protector = _dataProtectionProvider.CreateProtector("gainfo:external:idno");
try
@@ -271,12 +255,10 @@ public class AppointmentService : IAppointmentService
}
/// <inheritdoc />
public async Task<AppointmentSummaryResponse> GetSummaryAsync(string factory, DateTime start, DateTime end)
{
var total = await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
.Where(x => x.IsEnterDoorArea && SqlFunc.DateIsSame(x.DoorStart, start))
//|| (x.IsEnterWorkplace && ((x.WorkplaceStart >= start && x.WorkplaceStart <= end) || (x.WorkplaceEnd >= start && x.WorkplaceEnd <= end)))
.Where(x => SqlFunc.Subqueryable<VisitorAppointmentEntity>().Where(p => p.No == x.No).Where(p => p.Factory == factory).Any())
.CountAsync();
@@ -287,18 +269,13 @@ public class AppointmentService : IAppointmentService
var notIn = await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
.Where(x => x.IsEnterDoorArea && SqlFunc.DateIsSame(x.DoorStart, start))
//|| (x.IsEnterWorkplace && ((x.WorkplaceStart >= start && x.WorkplaceStart <= end) || (x.WorkplaceEnd >= start && x.WorkplaceEnd <= end)))
.Where(x => (x.IsEnterDoorArea && x.DoorStatus == VisitorAppointmentDetailStatusEnumType.Wait)
//|| (x.IsEnterWorkplace && x.WorkplaceStatus == VisitorAppointmentDetailStatusEnumType.Wait)
)
.Where(x => x.IsEnterDoorArea && x.DoorStatus == VisitorAppointmentDetailStatusEnumType.Wait)
.Where(x => SqlFunc.Subqueryable<VisitorAppointmentEntity>().Where(p => p.No == x.No).Where(p => p.Factory == factory).Any())
.CountAsync();
var leave = await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
.Where(x => x.IsEnterDoorArea && SqlFunc.DateIsSame(x.DoorEnd, start))
.Where(x => (x.IsEnterDoorArea && x.DoorStatus == VisitorAppointmentDetailStatusEnumType.Leave)
//|| (x.IsEnterWorkplace && x.WorkplaceStatus == VisitorAppointmentDetailStatusEnumType.Leave)
)
.Where(x => x.IsEnterDoorArea && (x.DoorStatus == VisitorAppointmentDetailStatusEnumType.Leave || x.DoorStatus == VisitorAppointmentDetailStatusEnumType.FocusLeave))
.Where(x => SqlFunc.Subqueryable<VisitorAppointmentEntity>().Where(p => p.No == x.No).Where(p => p.Factory == factory).Any())
.CountAsync();
@@ -316,4 +293,69 @@ public class AppointmentService : IAppointmentService
NotLeave = notLeave
};
}
public async Task UpdateFaceAsync(long detailId, string base64)
{
var detail = await _dbContext.Queryable<VisitorAppointmentDetailEntity>().Where(x => x.Id == detailId).SingleAsync();
detail.ThrowIfNull("数据不存在");
await _gainfoFaceService.UploadExternalFaceAsync(new GainfoUploadFaceRequest
{
UserNo = detail.IdNo,
Face = base64
});
await GenerateDeviceTasksAsync(detail, true, DeviceTaskEnumType.Update);
}
//*********************************************************************************************************************
private async Task GenerateDeviceTasksAsync(VisitorAppointmentDetailEntity detail, bool withWorkplace, DeviceTaskEnumType deviceTaskType)
{
var areaCodes = GetValidAreaCodes(detail, withWorkplace).ToList();
if (areaCodes.Any())
{
var existsAreaCodes = await _dbContext.Queryable<AppointmentAreaEntity>().Where(x => areaCodes.Contains(x.CustomCode)).Select(x => x.CustomCode).ToListAsync();
//当前分配的设备组code
var deviceGroupCodes = await _dbContext.Queryable<AppointmentAreaAssignmentEntity>()
.Where(x => existsAreaCodes.Contains(x.CustomCode))
.Select(x => x.DeviceGroupCode)
.ToListAsync();
var deviceCodes = await _dbContext.Queryable<DeviceGroupRelationshipEntity>().Where(x => deviceGroupCodes.Contains(x.GroupCode)).Select(x => x.DeviceCode).ToListAsync();
var deviceUniqueNos = await _dbContext.Queryable<DeviceEntity>().Where(x => deviceCodes.Contains(x.Code)).Select(x => new { x.UniqueNo, x.TenantId }).ToListAsync();
await _dbContext.InsertAsync(deviceUniqueNos.Select(x => new DeviceTaskEntity
{
DeviceType = DeviceTypeEnumType.Door,
DeviceUniqueNo = x.UniqueNo,
Status = DeviceTaskStatusEnumType.Wait,
UserNo = detail.UserNo,
Type = deviceTaskType,
Priority = 100,
TenantId = x.TenantId,
Source = DeviceTaskSourceEnumType.Appointment,
Version = 0
}).ToList());
}
}
private static IEnumerable<string> GetValidAreaCodes(VisitorAppointmentDetailEntity detail, bool withWorkplace)
{
if (detail.IsEnterDoorArea)
{
yield return detail.ApplyDoorArea;
}
if (withWorkplace && detail.IsEnterWorkplace)
{
foreach (var item in detail.ApplyWorkplaceAreas)
{
yield return item;
}
}
}
}