From 2a4926685157bbbc5f24df445b45f654dda65a79 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Mon, 16 Dec 2024 17:08:33 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E8=AE=BF=E5=AE=A2=E5=BC=BA=E5=88=B6?= =?UTF-8?q?=E7=A6=BB=E5=9C=BA,=E6=9B=B4=E6=96=B0=E7=85=A7=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/AppointmentsController.cs | 21 ++- .../Request/AppointmentConfirmRequest.cs | 5 +- .../Request/AppointmentFocusLeaveRequest.cs | 11 ++ .../Services/IAppointmentService.cs | 10 +- .../Services/Implements/AppointmentService.cs | 164 +++++++++++------- .../Entity/VisitorAppointmentDetailEntity.cs | 6 + .../VisitorAppointmentDetailStatusEnumType.cs | 14 +- 7 files changed, 160 insertions(+), 71 deletions(-) create mode 100644 Src/Dlhis.Basic/Appointment/Request/AppointmentFocusLeaveRequest.cs diff --git a/Src/Dlhis.Basic/Appointment/Controllers/AppointmentsController.cs b/Src/Dlhis.Basic/Appointment/Controllers/AppointmentsController.cs index bd78cd22..3d6c1a5d 100644 --- a/Src/Dlhis.Basic/Appointment/Controllers/AppointmentsController.cs +++ b/Src/Dlhis.Basic/Appointment/Controllers/AppointmentsController.cs @@ -61,13 +61,26 @@ public class AppointmentsController : ControllerBase await _appointmentService.ConfirmAsync(request); } - [AllowAnonymous] + /// + /// 强制离场 + /// + /// + [HttpPost("focusleave")] + [Transactional] + public async Task FocusLeaveAsync(AppointmentFocusLeaveRequest request) + { + await _appointmentService.FocusLeaveAsync(request.Id, request.Reason); + } + + /// + /// 人脸更新 + /// + /// [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); } /// diff --git a/Src/Dlhis.Basic/Appointment/Request/AppointmentConfirmRequest.cs b/Src/Dlhis.Basic/Appointment/Request/AppointmentConfirmRequest.cs index 8c3c207a..d8ae9054 100644 --- a/Src/Dlhis.Basic/Appointment/Request/AppointmentConfirmRequest.cs +++ b/Src/Dlhis.Basic/Appointment/Request/AppointmentConfirmRequest.cs @@ -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 /// /// base64 image /// + [Required] public string Base64Image { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/Appointment/Request/AppointmentFocusLeaveRequest.cs b/Src/Dlhis.Basic/Appointment/Request/AppointmentFocusLeaveRequest.cs new file mode 100644 index 00000000..b367bba7 --- /dev/null +++ b/Src/Dlhis.Basic/Appointment/Request/AppointmentFocusLeaveRequest.cs @@ -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; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/Appointment/Services/IAppointmentService.cs b/Src/Dlhis.Basic/Appointment/Services/IAppointmentService.cs index 11780c93..7c037ee7 100644 --- a/Src/Dlhis.Basic/Appointment/Services/IAppointmentService.cs +++ b/Src/Dlhis.Basic/Appointment/Services/IAppointmentService.cs @@ -38,6 +38,14 @@ public interface IAppointmentService : IScopeDependency /// Task GetTodayByIdNoAsync(string idNo, string factory); + /// + /// 强制离开 + /// + /// + /// + /// + Task FocusLeaveAsync(long id, string reason); + /// /// 获取记录列表 /// @@ -53,5 +61,5 @@ public interface IAppointmentService : IScopeDependency Task GetSummaryAsync(string factory, DateTime start, DateTime end); - Task GenerateTaskAndUpdateFaceAsync(long detailId, string base64, DeviceTaskEnumType deviceTaskType); + Task UpdateFaceAsync(long detailId, string base64); } \ No newline at end of file diff --git a/Src/Dlhis.Basic/Appointment/Services/Implements/AppointmentService.cs b/Src/Dlhis.Basic/Appointment/Services/Implements/AppointmentService.cs index 3ab01224..171d178f 100644 --- a/Src/Dlhis.Basic/Appointment/Services/Implements/AppointmentService.cs +++ b/Src/Dlhis.Basic/Appointment/Services/Implements/AppointmentService.cs @@ -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().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().Where(x => x.Id == detailId).SingleAsync(); - detail.ThrowIfNull("预约信息不存在"); - - var areaCodes = GetValidAreaCodes(detail); - var existsAreaCodes = await _dbContext.Queryable().Where(x => areaCodes.Contains(x.CustomCode)).Select(x => x.CustomCode).ToListAsync(); - - //当前分配的设备组code - var deviceGroupCodes = await _dbContext.Queryable() - .Where(x => existsAreaCodes.Contains(x.CustomCode)) - .Select(x => x.DeviceGroupCode) - .ToListAsync(); - - var deviceCodes = await _dbContext.Queryable().Where(x => deviceGroupCodes.Contains(x.GroupCode)).Select(x => x.DeviceCode).ToListAsync(); - var deviceUniqueNos = await _dbContext.Queryable().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 GetValidAreaCodes(VisitorAppointmentDetailEntity detail) - { - if (detail.IsEnterDoorArea) - { - yield return detail.ApplyDoorArea; - } - } - - public async Task GetTodayByIdNoAsync(string idNo, string factory) { var protector = _dataProtectionProvider.CreateProtector("gainfo:external:idno"); @@ -185,7 +147,7 @@ public class AppointmentService : IAppointmentService .LeftJoin((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().Where(p => p.Factory == factory).Where(p => p.No == x.No).Any()) + .Where(x => SqlFunc.Subqueryable().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> GetRecordPageByIdNoAsync([FromQuery] AppointmentIdNoPageRequest request) + + public async Task FocusLeaveAsync(long id, string reason) + { + var detail = await _dbContext.Queryable().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> GetRecordPageByIdNoAsync(AppointmentIdNoPageRequest request) { var protector = _dataProtectionProvider.CreateProtector("gainfo:external:idno"); try @@ -271,12 +255,10 @@ public class AppointmentService : IAppointmentService } - /// public async Task GetSummaryAsync(string factory, DateTime start, DateTime end) { var total = await _dbContext.Queryable() .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().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() .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().Where(p => p.No == x.No).Where(p => p.Factory == factory).Any()) .CountAsync(); var leave = await _dbContext.Queryable() .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().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().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().Where(x => areaCodes.Contains(x.CustomCode)).Select(x => x.CustomCode).ToListAsync(); + + //当前分配的设备组code + var deviceGroupCodes = await _dbContext.Queryable() + .Where(x => existsAreaCodes.Contains(x.CustomCode)) + .Select(x => x.DeviceGroupCode) + .ToListAsync(); + + var deviceCodes = await _dbContext.Queryable().Where(x => deviceGroupCodes.Contains(x.GroupCode)).Select(x => x.DeviceCode).ToListAsync(); + var deviceUniqueNos = await _dbContext.Queryable().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 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; + } + } + } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Visitor/Entity/VisitorAppointmentDetailEntity.cs b/Src/Dlhis.Entity/Visitor/Entity/VisitorAppointmentDetailEntity.cs index ff797d36..bf94af3f 100644 --- a/Src/Dlhis.Entity/Visitor/Entity/VisitorAppointmentDetailEntity.cs +++ b/Src/Dlhis.Entity/Visitor/Entity/VisitorAppointmentDetailEntity.cs @@ -117,6 +117,12 @@ public class VisitorAppointmentDetailEntity : SugarBaseEntity /// [SugarColumn(IsNullable = true)] public DateTime? ArrivedTime { get; set; } + + /// + /// 强制离场时间 + /// + [SugarColumn(IsNullable = true)] + public DateTime? FocusLeaveDateTime { get; set; } /// /// 车间状态 diff --git a/Src/Dlhis.Entity/Visitor/Enums/VisitorAppointmentDetailStatusEnumType.cs b/Src/Dlhis.Entity/Visitor/Enums/VisitorAppointmentDetailStatusEnumType.cs index d89e45e1..46202b22 100644 --- a/Src/Dlhis.Entity/Visitor/Enums/VisitorAppointmentDetailStatusEnumType.cs +++ b/Src/Dlhis.Entity/Visitor/Enums/VisitorAppointmentDetailStatusEnumType.cs @@ -25,7 +25,7 @@ public enum VisitorAppointmentDetailStatusEnumType /// [Description("到达")] Arrived = 10, - + /// /// 离开 /// @@ -33,8 +33,14 @@ public enum VisitorAppointmentDetailStatusEnumType Leave = 11, /// - /// 作废 + /// 强制离场 /// - [Description("作废")] + [Description("强制离场")] + FocusLeave = 12, + + /// + /// 未预约 + /// + [Description("未预约")] Obsolete = 99 -} +} \ No newline at end of file