From f8d1997ddd1946d29acff0ac4b823f883b30fce8 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Wed, 17 Apr 2024 15:38:25 +0800 Subject: [PATCH] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 528cdd51c05d26437f0b23f415e06311b667e9f7 Author: liguoyang Date: Wed Apr 17 15:37:30 2024 +0800 feat 访客预约 commit e73a3fcd9307f86aba2c39578495c03cde1d41f9 Author: liguoyang Date: Tue Apr 16 16:15:16 2024 +0800 feat 业务curd commit b98b6e2764fea875866e11f790f388ccf3c234b5 Merge: a3dcec3 965e84b Author: liguoyang Date: Tue Apr 16 14:56:30 2024 +0800 Merge branch 'feat-visitorAppointments' of https://git.dlhis.com/liguoyang/jinko.yikatong into feat-visitorAppointments commit a3dcec30e1289fbb09de8f85009d3931d971337a Author: liguoyang Date: Fri Apr 12 17:57:49 2024 +0800 fix appsettings commit 766fbec0c45a3852a75a7a37686b885ac3b0a77a Author: liguoyang Date: Fri Apr 12 17:37:01 2024 +0800 add dockerfile commit 86731d41fee97ba073065ed1b807987760a371a7 Author: liguoyang Date: Sun Apr 14 20:11:56 2024 +0800 fix 测试websocket链接 commit 1301b126a9ba9a7d97cf45967cf2915e1169c505 Author: liguoyang Date: Fri Apr 12 17:57:49 2024 +0800 fix appsettings commit 081f3a67896c67891c3f80edde82a440b8736851 Author: liguoyang Date: Fri Apr 12 17:37:01 2024 +0800 add dockerfile commit 271b6c5898b5732a35ccfa0629ce89442ac49143 Author: liguoyang Date: Fri Apr 12 17:34:26 2024 +0800 test 提交测试代码 commit 965e84b6f3b7f925f8021c9b996cce961b896dea Merge: 578eb6a 6a6fad1 Author: liguoyang Date: Mon Apr 15 17:06:45 2024 +0800 Merge branch 'feat-visitorAppointments' of https://git.dlhis.com/liguoyang/jinko.yikatong into feat-visitorAppointments commit 578eb6afbd96f0bfe4aaf8058fd4743309c74d62 Author: liguoyang Date: Sun Apr 14 20:11:56 2024 +0800 fix 测试websocket链接 commit 114511f1daea64b7dbf9c3c38b73e28b6d0301e6 Author: liguoyang Date: Fri Apr 12 17:57:49 2024 +0800 fix appsettings commit 5eacfa8af8087eade8553266a12a2cf42305716b Author: liguoyang Date: Fri Apr 12 17:37:01 2024 +0800 add dockerfile commit b2ffff1f099be343d89690014d05cb859776acbb Author: liguoyang Date: Fri Apr 12 17:34:26 2024 +0800 test 提交测试代码 commit 6a6fad1d1b8772eebf5df12cd74cfd5c955ff560 Author: liguoyang Date: Sun Apr 14 20:11:56 2024 +0800 fix 测试websocket链接 commit 9ce3c4d6f63957c175d65370d9a6b80e10f4254f Author: liguoyang Date: Fri Apr 12 17:57:49 2024 +0800 fix appsettings commit c637fd89850cf289d7da457c6c6f47354b5beed3 Author: liguoyang Date: Fri Apr 12 17:37:01 2024 +0800 add dockerfile commit 58c39815b1c45a99aea0caf503fcb1365c957f03 Author: liguoyang Date: Fri Apr 12 17:34:26 2024 +0800 test 提交测试代码 --- Dlhis.Jinko.Face.sln | 18 +- Src/Dlhis.Basic.Api/Dlhis.Basic.Api.csproj | 4 - Src/Dlhis.Basic.Api/IDeviceGroupApi.cs | 20 + .../Response/DeviceUnderGroupResponse.cs | 21 + .../Controllers/DeviceGroupsController.cs | 10 + Src/Dlhis.Basic/Device/Dtos/IPPortDto.cs | 8 - .../Device/Request/DeviceGroupSaveRequest.cs | 18 +- .../Device/Response/DeviceGroupResponse.cs | 19 + .../Device/Services/IDeviceGroupService.cs | 2 + .../Implements/DeviceConnectService.cs | 3 +- .../Services/Implements/DeviceGroupService.cs | 37 +- .../Controllers/GainfoFacesController.cs | 32 -- .../Controllers/GainfosController.cs | 39 +- .../Request/GainfoCheckIdNoAndNameRequest.cs | 19 + .../Organization/Services/IGainfoService.cs | 10 +- .../Services/Implements/GainfoService.cs | 111 +---- Src/Dlhis.Basic/Packs/SqlSugarPack.cs | 4 +- Src/Dlhis.Basic/appsettings.Development.json | 1 - Src/Dlhis.Entity/Basic/Entity/GainfoEntity.cs | 20 +- .../Device/Entities/DeviceGroupEntity.cs | 6 + .../Device/Entities/DeviceTaskEntity.cs | 6 +- Src/Dlhis.Entity/Dlhis.Entity.csproj | 4 - .../Entity/AppointmentAreaAssignmentEntity.cs | 28 ++ .../Visitor/Entity/AppointmentAreaEntity.cs | 54 +++ .../Visitor/Entity/ApponintmentAreaEntity.cs | 44 ++ .../Entity/VisitorAppointmentDetailEntity.cs | 73 +++ .../Entity/VisitorAppointmentEntity.cs | 30 ++ .../Visitor/Enums/AppointmentAreaEnumType.cs | 22 + .../Enums/AppointmentDetailEnumType.cs | 35 ++ .../Visitor/Enums/ApponintmentAreaEnumType.cs | 19 + .../Enums/VisitorAppointmentDetailEnumType.cs | 22 + .../Controllers/AppointmentPushController.cs | 26 ++ Src/Dlhis.Message/Dlhis.Message.csproj | 16 + Src/Dlhis.Message/Dockerfile | 23 + Src/Dlhis.Message/Packs/SignalRPack.cs | 22 + Src/Dlhis.Message/Program.cs | 20 + .../Properties/launchSettings.json | 15 + .../Services/IVisitorAppointmentService.cs | 6 + Src/Dlhis.Message/TestBackgroundService.cs | 26 ++ Src/Dlhis.Message/VisitorAppointmentHub.cs | 19 + .../appsettings.Development.json | 25 + Src/Dlhis.Message/appsettings.json | 72 +++ Src/Dlhis.ScheduledTask/BaseJob.cs | 4 +- .../TaskAssignment/Dto/TaskDto.cs | 25 + .../Services/Implements/AssignmentService.cs | 436 +++++++++--------- .../Controllers/AppointmentsController.cs | 84 ++++ .../ApponintmentAreasController.cs | 68 +++ .../Dto/AppointmentReceiveItemDto.cs | 31 ++ .../Request/AppointmentAreaAssignRequest.cs | 18 + .../Request/AppointmentAreaSaveRequest.cs | 35 ++ .../Request/AppointmentConfirmRequest.cs | 6 + .../Request/AppointmentIdNoPageRequest.cs | 14 + .../Request/AppointmentPageRequest.cs | 9 + .../Request/AppointmentReceiveRequest.cs | 83 ++++ .../Request/ApponintmentAreaSaveRequest.cs | 18 + .../Response/AppointmentDetailResponse.cs | 56 +++ .../Response/AppointmentPageResponse.cs | 22 + .../Response/ApponintmentAreaPageResponse.cs | 34 ++ .../Services/IAppointmentService.cs | 42 ++ .../Services/IApponintmentAreaService.cs | 17 + .../Services/Implements/AppointmentService.cs | 189 ++++++++ .../Implements/ApponintmentAreaService.cs | 93 ++++ Src/Dlhis.Visitor/Dlhis.Visitor.csproj | 23 + Src/Dlhis.Visitor/Packs/SqlSugarPack.cs | 36 ++ Src/Dlhis.Visitor/Program.cs | 21 + .../Properties/launchSettings.json | 15 + .../appsettings.Development.json | 35 ++ Src/Dlhis.Visitor/appsettings.json | 75 +++ 68 files changed, 2086 insertions(+), 412 deletions(-) create mode 100644 Src/Dlhis.Basic.Api/IDeviceGroupApi.cs create mode 100644 Src/Dlhis.Basic.Api/Response/DeviceUnderGroupResponse.cs delete mode 100644 Src/Dlhis.Basic/Device/Dtos/IPPortDto.cs create mode 100644 Src/Dlhis.Basic/Device/Response/DeviceGroupResponse.cs delete mode 100644 Src/Dlhis.Basic/Organization/Controllers/GainfoFacesController.cs create mode 100644 Src/Dlhis.Basic/Organization/Request/GainfoCheckIdNoAndNameRequest.cs create mode 100644 Src/Dlhis.Entity/Visitor/Entity/AppointmentAreaAssignmentEntity.cs create mode 100644 Src/Dlhis.Entity/Visitor/Entity/AppointmentAreaEntity.cs create mode 100644 Src/Dlhis.Entity/Visitor/Entity/ApponintmentAreaEntity.cs create mode 100644 Src/Dlhis.Entity/Visitor/Entity/VisitorAppointmentDetailEntity.cs create mode 100644 Src/Dlhis.Entity/Visitor/Entity/VisitorAppointmentEntity.cs create mode 100644 Src/Dlhis.Entity/Visitor/Enums/AppointmentAreaEnumType.cs create mode 100644 Src/Dlhis.Entity/Visitor/Enums/AppointmentDetailEnumType.cs create mode 100644 Src/Dlhis.Entity/Visitor/Enums/ApponintmentAreaEnumType.cs create mode 100644 Src/Dlhis.Entity/Visitor/Enums/VisitorAppointmentDetailEnumType.cs create mode 100644 Src/Dlhis.Message/Controllers/AppointmentPushController.cs create mode 100644 Src/Dlhis.Message/Dlhis.Message.csproj create mode 100644 Src/Dlhis.Message/Dockerfile create mode 100644 Src/Dlhis.Message/Packs/SignalRPack.cs create mode 100644 Src/Dlhis.Message/Program.cs create mode 100644 Src/Dlhis.Message/Properties/launchSettings.json create mode 100644 Src/Dlhis.Message/Services/IVisitorAppointmentService.cs create mode 100644 Src/Dlhis.Message/TestBackgroundService.cs create mode 100644 Src/Dlhis.Message/VisitorAppointmentHub.cs create mode 100644 Src/Dlhis.Message/appsettings.Development.json create mode 100644 Src/Dlhis.Message/appsettings.json create mode 100644 Src/Dlhis.ScheduledTask/TaskAssignment/Dto/TaskDto.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Controllers/AppointmentsController.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Controllers/ApponintmentAreasController.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Dto/AppointmentReceiveItemDto.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Request/AppointmentAreaAssignRequest.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Request/AppointmentAreaSaveRequest.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Request/AppointmentConfirmRequest.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Request/AppointmentIdNoPageRequest.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Request/AppointmentPageRequest.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Request/AppointmentReceiveRequest.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Request/ApponintmentAreaSaveRequest.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Response/AppointmentDetailResponse.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Response/AppointmentPageResponse.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Response/ApponintmentAreaPageResponse.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Services/IAppointmentService.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Services/IApponintmentAreaService.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Services/Implements/AppointmentService.cs create mode 100644 Src/Dlhis.Visitor/Appointment/Services/Implements/ApponintmentAreaService.cs create mode 100644 Src/Dlhis.Visitor/Dlhis.Visitor.csproj create mode 100644 Src/Dlhis.Visitor/Packs/SqlSugarPack.cs create mode 100644 Src/Dlhis.Visitor/Program.cs create mode 100644 Src/Dlhis.Visitor/Properties/launchSettings.json create mode 100644 Src/Dlhis.Visitor/appsettings.Development.json create mode 100644 Src/Dlhis.Visitor/appsettings.json diff --git a/Dlhis.Jinko.Face.sln b/Dlhis.Jinko.Face.sln index 377d7609..f8c00af7 100644 --- a/Dlhis.Jinko.Face.sln +++ b/Dlhis.Jinko.Face.sln @@ -35,12 +35,18 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "External", "External", "{48 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.External", "Src\Dlhis.External\Dlhis.External.csproj", "{8472596E-0DE7-4A17-93D6-F0FC7D44FDF5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dlhis.Scheduled.Api", "Src\Dlhis.Scheduled.Api\Dlhis.Scheduled.Api.csproj", "{9EA85FB2-F320-4F97-B278-00652CF35BD8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.Scheduled.Api", "Src\Dlhis.Scheduled.Api\Dlhis.Scheduled.Api.csproj", "{9EA85FB2-F320-4F97-B278-00652CF35BD8}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.Canteen", "Src\Dlhis.Canteen\Dlhis.Canteen.csproj", "{A54426E2-1CA0-48AB-BBA6-07CDE2807E35}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.Canteen.Api", "Src\Dlhis.Canteen.Api\Dlhis.Canteen.Api.csproj", "{D4043506-7247-4DDC-9751-927403515669}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.Visitor", "Src\Dlhis.Visitor\Dlhis.Visitor.csproj", "{69E8A91A-5D05-4327-BC24-038523C7628C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Message", "Message", "{65E76F97-E78A-4C95-B788-4091236B1A79}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.Message", "Src\Dlhis.Message\Dlhis.Message.csproj", "{053BF7B2-B1A0-435F-9C77-2EF5622CC5C5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -103,6 +109,14 @@ Global {D4043506-7247-4DDC-9751-927403515669}.Debug|Any CPU.Build.0 = Debug|Any CPU {D4043506-7247-4DDC-9751-927403515669}.Release|Any CPU.ActiveCfg = Release|Any CPU {D4043506-7247-4DDC-9751-927403515669}.Release|Any CPU.Build.0 = Release|Any CPU + {69E8A91A-5D05-4327-BC24-038523C7628C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {69E8A91A-5D05-4327-BC24-038523C7628C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {69E8A91A-5D05-4327-BC24-038523C7628C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {69E8A91A-5D05-4327-BC24-038523C7628C}.Release|Any CPU.Build.0 = Release|Any CPU + {053BF7B2-B1A0-435F-9C77-2EF5622CC5C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {053BF7B2-B1A0-435F-9C77-2EF5622CC5C5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {053BF7B2-B1A0-435F-9C77-2EF5622CC5C5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {053BF7B2-B1A0-435F-9C77-2EF5622CC5C5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -120,6 +134,8 @@ Global {9EA85FB2-F320-4F97-B278-00652CF35BD8} = {AA987BDF-EF63-467B-AD04-59F9B10D9000} {A54426E2-1CA0-48AB-BBA6-07CDE2807E35} = {3D8A98C1-83C9-4375-AEAB-4F72AFAF365B} {D4043506-7247-4DDC-9751-927403515669} = {3D8A98C1-83C9-4375-AEAB-4F72AFAF365B} + {69E8A91A-5D05-4327-BC24-038523C7628C} = {489252FB-A44B-46EE-B065-21CDCB724441} + {053BF7B2-B1A0-435F-9C77-2EF5622CC5C5} = {65E76F97-E78A-4C95-B788-4091236B1A79} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7439494A-E2FD-4FEA-8ABF-74AE57A4A5A0} diff --git a/Src/Dlhis.Basic.Api/Dlhis.Basic.Api.csproj b/Src/Dlhis.Basic.Api/Dlhis.Basic.Api.csproj index 2311965f..ae3784a1 100644 --- a/Src/Dlhis.Basic.Api/Dlhis.Basic.Api.csproj +++ b/Src/Dlhis.Basic.Api/Dlhis.Basic.Api.csproj @@ -10,8 +10,4 @@ - - - - diff --git a/Src/Dlhis.Basic.Api/IDeviceGroupApi.cs b/Src/Dlhis.Basic.Api/IDeviceGroupApi.cs new file mode 100644 index 00000000..790d3024 --- /dev/null +++ b/Src/Dlhis.Basic.Api/IDeviceGroupApi.cs @@ -0,0 +1,20 @@ +using Dlhis.Basic.Api.Response; +using Kurisu.Core.Result; +using Kurisu.RemoteCall.Attributes; + +namespace Dlhis.Basic.Api; + + +[EnableRemoteClient(Name = "basic-service", BaseUrl = "${InternalRequest:BasicRequestUrl}")] +public interface IDeviceGroupApi +{ + + /// + /// 获取分组下的设备 + /// + /// + /// + [Auth] + [Get("/api/deviceGroups/devices")] + Task>> GetDevicesByCodeAsync(Guid code); +} diff --git a/Src/Dlhis.Basic.Api/Response/DeviceUnderGroupResponse.cs b/Src/Dlhis.Basic.Api/Response/DeviceUnderGroupResponse.cs new file mode 100644 index 00000000..a2e8a5ea --- /dev/null +++ b/Src/Dlhis.Basic.Api/Response/DeviceUnderGroupResponse.cs @@ -0,0 +1,21 @@ +namespace Dlhis.Basic.Api.Response; + +public class DeviceUnderGroupResponse +{ + public Guid Code { get; set; } + + /// + /// 设备唯一码,IP/MAC/SNO + /// + public string UniqueNo { get; set; } + + /// + /// 品牌 + /// + public string Brand { get; set; } + + /// + /// 是否启用 + /// + public bool Enable { get; set; } +} diff --git a/Src/Dlhis.Basic/Device/Controllers/DeviceGroupsController.cs b/Src/Dlhis.Basic/Device/Controllers/DeviceGroupsController.cs index 8781919a..bfd389b3 100644 --- a/Src/Dlhis.Basic/Device/Controllers/DeviceGroupsController.cs +++ b/Src/Dlhis.Basic/Device/Controllers/DeviceGroupsController.cs @@ -71,4 +71,14 @@ public class DeviceGroupsController : ControllerBase { await _deviceGroupService.AssignDevicesAsync(request); } + + /// + /// 获取用于预约的设备组 + /// + /// + [HttpGet("type/appointment")] + public async Task> GetAppointmentGroupsAsync() + { + return await _deviceGroupService.GetAppointmentGroupsAsync(); + } } diff --git a/Src/Dlhis.Basic/Device/Dtos/IPPortDto.cs b/Src/Dlhis.Basic/Device/Dtos/IPPortDto.cs deleted file mode 100644 index 60ba4f46..00000000 --- a/Src/Dlhis.Basic/Device/Dtos/IPPortDto.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Dlhis.Basic.Device.Dtos -{ - public class IPPortDto - { - public string IP { get; set; } - public int Port { get; set; } - } -} diff --git a/Src/Dlhis.Basic/Device/Request/DeviceGroupSaveRequest.cs b/Src/Dlhis.Basic/Device/Request/DeviceGroupSaveRequest.cs index 73bf5281..b4812e81 100644 --- a/Src/Dlhis.Basic/Device/Request/DeviceGroupSaveRequest.cs +++ b/Src/Dlhis.Basic/Device/Request/DeviceGroupSaveRequest.cs @@ -1,9 +1,10 @@ using Dlhis.Entity.Device.Enums; +using Kurisu.AspNetCore.Utils.Extensions; using System.ComponentModel.DataAnnotations; namespace Dlhis.Basic.Device.Request; -public class DeviceGroupSaveRequest +public class DeviceGroupSaveRequest : IValidatableObject { public long? Id { get; set; } @@ -22,10 +23,23 @@ public class DeviceGroupSaveRequest /// 分类类型 DeviceTypeEnumType /// [EnumDataType(typeof(DeviceTypeEnumType))] - public DeviceTypeEnumType? Type { get; set; } + public DeviceTypeEnumType Type { get; set; } + + /// + /// 可作为预约分组 + /// + public bool AsAppointment { get; set; } /// /// 备注 /// public string Remark { get; set; } + + public IEnumerable Validate(ValidationContext validationContext) + { + if (AsAppointment && Type != DeviceTypeEnumType.Door) + { + yield return new ValidationResult($"作为预约分组必要为{DeviceTypeEnumType.Door.GetDescription()}类型", new[] { nameof(Type) }); + } + } } diff --git a/Src/Dlhis.Basic/Device/Response/DeviceGroupResponse.cs b/Src/Dlhis.Basic/Device/Response/DeviceGroupResponse.cs new file mode 100644 index 00000000..af01c809 --- /dev/null +++ b/Src/Dlhis.Basic/Device/Response/DeviceGroupResponse.cs @@ -0,0 +1,19 @@ +namespace Dlhis.Basic.Device.Response; + +public class DeviceGroupResponse +{ + /// + /// id + /// + public long Id { get; set; } + + /// + /// code + /// + public Guid Code { get; set; } + + /// + /// 分组名 + /// + public string Name { get; set; } +} diff --git a/Src/Dlhis.Basic/Device/Services/IDeviceGroupService.cs b/Src/Dlhis.Basic/Device/Services/IDeviceGroupService.cs index 4335fce8..9772a7ea 100644 --- a/Src/Dlhis.Basic/Device/Services/IDeviceGroupService.cs +++ b/Src/Dlhis.Basic/Device/Services/IDeviceGroupService.cs @@ -13,4 +13,6 @@ public interface IDeviceGroupService : IScopeDependency Task> GetDevicesAsync(Guid code); Task AssignDevicesAsync(DeviceAssignRequest requests); + + Task> GetAppointmentGroupsAsync(); } diff --git a/Src/Dlhis.Basic/Device/Services/Implements/DeviceConnectService.cs b/Src/Dlhis.Basic/Device/Services/Implements/DeviceConnectService.cs index 85b68b72..d735172e 100644 --- a/Src/Dlhis.Basic/Device/Services/Implements/DeviceConnectService.cs +++ b/Src/Dlhis.Basic/Device/Services/Implements/DeviceConnectService.cs @@ -1,15 +1,14 @@ using System.Net; using System.Net.Sockets; -using Dlhis.Basic.Device.Dtos; using Dlhis.Basic.Device.Request; using Dlhis.Basic.Device.Response; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Device.Entities; using Dlhis.Entity.Device.Enums; using Kurisu.AspNetCore.Utils.Extensions; +using Kurisu.Core.CustomClass; using Kurisu.SqlSugar.Services; using Mapster; -using Newtonsoft.Json; namespace Dlhis.Basic.Device.Services.Implements; diff --git a/Src/Dlhis.Basic/Device/Services/Implements/DeviceGroupService.cs b/Src/Dlhis.Basic/Device/Services/Implements/DeviceGroupService.cs index 3c8797d6..e883ef88 100644 --- a/Src/Dlhis.Basic/Device/Services/Implements/DeviceGroupService.cs +++ b/Src/Dlhis.Basic/Device/Services/Implements/DeviceGroupService.cs @@ -78,14 +78,6 @@ public class DeviceGroupService : IDeviceGroupService } } - public async Task DeleteAsync(long id) - { - var deviceGroup = await _dbContext.Queryable().Where(x => x.Id == id).FirstAsync(); - deviceGroup.ThrowIfNull("设备分组不存在,无需删除"); - - await _dbContext.DeleteAsync(deviceGroup); - } - public async Task AssignDevicesAsync(DeviceAssignRequest request) { @@ -117,14 +109,39 @@ public class DeviceGroupService : IDeviceGroupService public async Task> GetDevicesAsync(Guid code) { - var relationships = await _dbContext.Queryable().Where(x => x.GroupCode == code).ToListAsync(); + var relationships = await _dbContext.Queryable() + .Where(x => x.GroupCode == code) + .ToListAsync(); + var deviceCodes = relationships.Select(x => x.DeviceCode); return await _dbContext.Queryable() + .LeftJoin((x, dt) => x.TemplateCode == dt.Code) .Where(x => deviceCodes.Contains(x.Code)) - .Select() + .Select((x, dt) => new DeviceUnderGroupResponse + { + UniqueNo = x.UniqueNo, + Type = x.Type, + Code = x.Code, + Enable = x.Enable, + Brand = dt.Brand + }) .ToListAsync(); + } + + public async Task> GetAppointmentGroupsAsync() + { + return await _dbContext.Queryable() + .Where(x => x.AsAppointment) + .Where(x => x.Type == DeviceTypeEnumType.Door) + .Select(x => new DeviceGroupResponse + { + Id = x.Id, + Code = x.Code, + Name = x.Name, + }) + .ToListAsync(); } /****************************************************** help methods *********************************************************/ diff --git a/Src/Dlhis.Basic/Organization/Controllers/GainfoFacesController.cs b/Src/Dlhis.Basic/Organization/Controllers/GainfoFacesController.cs deleted file mode 100644 index 124b041d..00000000 --- a/Src/Dlhis.Basic/Organization/Controllers/GainfoFacesController.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Dlhis.Basic.Organization.Request; -using Dlhis.Basic.Organization.Services; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; - -namespace Dlhis.Basic.Organization.Controllers; - -/// -/// 人员face -/// -[Route("api/[controller]")] -[ApiController] -public class GainfoFacesController : ControllerBase -{ - private readonly IGainfoFaceService _gainfoFaceService; - - public GainfoFacesController(IGainfoFaceService gainfoFaceService) - { - _gainfoFaceService = gainfoFaceService; - } - - /// - /// 上传外部人员人脸照片 - /// - /// - [AllowAnonymous] - [HttpPost("external/face")] - public async Task UploadExternalFaceAsync(GainfoUploadFaceRequest request) - { - await _gainfoFaceService.UploadExternalFaceAsync(request); - } -} diff --git a/Src/Dlhis.Basic/Organization/Controllers/GainfosController.cs b/Src/Dlhis.Basic/Organization/Controllers/GainfosController.cs index 84068abb..e5c23141 100644 --- a/Src/Dlhis.Basic/Organization/Controllers/GainfosController.cs +++ b/Src/Dlhis.Basic/Organization/Controllers/GainfosController.cs @@ -18,21 +18,12 @@ namespace Dlhis.Basic.MealUser.Controllers; public class GainfosController : ControllerBase { private readonly IGainfoService _gainfoService; + private readonly IGainfoFaceService _gainfoFaceService; - public GainfosController(IGainfoService gainfoService) + public GainfosController(IGainfoService gainfoService, IGainfoFaceService gainfoFaceService) { _gainfoService = gainfoService; - } - - /// - /// 档案表保存 - /// - /// - /// - [HttpPost("save")] - public async Task SaveAsync(List requests) - { - await _gainfoService.SaveAsync(requests); + _gainfoFaceService = gainfoFaceService; } /// @@ -80,6 +71,17 @@ public class GainfosController : ControllerBase await _gainfoService.UploadFaceAsync(request); } + /// + /// 上传外部人员人脸照片 + /// + /// + [AllowAnonymous] + [HttpPost("external/face")] + public async Task UploadExternalFaceAsync(GainfoUploadFaceRequest request) + { + await _gainfoFaceService.UploadExternalFaceAsync(request); + } + /// /// 批量上传人脸照片 /// @@ -161,5 +163,18 @@ public class GainfosController : ControllerBase { await _gainfoService.MigrationAsync(request); } + + + /// + /// 检查idno和名称是否匹配 + /// + /// + /// + [AllowAnonymous] + [HttpPost("check/idnoWithName")] + public async Task CheckIdNoAndNameMatchAsync(GainfoCheckIdNoAndNameRequest request) + { + await _gainfoService.CheckIdNoAndNameMatchAsync(request); + } } diff --git a/Src/Dlhis.Basic/Organization/Request/GainfoCheckIdNoAndNameRequest.cs b/Src/Dlhis.Basic/Organization/Request/GainfoCheckIdNoAndNameRequest.cs new file mode 100644 index 00000000..c1a1124f --- /dev/null +++ b/Src/Dlhis.Basic/Organization/Request/GainfoCheckIdNoAndNameRequest.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dlhis.Basic.Organization.Request; + +public class GainfoCheckIdNoAndNameRequest +{ + /// + /// 身份证 + /// + [Required(ErrorMessage = "身份证不可为空")] + [StringLength(18, ErrorMessage = "身份证位数错误", MinimumLength = 18)] + public string IdNo { get; set; } + + /// + /// 姓名 + /// + [Required(ErrorMessage = "姓名不可为空")] + public string Name { get; set; } +} diff --git a/Src/Dlhis.Basic/Organization/Services/IGainfoService.cs b/Src/Dlhis.Basic/Organization/Services/IGainfoService.cs index 6fca4a02..7624acfc 100644 --- a/Src/Dlhis.Basic/Organization/Services/IGainfoService.cs +++ b/Src/Dlhis.Basic/Organization/Services/IGainfoService.cs @@ -11,14 +11,6 @@ public interface IGainfoService : IScopeDependency Task> GetPageByCodeAsync(string code); - Task SaveAsync(List requests); - - Task UpdateAsync(GainfoSaveRequest request); - - Task DimissionAsync(GainfoDimissionRequest request); - - Task OnboardingAsync(GainfoDimissionRequest request); - Task CurrentUserInfoAsync(); Task UploadFaceAsync(GainfoUploadFaceRequest request); @@ -37,4 +29,6 @@ public interface IGainfoService : IScopeDependency Task MigrationAsync(MigrationRequest request); + + Task CheckIdNoAndNameMatchAsync(GainfoCheckIdNoAndNameRequest request); } diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs index 778b96fd..f0f9f9cd 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs @@ -1,4 +1,5 @@ -using Dlhis.Basic.Device.Services; +using System.Text.RegularExpressions; +using Dlhis.Basic.Device.Services; using Dlhis.Basic.Organization.Request; using Dlhis.Basic.Organization.Response; using Dlhis.Entity.Basic.Entity; @@ -13,7 +14,6 @@ using Kurisu.Core.DataAccess.Dto; using Kurisu.Core.User.Abstractions; using Kurisu.SqlSugar.Extensions; using Kurisu.SqlSugar.Services; -using Mapster; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Mvc; @@ -23,10 +23,10 @@ public class GainfoService : IGainfoService { private readonly IGainfoStore _gainfoStore; private readonly IDbContext _dbContext; + private readonly IDataProtectionProvider _dataProtectionProvider; private readonly ICurrentUser _currentUser; private readonly IDevicePermissionService _devicePermissionService; private readonly RedisCache _redisCache; - private readonly IServiceProvider _serviceProvider; private readonly IConfiguration _configuration; private readonly ITenantApi _tenantApi; private readonly IHangfireApi _hangfireApi; @@ -34,10 +34,10 @@ public class GainfoService : IGainfoService public GainfoService(IGainfoStore gainfoStore, IDbContext dbContext, + IDataProtectionProvider dataProtectionProvider, ICurrentUser currentUser, IDevicePermissionService devicePermissionService, RedisCache redisCache, - IServiceProvider serviceProvider, IConfiguration configuration, ITenantApi tenantApi, IHangfireApi hangfireApi, @@ -45,10 +45,10 @@ public class GainfoService : IGainfoService { _gainfoStore = gainfoStore; _dbContext = dbContext; + _dataProtectionProvider = dataProtectionProvider; _currentUser = currentUser; _devicePermissionService = devicePermissionService; _redisCache = redisCache; - _serviceProvider = serviceProvider; _configuration = configuration; _tenantApi = tenantApi; _hangfireApi = hangfireApi; @@ -80,10 +80,8 @@ public class GainfoService : IGainfoService .WhereIF(request.DepartmentSelections.IsEmpty(), gainfo => gainfo.Factory == currentTenantId) .WhereIF(request.Search.IsPresent(), gainfo => gainfo.Name.Contains(request.Search) - || gainfo.Code.Contains(request.Search) - || gainfo.IdNo.Contains(request.Search) - || gainfo.Werks.Contains(request.Search) - ) + || gainfo.Code == request.Search + || gainfo.IdNo == request.Search) .Select() .ToPageListAsync(request); @@ -109,78 +107,6 @@ public class GainfoService : IGainfoService return page; } - /// - ///保存档案号 - /// - /// - /// - public async Task SaveAsync(List request) - { - //todo check - var entities = request.Adapt>(); - entities.ForEach(x => - { - if (x.No.IsEmpty()) - { - x.No = "F" + Guid.NewGuid().ToString(); - } - }); - - await _gainfoStore.InsertAsync(entities); - } - - - /// - ///修改档案号 - /// - /// - /// - public async Task UpdateAsync(GainfoSaveRequest request) - { - var gainfo = await _gainfoStore.Queryable(request.GainfoStatus).Where(x => x.Id == request.Id).FirstAsync(); - gainfo.ThrowIfNull("档案数据不存在,无法更新"); - - request.Adapt(gainfo); - await _gainfoStore.UpdateAsync(gainfo); - } - - /// - /// 正式转离职 - /// - /// - /// - public async Task DimissionAsync(GainfoDimissionRequest request) - { - var gainfo = await _gainfoStore.Queryable(GainfoStatusEnumType.Working) - .Where(x => x.No == request.UserNo) - .FirstAsync(); - - gainfo.ThrowIfNull("该档案不存在"); - - //添加到离职表 - await _gainfoStore.InsertAsync(gainfo, GainfoStatusEnumType.Leave); - //删除原数据 - await _gainfoStore.DeleteAsync(gainfo, GainfoStatusEnumType.Working); - } - - /// - /// 临时转正式 - /// - /// - /// - /// - public async Task OnboardingAsync(GainfoDimissionRequest request) - { - var gainfo = await _gainfoStore.Queryable(GainfoStatusEnumType.External) - .Where(x => x.No == request.UserNo) - .FirstAsync(); - - gainfo.ThrowIfNull($"该档案不存在"); - - //添加到正式表,不删除原数据,留档处理 - await _gainfoStore.InsertAsync(gainfo); - } - public async Task CurrentUserInfoAsync() { var code = _currentUser.GetUserClaim("jinko-code"); @@ -239,9 +165,7 @@ public class GainfoService : IGainfoService public async Task GetFaceAsync(string token) { - var timeLimitedDataProtector = _serviceProvider.GetService() - .CreateProtector("down:face") - .ToTimeLimitedDataProtector(); + var timeLimitedDataProtector = _dataProtectionProvider.CreateProtector("down:face").ToTimeLimitedDataProtector(); try { @@ -263,7 +187,6 @@ public class GainfoService : IGainfoService return new NotFoundResult(); } - await _redisCache.HashSetAsync("faces", userCode, face.Face); return new FileContentResult(Convert.FromBase64String(face.Face), "image/png"); } catch (Exception ex) @@ -373,9 +296,7 @@ public class GainfoService : IGainfoService face.ThrowIfNull("人脸照片尚未录入"); - var timeLimitedDataProtector = _serviceProvider.GetService() - .CreateProtector("down:face") - .ToTimeLimitedDataProtector(); + var timeLimitedDataProtector = _dataProtectionProvider.CreateProtector("down:face").ToTimeLimitedDataProtector(); var faceUrl = _configuration.GetSection("FaceUrlOptions:Url").Value; var limit = _configuration.GetSection("FaceUrlOptions:Limit").Get(); @@ -404,6 +325,20 @@ public class GainfoService : IGainfoService return faceDictionary; } + + public async Task CheckIdNoAndNameMatchAsync(GainfoCheckIdNoAndNameRequest request) + { + var match = await _gainfoStore.Queryable(GainfoStatusEnumType.External).AnyAsync(x => x.IdNo == request.IdNo && x.Name == request.Name); + if (!match) + { + match = await _gainfoStore.Queryable(GainfoStatusEnumType.Working).AnyAsync(x => x.IdNo == request.IdNo && x.Name == request.Name); + } + + match.ThrowIfFalse("验证失败!"); + + return request.IdNo; + } + /// /// 档案列表 /// diff --git a/Src/Dlhis.Basic/Packs/SqlSugarPack.cs b/Src/Dlhis.Basic/Packs/SqlSugarPack.cs index 9e6d5ca3..9df2950d 100644 --- a/Src/Dlhis.Basic/Packs/SqlSugarPack.cs +++ b/Src/Dlhis.Basic/Packs/SqlSugarPack.cs @@ -53,8 +53,8 @@ public class SqlSugarPack : BaseAppPack public override void Configure(IApplicationBuilder app, IWebHostEnvironment env) { - var siGenerate = Configuration.GetSection("SqlSugarOptions").GetValue("Generate"); - if (siGenerate) + var isGenerate = Configuration.GetSection("SqlSugarOptions").GetValue("Generate"); + if (isGenerate) { using var scope = app.ApplicationServices.CreateScope(); var db = scope.ServiceProvider.GetService(); diff --git a/Src/Dlhis.Basic/appsettings.Development.json b/Src/Dlhis.Basic/appsettings.Development.json index e3e356f0..8af9df4f 100644 --- a/Src/Dlhis.Basic/appsettings.Development.json +++ b/Src/Dlhis.Basic/appsettings.Development.json @@ -5,7 +5,6 @@ "Microsoft.AspNetCore": "Warning" } }, - "EightThirtyPM": "20:30:00", "InternalRequest": { "CommonRequestUrl": "http://localhost:5001", "SysRequestUrl": "http://localhost:5003", diff --git a/Src/Dlhis.Entity/Basic/Entity/GainfoEntity.cs b/Src/Dlhis.Entity/Basic/Entity/GainfoEntity.cs index 26296b5a..6ae4192d 100644 --- a/Src/Dlhis.Entity/Basic/Entity/GainfoEntity.cs +++ b/Src/Dlhis.Entity/Basic/Entity/GainfoEntity.cs @@ -62,7 +62,7 @@ public class GainfoEntity : SugarBaseEntity /// /// 身份证号 /// - [SugarColumn(ColumnDescription = "身份证号")] + [SugarColumn(ColumnDescription = "身份证号", UniqueGroupNameList = new[] { "idx_Gainfo_IdNo" })] public string IdNo { get; set; } /// @@ -211,22 +211,4 @@ public class GainfoExternalEntity : GainfoEntity /// [SugarColumn(ColumnDescription = "公司", IsNullable = false)] public string Company { get; set; } - - /// - /// 到达时间 - /// - [SugarColumn(ColumnDescription = "到达时间")] - public DateTime From { get; set; } - - /// - /// 离开时间 - /// - [SugarColumn(ColumnDescription = "离开时间")] - public DateTime To { get; set; } - - /// - /// 对接人No - /// - [SugarColumn(ColumnDescription = "对接人", IsNullable = false)] - public string JinkoNo { get; set; } } diff --git a/Src/Dlhis.Entity/Device/Entities/DeviceGroupEntity.cs b/Src/Dlhis.Entity/Device/Entities/DeviceGroupEntity.cs index 0d22dc00..c54f9911 100644 --- a/Src/Dlhis.Entity/Device/Entities/DeviceGroupEntity.cs +++ b/Src/Dlhis.Entity/Device/Entities/DeviceGroupEntity.cs @@ -55,6 +55,12 @@ public class DeviceGroupEntity : SugarBaseEntity, ITenantId, ISoftDeleted [SugarColumn(IsNullable = true)] public string Remark { get; set; } + /// + /// 可作为预约分组 + /// + [SugarColumn(ColumnDataType = "bit", DefaultValue = "0")] + public bool AsAppointment { get; set; } = false; + public string TenantId { get; set; } diff --git a/Src/Dlhis.Entity/Device/Entities/DeviceTaskEntity.cs b/Src/Dlhis.Entity/Device/Entities/DeviceTaskEntity.cs index d1c9ace1..56af07d6 100644 --- a/Src/Dlhis.Entity/Device/Entities/DeviceTaskEntity.cs +++ b/Src/Dlhis.Entity/Device/Entities/DeviceTaskEntity.cs @@ -15,7 +15,7 @@ public class DeviceTaskEntity : SugarBaseEntity, ITenantId, IVersion /// /// 任务类型 /// - [SugarColumn(ColumnDataType = "varchar(50)", SqlParameterDbType = typeof(EnumToStringConvert))] + [SugarColumn(ColumnDataType = "varchar(50)", SqlParameterDbType = typeof(EnumToStringConvert), IndexGroupNameList = new[] { "idx_DeviceTask_Type" })] public DeviceTaskEnumType Type { get; set; } /// @@ -44,7 +44,7 @@ public class DeviceTaskEntity : SugarBaseEntity, ITenantId, IVersion /// /// 任务下发状态 /// - [SugarColumn(ColumnDataType = "varchar(50)", SqlParameterDbType = typeof(EnumToStringConvert))] + [SugarColumn(ColumnDataType = "varchar(50)", SqlParameterDbType = typeof(EnumToStringConvert), IndexGroupNameList = new[] { "idx_DeviceTask_Status" })] public DeviceTaskStatusEnumType Status { get; set; } /// @@ -69,7 +69,7 @@ public class DeviceTaskEntity : SugarBaseEntity, ITenantId, IVersion /// 优先级 /// [SugarColumn(IsNullable = true, DefaultValue = "0")] - public int Priority { get; set; } = 0; + public int Priority { get; set; } = 0; public string TenantId { get; set; } diff --git a/Src/Dlhis.Entity/Dlhis.Entity.csproj b/Src/Dlhis.Entity/Dlhis.Entity.csproj index 31994a94..36c0cf47 100644 --- a/Src/Dlhis.Entity/Dlhis.Entity.csproj +++ b/Src/Dlhis.Entity/Dlhis.Entity.csproj @@ -6,10 +6,6 @@ disable - - - - diff --git a/Src/Dlhis.Entity/Visitor/Entity/AppointmentAreaAssignmentEntity.cs b/Src/Dlhis.Entity/Visitor/Entity/AppointmentAreaAssignmentEntity.cs new file mode 100644 index 00000000..3635b96b --- /dev/null +++ b/Src/Dlhis.Entity/Visitor/Entity/AppointmentAreaAssignmentEntity.cs @@ -0,0 +1,28 @@ +using Kurisu.Core.DataAccess.Entity; +using Kurisu.SqlSugar; +using SqlSugar; + +namespace Dlhis.Entity.Visitor.Entity; + +/// +/// 预约区域分配 +/// +[SugarTable(TableName = "AppointmentAreaAssignment", TableDescription = "预约区域分配")] +public class AppointmentAreaAssignmentEntity : SugarBaseEntity, ITenantId +{ + /// + /// 预约区域编码 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "预约区域编码")] + public string CustomCode { get; set; } + + /// + /// 分组code + /// + [SugarColumn(IsNullable = false, ColumnDescription = "分组code")] + public Guid GroupCode { get; set; } + //UniqueGroupNameList = new[] { "idx_aaa_cc_grpc_tid" } + + [SugarColumn()] + public string TenantId { get; set; } +} diff --git a/Src/Dlhis.Entity/Visitor/Entity/AppointmentAreaEntity.cs b/Src/Dlhis.Entity/Visitor/Entity/AppointmentAreaEntity.cs new file mode 100644 index 00000000..704969a0 --- /dev/null +++ b/Src/Dlhis.Entity/Visitor/Entity/AppointmentAreaEntity.cs @@ -0,0 +1,54 @@ +using Dlhis.Entity.Visitor.Enums; +using Kurisu.Core.DataAccess.Entity; +using Kurisu.SqlSugar; +using Mapster; +using SqlSugar; +using SqlSugar.DbConvert; + +namespace Dlhis.Entity.Visitor.Entity; + +/// +/// 预约区域 +/// +[SugarTable(TableName = "AppointmentArea", TableDescription = "预约区域")] +public class AppointmentAreaEntity : SugarBaseEntity, ITenantId, ISoftDeleted +{ + /// + /// 区域类型 + /// + [AdaptIgnore(MemberSide.Destination)] + [SugarColumn(IsNullable = false, ColumnDescription = "区域类型", ColumnDataType = "varchar(50)", + SqlParameterDbType = typeof(EnumToStringConvert), + UniqueGroupNameList = new[] { "idx_ApponintmentArea_t_cc_tid" })] + public AppointmentAreaEnumType Type { get; set; } + + /// + /// 自定义编码 + /// + [AdaptIgnore(MemberSide.Destination)] + [SugarColumn(IsNullable = false, ColumnDescription = "自定义编码", + UniqueGroupNameList = new[] { "idx_ApponintmentArea_t_cc_tid" })] + public string CustomCode { get; set; } + + /// + /// 名称 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "名称")] + public string Name { get; set; } + + /// + /// 备注 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "备注")] + public string Remark { get; set; } + + /// + /// 基地/租户 + /// + [SugarColumn(IsNullable = false, ColumnDescription = " 基地/租户", + UniqueGroupNameList = new[] { "idx_ApponintmentArea_t_cc_tid" })] + public string TenantId { get; set; } + + + public bool IsDeleted { get; set; } +} diff --git a/Src/Dlhis.Entity/Visitor/Entity/ApponintmentAreaEntity.cs b/Src/Dlhis.Entity/Visitor/Entity/ApponintmentAreaEntity.cs new file mode 100644 index 00000000..9b006faf --- /dev/null +++ b/Src/Dlhis.Entity/Visitor/Entity/ApponintmentAreaEntity.cs @@ -0,0 +1,44 @@ +using Dlhis.Entity.Visitor.Enums; +using Kurisu.Core.DataAccess.Entity; +using Kurisu.SqlSugar; +using SqlSugar; +using SqlSugar.DbConvert; + +namespace Dlhis.Entity.Visitor.Entity; + +/// +/// 预约区域 +/// +[SugarTable(TableName = "ApponintmentArea", TableDescription = "预约区域")] +public class ApponintmentAreaEntity : SugarBaseEntity, ITenantId +{ + /// + /// 区域类型 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "区域类型", ColumnDataType = "varchar(50)", SqlParameterDbType = typeof(EnumToStringConvert))] + public AppointmentAreaEnumType Type { get; set; } + + /// + /// 自定义编码 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "自定义编码", UniqueGroupNameList = new[] { "idx_aa_cc_tid" })] + public string CustomCode { get; set; } + + /// + /// 名称 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "名称")] + public string Name { get; set; } + + /// + /// 备注 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "备注")] + public string Remark { get; set; } + + /// + /// 基地/租户 + /// + [SugarColumn(IsNullable = false, ColumnDescription = " 基地/租户", UniqueGroupNameList = new[] { "idx_aa_cc_tid" })] + public string TenantId { get; set; } +} diff --git a/Src/Dlhis.Entity/Visitor/Entity/VisitorAppointmentDetailEntity.cs b/Src/Dlhis.Entity/Visitor/Entity/VisitorAppointmentDetailEntity.cs new file mode 100644 index 00000000..48f6a32b --- /dev/null +++ b/Src/Dlhis.Entity/Visitor/Entity/VisitorAppointmentDetailEntity.cs @@ -0,0 +1,73 @@ +using Dlhis.Entity.Visitor.Enums; +using Kurisu.SqlSugar; +using SqlSugar; +using SqlSugar.DbConvert; + +namespace Dlhis.Entity.Visitor.Entity; + +/// +/// 预约明细 +/// +[SugarTable(TableName = "VisitorAppointmentDetail", TableDescription = "访客预约")] +public class VisitorAppointmentDetailEntity : SugarBaseEntity +{ + [SugarColumn(IsNullable = false, ColumnDescription = "父id")] + public long AppointmentId { get; set; } + + /// + /// 流水号 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "流水号")] + public string FlowId { get; set; } + + /// + /// 访客名称 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "访客名称")] + public string Name { get; set; } + + /// + /// 手机号 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "手机号")] + public string Phone { get; set; } + + /// + /// 是否外部人员 + /// + [SugarColumn(IsNullable = false, ColumnDataType = "bit")] + public bool IsExternal { get; set; } + + /// + /// 身份证 + /// + /// + /// 使用身份证字段作为申请人唯一标识 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "身份证")] + public string IdNo { get; set; } + + /// + /// 预计到达 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "预计到达")] + public DateTime Start { get; set; } + + /// + /// 预计离开 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "预计离开")] + public DateTime End { get; set; } + + /// + /// 状态 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "状态", ColumnDataType = "varchar(50)", SqlParameterDbType = typeof(EnumToStringConvert))] + public AppointmentDetailEnumType Status { get; set; } + + /// + /// 备注 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "备注")] + public string Remark { get; set; } +} diff --git a/Src/Dlhis.Entity/Visitor/Entity/VisitorAppointmentEntity.cs b/Src/Dlhis.Entity/Visitor/Entity/VisitorAppointmentEntity.cs new file mode 100644 index 00000000..55cc53cb --- /dev/null +++ b/Src/Dlhis.Entity/Visitor/Entity/VisitorAppointmentEntity.cs @@ -0,0 +1,30 @@ +using Kurisu.SqlSugar; +using SqlSugar; + +namespace Dlhis.Entity.Visitor.Entity; + +[SugarTable(TableName = "VisitorAppointment", TableDescription = "访客预约")] +public class VisitorAppointmentEntity : SugarBaseEntity +{ + /// + /// 流水号 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "流水号", UniqueGroupNameList = new[] { "idx_VisitorAppointment_FlowId" })] + public string FlowId { get; set; } + + public string Title { get; set; } + + public string Code { get; set; } + + public string Name { get; set; } + + public string Description { get; set; } + + public string DepartmentNo { get; set; } + + public string Company { get; set; } + + public DateTime ApplyTime { get; set; } + + public string AreaCustomCode { get; set; } +} diff --git a/Src/Dlhis.Entity/Visitor/Enums/AppointmentAreaEnumType.cs b/Src/Dlhis.Entity/Visitor/Enums/AppointmentAreaEnumType.cs new file mode 100644 index 00000000..70ebf494 --- /dev/null +++ b/Src/Dlhis.Entity/Visitor/Enums/AppointmentAreaEnumType.cs @@ -0,0 +1,22 @@ +using System.ComponentModel; + +namespace Dlhis.Entity.Visitor.Enums; + +/// +/// 预约区域类型 +/// +[Description("预约区域类型")] +public enum AppointmentAreaEnumType +{ + /// + /// 门岗 + /// + [Description("门岗")] + Door = 1, + + /// + /// 车间 + /// + [Description("车间")] + Workshop = 2, +} diff --git a/Src/Dlhis.Entity/Visitor/Enums/AppointmentDetailEnumType.cs b/Src/Dlhis.Entity/Visitor/Enums/AppointmentDetailEnumType.cs new file mode 100644 index 00000000..dec16c8d --- /dev/null +++ b/Src/Dlhis.Entity/Visitor/Enums/AppointmentDetailEnumType.cs @@ -0,0 +1,35 @@ +using System.ComponentModel; + +namespace Dlhis.Entity.Visitor.Enums; + +/// +/// 访客预约明细状态 +/// +[Description("预约状态")] +public enum AppointmentDetailEnumType +{ + /// + /// 待来访 + /// + [Description("待来访")] + Wait = 0, + + /// + /// 取消 + /// + [Description("取消")] + Cancel = 5, + + /// + /// 到达 + /// + [Description("到达")] + Arrived = 10, + + + /// + /// 离开 + /// + [Description("离开")] + Leave = 99 +} diff --git a/Src/Dlhis.Entity/Visitor/Enums/ApponintmentAreaEnumType.cs b/Src/Dlhis.Entity/Visitor/Enums/ApponintmentAreaEnumType.cs new file mode 100644 index 00000000..f7972f2e --- /dev/null +++ b/Src/Dlhis.Entity/Visitor/Enums/ApponintmentAreaEnumType.cs @@ -0,0 +1,19 @@ +using System.ComponentModel; + +namespace Dlhis.Entity.Visitor.Enums; + +[Description("预约区域")] +public enum ApponintmentAreaEnumType +{ + /// + /// 门岗 + /// + [Description("门岗")] + Door = 1, + + /// + /// 车间 + /// + [Description("车间")] + Workshop = 2, +} diff --git a/Src/Dlhis.Entity/Visitor/Enums/VisitorAppointmentDetailEnumType.cs b/Src/Dlhis.Entity/Visitor/Enums/VisitorAppointmentDetailEnumType.cs new file mode 100644 index 00000000..fe0c852c --- /dev/null +++ b/Src/Dlhis.Entity/Visitor/Enums/VisitorAppointmentDetailEnumType.cs @@ -0,0 +1,22 @@ +using System.ComponentModel; + +namespace Dlhis.Entity.Visitor.Enums; + +/// +/// 访客预约明细状态 +/// +[Description("访客预约状态")] +public enum VisitorAppointmentDetailEnumType +{ + /// + /// 到达 + /// + [Description("到达")] + Arrived = 1, + + /// + /// 离开 + /// + [Description("离开")] + Leave = 99 +} diff --git a/Src/Dlhis.Message/Controllers/AppointmentPushController.cs b/Src/Dlhis.Message/Controllers/AppointmentPushController.cs new file mode 100644 index 00000000..8d25db42 --- /dev/null +++ b/Src/Dlhis.Message/Controllers/AppointmentPushController.cs @@ -0,0 +1,26 @@ +using Dlhis.Message.Services; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; + +namespace Dlhis.Message.Controllers; + +/// +/// +/// +[Route("api/[controller]")] +[ApiController] +public class AppointmentPushController : ControllerBase +{ + private readonly IHubContext _hubContext; + + public AppointmentPushController(IHubContext hubContext) + { + _hubContext = hubContext; + } + + [HttpPost("push")] + public async Task PushAsync(Dictionary values) + { + await _hubContext.Clients.All.Raise(values); + } +} diff --git a/Src/Dlhis.Message/Dlhis.Message.csproj b/Src/Dlhis.Message/Dlhis.Message.csproj new file mode 100644 index 00000000..82051fc6 --- /dev/null +++ b/Src/Dlhis.Message/Dlhis.Message.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + enable + enable + Linux + ..\.. + + + + + + + + diff --git a/Src/Dlhis.Message/Dockerfile b/Src/Dlhis.Message/Dockerfile new file mode 100644 index 00000000..f23a7195 --- /dev/null +++ b/Src/Dlhis.Message/Dockerfile @@ -0,0 +1,23 @@ +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +WORKDIR /app +EXPOSE 80 + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["Src/Dlhis.Message/Dlhis.Message.csproj", "Src/Dlhis.Message/"] +RUN dotnet restore "./Src/Dlhis.Message/./Dlhis.Message.csproj" +COPY . . +WORKDIR "/src/Src/Dlhis.Message" +RUN dotnet build "./Dlhis.Message.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./Dlhis.Message.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Dlhis.Message.dll"] \ No newline at end of file diff --git a/Src/Dlhis.Message/Packs/SignalRPack.cs b/Src/Dlhis.Message/Packs/SignalRPack.cs new file mode 100644 index 00000000..0c5d762d --- /dev/null +++ b/Src/Dlhis.Message/Packs/SignalRPack.cs @@ -0,0 +1,22 @@ +using Kurisu.AspNetCore.Startup; + +namespace Dlhis.Message.Packs; + +public class SignalRPack : BaseAppPack +{ + public override bool IsBeforeUseRouting => false; + + + public override void ConfigureServices(IServiceCollection services) + { + services.AddSignalR(); + } + + public override void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseEndpoints(endpoints => + { + endpoints.MapHub("/hub/appointment"); + }); + } +} diff --git a/Src/Dlhis.Message/Program.cs b/Src/Dlhis.Message/Program.cs new file mode 100644 index 00000000..b2292f00 --- /dev/null +++ b/Src/Dlhis.Message/Program.cs @@ -0,0 +1,20 @@ +using Kurisu.AspNetCore.Startup; +using Kurisu.Startup; +using Microsoft.IdentityModel.Logging; + +class Program +{ + static void Main(string[] args) + { + KurisuHost.Run(true, args); + } +} + +public class Startup : DefaultStartup +{ + public Startup(IConfiguration configuration) : base(configuration) + { + IdentityModelEventSource.ShowPII = true; + } +} + diff --git a/Src/Dlhis.Message/Properties/launchSettings.json b/Src/Dlhis.Message/Properties/launchSettings.json new file mode 100644 index 00000000..85b6d7fd --- /dev/null +++ b/Src/Dlhis.Message/Properties/launchSettings.json @@ -0,0 +1,15 @@ +{ + "profiles": { + "Dlhis.Message": { + "commandName": "Project", + "launchBrowser": false, + "launchUrl": "weatherforecast", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:5050" + } + }, + "$schema": "https://json.schemastore.org/launchsettings.json" +} \ No newline at end of file diff --git a/Src/Dlhis.Message/Services/IVisitorAppointmentService.cs b/Src/Dlhis.Message/Services/IVisitorAppointmentService.cs new file mode 100644 index 00000000..09489134 --- /dev/null +++ b/Src/Dlhis.Message/Services/IVisitorAppointmentService.cs @@ -0,0 +1,6 @@ +namespace Dlhis.Message.Services; + +public interface IVisitorAppointmentService +{ + Task Raise(Dictionary obj); +} diff --git a/Src/Dlhis.Message/TestBackgroundService.cs b/Src/Dlhis.Message/TestBackgroundService.cs new file mode 100644 index 00000000..f25ab20e --- /dev/null +++ b/Src/Dlhis.Message/TestBackgroundService.cs @@ -0,0 +1,26 @@ + +using Dlhis.Message.Services; +using Microsoft.AspNetCore.SignalR; + +namespace Dlhis.Message +{ + public class TestBackgroundService : BackgroundService, ISingletonDependency + { + private readonly IHubContext _hubContext; + + public TestBackgroundService(IHubContext hubContext) + { + _hubContext = hubContext; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + await _hubContext.Clients.All.Raise(new Dictionary { ["name"] = "ligy" }); + + await Task.Delay(1000 * 10); + } + } + } +} diff --git a/Src/Dlhis.Message/VisitorAppointmentHub.cs b/Src/Dlhis.Message/VisitorAppointmentHub.cs new file mode 100644 index 00000000..2b1405c5 --- /dev/null +++ b/Src/Dlhis.Message/VisitorAppointmentHub.cs @@ -0,0 +1,19 @@ +using Dlhis.Message.Services; +using Microsoft.AspNetCore.SignalR; + +namespace Dlhis.Message; + +public class VisitorAppointmentHub : Hub +{ + private readonly ILogger _logger; + + public VisitorAppointmentHub(ILogger logger) + { + _logger = logger; + } + + public override async Task OnConnectedAsync() + { + _logger.LogInformation("链接"); + } +} diff --git a/Src/Dlhis.Message/appsettings.Development.json b/Src/Dlhis.Message/appsettings.Development.json new file mode 100644 index 00000000..737d4399 --- /dev/null +++ b/Src/Dlhis.Message/appsettings.Development.json @@ -0,0 +1,25 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "SwaggerOptions": { + "Enable": true, + "Authority": "https://yikatong.isawesome.cn/oauth2", + "ClientId": "4fb184324eac4180", + "ClientSecret": "8ac8f235152f1524", + "Scopes": { + "openid": "openid", + "profile": "profile", + "yikatong": "yikatong" + } + }, + "IdentityServerOptions": { + "Authority": "https://yikatong.isawesome.cn/oauth2", + "RequireHttpsMetadata": true, + "Issuer": "identity.isawesome.cn", + "Audience": "" + } +} diff --git a/Src/Dlhis.Message/appsettings.json b/Src/Dlhis.Message/appsettings.json new file mode 100644 index 00000000..5629eb3b --- /dev/null +++ b/Src/Dlhis.Message/appsettings.json @@ -0,0 +1,72 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "SqlSugarOptions": { + "DefaultConnectionString": "server=192.168.199.124;port=3306;userid=root;password=dlhis123;database=yikatong;charset=utf8mb4;", + "SlaveConnectionString": [], + "Timeout": 30, + "SlowSqlTime": 1, + "EnableSqlLog": false + }, + "SwaggerOptions": { + "Enable": true, + "Authority": "http://identity.oauth.svc.cluster.local", + "ClientId": "4fb184324eac4180", + "ClientSecret": "8ac8f235152f1524", + "Scopes": { + "openid": "openid", + "profile": "profile", + "yikatong": "yikatong" + } + }, + "IdentityServerOptions": { + "Authority": "http://identity.oauth.svc.cluster.local", + "RequireHttpsMetadata": false, + "Issuer": "identity.isawesome.cn", + "Audience": "", + "Pat": { + "Enable": false, + "Scheme": "token", + "ClientId": "reference", + "ClientSecret": "123456" + } + }, + "Serilog": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "System": "Warning", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "WriteTo": [ + { + "Name": "Async", + "Args": { + "configure": [ + { + "Name": "Console", + "Args": { + "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "MySQL", + "Args": { + "connectionString": "server=192.168.199.124;port=3306;userid=root;password=dlhis123;database=logs;charset=utf8mb4;", + "tableName": "Logs", + "autoCreateSqlTable": true + } + } + ] + } + } + ] + } +} diff --git a/Src/Dlhis.ScheduledTask/BaseJob.cs b/Src/Dlhis.ScheduledTask/BaseJob.cs index 702f5530..c8dcaa44 100644 --- a/Src/Dlhis.ScheduledTask/BaseJob.cs +++ b/Src/Dlhis.ScheduledTask/BaseJob.cs @@ -30,7 +30,7 @@ public abstract class BaseJob : IJob sqlSugarOptionsService.IgnoreTenant = true; var name = this.GetType().GetCustomAttribute()!.Name; - Logger.LogInformation("[{name}]开始执行...", name); + Logger.LogDebug("[{name}]开始执行...", name); try { @@ -42,7 +42,7 @@ public abstract class BaseJob : IJob } finally { - Logger.LogInformation("[{name}]执行结束...", name); + Logger.LogDebug("[{name}]执行结束...", name); DbContext.Client.QueryFilter.Restore(); sqlSugarOptionsService.IgnoreTenant = false; } diff --git a/Src/Dlhis.ScheduledTask/TaskAssignment/Dto/TaskDto.cs b/Src/Dlhis.ScheduledTask/TaskAssignment/Dto/TaskDto.cs new file mode 100644 index 00000000..b64dfcc0 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/TaskAssignment/Dto/TaskDto.cs @@ -0,0 +1,25 @@ +using Dlhis.Entity.Device.Enums; + +namespace Dlhis.ScheduledTask.TaskAssignment.Dto; + +public class TaskDto +{ + public long TaskId { get; set; } + public long? UserId { get; set; } + + public DeviceTaskEnumType Type { get; set; } + public string DeviceUniqueNo { get; set; } + public string DeviceConnectionInfo { get; set; } + public string Brand { get; set; } + public string FuncStr { get; set; } + public string UserNo { get; set; } + public string UserCode { get; set; } + public string UserName { get; set; } + public string DepartmentNo { get; set; } + public string DepartmentName { get; set; } + public string CardNo { get; set; } + + public int Version { get; set; } + + public DeviceTaskStatusEnumType Status { get; set; } +} diff --git a/Src/Dlhis.ScheduledTask/TaskAssignment/Services/Implements/AssignmentService.cs b/Src/Dlhis.ScheduledTask/TaskAssignment/Services/Implements/AssignmentService.cs index c3e4bb5d..fb628937 100644 --- a/Src/Dlhis.ScheduledTask/TaskAssignment/Services/Implements/AssignmentService.cs +++ b/Src/Dlhis.ScheduledTask/TaskAssignment/Services/Implements/AssignmentService.cs @@ -13,6 +13,7 @@ using Newtonsoft.Json.Linq; using Kurisu.Core.CustomClass; using Kurisu.AspNetCore; using Kurisu.AspNetCore.Utils; +using Dlhis.ScheduledTask.TaskAssignment.Dto; namespace Dlhis.ScheduledTask.TaskAssignment.Services.Implements; @@ -21,248 +22,158 @@ public class AssignmentService : IAssignmentService private readonly IDbContext _dbContext; private readonly IDataProtectionProvider _dataProtectionProvider; private readonly FaceUrlOptions _faceUrlOptions; - private readonly ILogger _logger; public AssignmentService(IDbContext dbContext, IDataProtectionProvider dataProtectionProvider, - IOptions options, - ILogger logger) + IOptions options) { _dbContext = dbContext; _dataProtectionProvider = dataProtectionProvider; _faceUrlOptions = options.Value; - _logger = logger; } public async Task> DeviceGetTasksAsync(DeviceTaskGetRequest request) { - ////获取心跳设备 todo - //var key = "heardbeat-devices"; - //var heartbeatDeviceNos = (await _redisCache.ListRangeAsync(key))?.Select(x => x.ToString()).ToList(); + var data = await GetDataAsync(request); + if (data.IsEmpty()) return new List(); - var data = await CommonHelper.RetryAsync(async () => - { - var page = await _dbContext.Queryable() - .LeftJoin((deviceTask, deivce) => deviceTask.DeviceUniqueNo == deivce.UniqueNo) - .LeftJoin((deviceTask, deivce, deivceTamplate) => deivceTamplate.Code == deivce.TemplateCode) - .LeftJoin((deviceTask, deivce, deivceTamplate, ga) => deviceTask.UserNo == ga.No) - .LeftJoin((deviceTask, deivce, deivceTamplate, ga, galeave) => deviceTask.UserNo == galeave.No) - .LeftJoin((deviceTask, deivce, deivceTamplate, ga, galeave, department) => department.No == ga.DepartmentNo) - .WhereIF(request.Brand.IsPresent(), (deviceTask, deivce, deivceTamplate) => deivceTamplate.Brand == request.Brand) - .WhereIF(request.DeviceUniqueNo.IsPresent(), (deviceTask, deivce) => deviceTask.DeviceUniqueNo == request.DeviceUniqueNo) - .WhereIF(request.Types.IsPresent(), deviceTask => request.Types.Contains(deviceTask.Type)) - .WhereIF(!request.IsProcess, deviceTask => deviceTask.Status == DeviceTaskStatusEnumType.Wait) - .WhereIF(request.IsProcess, deviceTask => deviceTask.Status == DeviceTaskStatusEnumType.Process - && SqlFunc.DateDiff(DateType.Minute, deviceTask.ModifiedTime, DateTime.Now) > 30) - //.Where(deviceTask => heartbeatDeviceNos.Contains(deviceTask.DeviceUniqueNo)) - .OrderBy(deviceTask => new { Priority = SqlFunc.Desc(deviceTask.Priority), deviceTask.CreateTime }) - .Select((deviceTask, deivce, deivceTamplate, ga, galeave, department) => new - { - UserId = SqlFunc.IsNull(SqlFunc.IsNull(deviceTask.UserId, ga.Id), galeave.IdentityUserId), - TaskId = deviceTask.Id, - deviceTask.Type, - deviceTask.DeviceUniqueNo, - DeviceConnectionInfo = deivce.ConnectionInfo, - deivceTamplate.Brand, - FuncStr = deivce.Funcs.ToString(), - deviceTask.UserNo, - UserCode = SqlFunc.IsNull(ga.Code, galeave.Code), - UserName = SqlFunc.IsNull(ga.Name, galeave.Name), - ga.DepartmentNo, - DepartmentName = department.Name, - ga.CardNo, - deviceTask.Version - }) - .ToPageListAsync(request); - - if (!page.Data.Any()) - { - return page.Data; - } - - var taskIdVs = page.Data.Select(x => new { x.TaskId, x.Version }).ToList(); - var where = LinqExpressionExtensions.False(); - taskIdVs.ForEach(p => - { - where = where.Or(x => x.Id == p.TaskId && x.Version == p.Version && x.Status != DeviceTaskStatusEnumType.Success); - }); - - var effecet = await _dbContext.Updateable() - .SetColumns(x => x.Version == x.Version + 1) - .SetColumns(x => x.Status == DeviceTaskStatusEnumType.Process) - .SetColumns(x => x.ModifiedTime == DateTime.Now) - .Where(where) - .ExecuteCommandAsync(); - - (taskIdVs.Count != effecet).ThrowIfTrue("获取任务失败"); - - return page.Data; - - }, 5); - - if (!data.Any()) - { - return new List(); - } - - Dictionary deviceUploadInfos = null; - if (data.Any(x => x.Type == DeviceTaskEnumType.UploadRecord)) - { - var deviceNos = data.Select(x => x.DeviceUniqueNo).Distinct(); - deviceUploadInfos = new Dictionary(deviceNos.Count()); - - var logInfos = await _dbContext.Queryable().Select(it => new - { - RowNumber = SqlFunc.RowNumber(SqlFunc.Desc(it.Id), it.DeviceUniqueNo), - it.DeviceUniqueNo, - it.RaiseDateTime - }) - .MergeTable() - .Where(it => it.RowNumber == 1) - .ToListAsync(); - - foreach (var item in deviceNos) - { - var logInfo = logInfos.FirstOrDefault(x => x.DeviceUniqueNo == item); - deviceUploadInfos.Add(item, logInfo?.RaiseDateTime); - } - } + var deviceUploadInfos = await GetDeviceUploadRecordInfosAsync(data); var timeLimitedDataProtector = _dataProtectionProvider .CreateProtector("down:face") .ToTimeLimitedDataProtector(); return data.GroupBy(x => new { x.Brand, x.DeviceUniqueNo, x.DeviceConnectionInfo, x.FuncStr }) - .Select(x => - { - var b = x.Key.Brand; - var d = x.Key.DeviceUniqueNo; - var dc = x.Key.DeviceConnectionInfo ?? "{}"; - var func = x.Key.FuncStr ?? "[]"; + .Select(x => + { + var b = x.Key.Brand; + var d = x.Key.DeviceUniqueNo; + var dc = x.Key.DeviceConnectionInfo ?? "{}"; + var func = x.Key.FuncStr ?? "[]"; - var jobj = new JObject - { - { "connectionInfo", JToken.Parse(dc) }, - { "function", JArray.Parse(func) } - }; + var jobj = new JObject + { + { "connectionInfo", JToken.Parse(dc) }, + { "function", JArray.Parse(func) } + }; - return new DeviceTaskToDeviceByDeviceResponse - { - Brand = b, - DeviceUniqueNo = d, - DeviceInfo = jobj, - Tasks = x.AsEnumerable().Select(item => - { - var key = $"face:{item.UserCode}"; - var token = item.Type == DeviceTaskEnumType.Delete - ? string.Empty - : timeLimitedDataProtector.Protect(key, TimeSpan.FromSeconds(_faceUrlOptions.Limit)); + return new DeviceTaskToDeviceByDeviceResponse + { + Brand = b, + DeviceUniqueNo = d, + DeviceInfo = jobj, + Tasks = x.Select(item => + { + var key = $"face:{item.UserCode}"; + var token = item.Type == DeviceTaskEnumType.Delete + ? string.Empty + : timeLimitedDataProtector.Protect(key, TimeSpan.FromSeconds(_faceUrlOptions.Limit)); - var dto = new TaskCombineDto - { - TaskId = item.TaskId, - Type = item.Type, - }; + var dto = new TaskCombineDto + { + TaskId = item.TaskId, + Type = item.Type, + }; - switch (dto.Type) - { - case DeviceTaskEnumType.Add: - case DeviceTaskEnumType.Delete: - case DeviceTaskEnumType.Update: - { - dto.Info = new UserToDeviceResponse - { - UserId = item.UserId.Value, - UserNo = item.UserNo, - UserCode = item.UserCode, - UserName = item.UserName, - DepartmentNo = item.DepartmentNo, - DepartmentName = item.DepartmentName, - CardNo = item.Type == DeviceTaskEnumType.Delete ? string.Empty : item.CardNo, - Face = item.Type == DeviceTaskEnumType.Delete ? string.Empty : _faceUrlOptions.Url + token,//下发才附带照片信息 - ValidDatePeriod = new DatePeriod - { - Start = DateOnly.FromDateTime(DateTime.Now.AddDays(-1)), - End = DateOnly.FromDateTime(DateTime.Now.AddYears(20)), - }, - TimePeriods = new List { 1 }, - Doors = new List { 1 }, - Schedule = 1 - }; - } - break; - case DeviceTaskEnumType.TimePeriodAdd: - case DeviceTaskEnumType.TimePeriodDelete: - { - dto.Info = new TimePeriodToDeviceResponse - { - Id = 1, - Name = "小白领", - Enable = true, - Sections = new List() - { - new() - { - DayOfWeek= DayOfWeek.Monday, - TimePeriods = new List() - { - new() - { - Start = TimeOnly.Parse("08:00:00"), - End = TimeOnly.Parse("17:30:00"), - }, - } - } - } - }; - } - break; - case DeviceTaskEnumType.ScheduleAdd: - case DeviceTaskEnumType.ScheduleDelete: - { - dto.Info = new ScheduleToDeviceResponse - { - Id = 1, - Enable = true, - Name = "计划的一部分", - Schedules = new List - { - new() - { - Name = "国庆节", - DateTimePeriod = new DateTimePeriod + switch (dto.Type) + { + case DeviceTaskEnumType.Add: + case DeviceTaskEnumType.Delete: + case DeviceTaskEnumType.Update: + { + dto.Info = new UserToDeviceResponse + { + UserId = item.UserId.HasValue ? item.UserId.Value : 0, + UserNo = item.UserNo, + UserCode = item.UserCode, + UserName = item.UserName, + DepartmentNo = item.DepartmentNo, + DepartmentName = item.DepartmentName, + CardNo = item.Type == DeviceTaskEnumType.Delete ? string.Empty : item.CardNo, + Face = item.Type == DeviceTaskEnumType.Delete ? string.Empty : _faceUrlOptions.Url + token,//下发才附带照片信息 + ValidDatePeriod = new DatePeriod + { + Start = DateOnly.FromDateTime(DateTime.Now.AddDays(-1)), + End = DateOnly.FromDateTime(DateTime.Now.AddYears(20)), + }, + TimePeriods = new List { 1 }, + Doors = new List { 1 }, + Schedule = 1 + }; + } + break; + case DeviceTaskEnumType.TimePeriodAdd: + case DeviceTaskEnumType.TimePeriodDelete: + { + dto.Info = new TimePeriodToDeviceResponse + { + Id = 1, + Name = "小白领", + Enable = true, + Sections = new List() + { + new() + { + DayOfWeek= DayOfWeek.Monday, + TimePeriods = new List() { - Start = new DateTime(2024,10,1), - End = new DateTime(2024,10,7) + new() + { + Start = TimeOnly.Parse("08:00:00"), + End = TimeOnly.Parse("17:30:00"), + }, } - } - } - }; - } - break; + } + } + }; + } + break; + case DeviceTaskEnumType.ScheduleAdd: + case DeviceTaskEnumType.ScheduleDelete: + { + dto.Info = new ScheduleToDeviceResponse + { + Id = 1, + Enable = true, + Name = "计划的一部分", + Schedules = new List + { + new() + { + Name = "国庆节", + DateTimePeriod = new DateTimePeriod + { + Start = new DateTime(2024,10,1), + End = new DateTime(2024,10,7) + } + } + } + }; + } + break; - case DeviceTaskEnumType.UploadRecord: - { - dto.Info = new UploadRecordToDeviceResponse - { - DateTimePeriod = new DateTimePeriod - { - Start = deviceUploadInfos[d] ?? DateTime.Now, - End = DateTime.Now.AddDays(1) - } - }; - } - break; - default: - break; - } + case DeviceTaskEnumType.UploadRecord: + { + dto.Info = new UploadRecordToDeviceResponse + { + DateTimePeriod = new DateTimePeriod + { + Start = deviceUploadInfos[d] ?? DateTime.Now, + End = DateTime.Now.AddDays(1) + } + }; + } + break; + default: + break; + } - return dto; + return dto; - }).ToList() - }; + }).ToList() + }; - }).ToList(); + }).ToList(); } /// @@ -314,4 +225,101 @@ public class AssignmentService : IAssignmentService await _dbContext.UpdateAsync(deviceTasks); } + + + //**************************************************** help method ************************************************** + + private async Task> GetDataAsync(DeviceTaskGetRequest request) + { + var data = await CommonHelper.RetryAsync(async () => + { + var page = await _dbContext.Queryable() + .LeftJoin((deviceTask, deivce) => deviceTask.DeviceUniqueNo == deivce.UniqueNo) + .LeftJoin((deviceTask, deivce, deivceTamplate) => deivceTamplate.Code == deivce.TemplateCode) + .LeftJoin((deviceTask, deivce, deivceTamplate, ga) => deviceTask.UserNo == ga.No) + .LeftJoin((deviceTask, deivce, deivceTamplate, ga, galeave) => deviceTask.UserNo == galeave.No) + .LeftJoin((deviceTask, deivce, deivceTamplate, ga, galeave, department) => department.No == ga.DepartmentNo) + .LeftJoin((deviceTask, deivce, deivceTamplate, ga, galeave, department, gainfoEx) => deviceTask.UserNo == gainfoEx.No) + .WhereIF(!request.IsProcess, deviceTask => deviceTask.Status == DeviceTaskStatusEnumType.Wait) + .WhereIF(request.IsProcess, deviceTask => deviceTask.Status == DeviceTaskStatusEnumType.Process + && SqlFunc.DateDiff(DateType.Minute, deviceTask.ModifiedTime, DateTime.Now) > 30) + .WhereIF(request.DeviceUniqueNo.IsPresent(), (deviceTask, deivce) => deviceTask.DeviceUniqueNo == request.DeviceUniqueNo) + .WhereIF(request.Types.IsPresent(), deviceTask => request.Types.Contains(deviceTask.Type)) + .WhereIF(request.Brand.IsPresent(), (deviceTask, deivce, deivceTamplate) => deivceTamplate.Brand == request.Brand) + .OrderBy(deviceTask => new { Priority = SqlFunc.Desc(deviceTask.Priority), deviceTask.CreateTime }) + .Select((deviceTask, deivce, deivceTamplate, ga, galeave, department, gainfoEx) => new TaskDto + { + UserId = SqlFunc.IsNull(SqlFunc.IsNull(deviceTask.UserId, ga.Id), galeave.IdentityUserId), + TaskId = deviceTask.Id, + Type = deviceTask.Type, + DeviceUniqueNo = deviceTask.DeviceUniqueNo, + DeviceConnectionInfo = deivce.ConnectionInfo, + Brand = deivceTamplate.Brand, + FuncStr = deivce.Funcs.ToString(), + UserNo = deviceTask.UserNo, + UserCode = SqlFunc.IsNull(SqlFunc.IsNull(ga.Code, galeave.Code), gainfoEx.Code), + UserName = SqlFunc.IsNull(SqlFunc.IsNull(ga.Name, galeave.Name), gainfoEx.Name), + DepartmentNo = ga.DepartmentNo, + DepartmentName = department.Name, + CardNo = ga.CardNo, + Version = deviceTask.Version, + Status = deviceTask.Status + }) + .ToPageListAsync(request); + + if (!page.Data.Any()) + { + return page.Data; + } + + //var taskIdVs = page.Data.Select(x => new { x.TaskId, x.Version, x.Status }).ToList(); + //var where = LinqExpressionExtensions.False(); + //taskIdVs.ForEach(p => + //{ + // where = where.Or(x => x.Id == p.TaskId && x.Version == p.Version && x.Status == p.Status); + //}); + + //var effecet = await _dbContext.Updateable() + // .SetColumns(x => x.Version == x.Version + 1) + // .SetColumns(x => x.Status == DeviceTaskStatusEnumType.Process) + // .SetColumns(x => x.ModifiedTime == DateTime.Now) + // .Where(where) + // .ExecuteCommandAsync(); + + //(taskIdVs.Count != effecet).ThrowIfTrue("获取任务失败"); + + return page.Data; + + }, 5); + + return data; + } + + private async Task> GetDeviceUploadRecordInfosAsync(List data) + { + if (data.Any(x => x.Type == DeviceTaskEnumType.UploadRecord)) + { + var deviceNos = data.Select(x => x.DeviceUniqueNo).Distinct(); + var result = new Dictionary(deviceNos.Count()); + + //日志数据最后一条 + var logInfos = await _dbContext.Queryable().Select(it => new + { + RowNumber = SqlFunc.RowNumber(SqlFunc.Desc(it.Id), it.DeviceUniqueNo), + it.DeviceUniqueNo, + it.RaiseDateTime + }) + .MergeTable() + .Where(it => it.RowNumber == 1) + .ToListAsync(); + + foreach (var item in deviceNos) + { + var logInfo = logInfos.FirstOrDefault(x => x.DeviceUniqueNo == item); + result.Add(item, logInfo?.RaiseDateTime); + } + } + + return new Dictionary(); + } } diff --git a/Src/Dlhis.Visitor/Appointment/Controllers/AppointmentsController.cs b/Src/Dlhis.Visitor/Appointment/Controllers/AppointmentsController.cs new file mode 100644 index 00000000..5923bd8c --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Controllers/AppointmentsController.cs @@ -0,0 +1,84 @@ +using System.ComponentModel.DataAnnotations; +using Dlhis.Visitor.Appointment.Request; +using Dlhis.Visitor.Appointment.Response; +using Dlhis.Visitor.Appointment.Services; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop; +using Kurisu.Core.DataAccess.Dto; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Dlhis.Visitor.Appointment.Controllers; + +/// +/// ԤԼ +/// +[Authorize] +[ApiController] +[Route("api/[controller]")] +public class AppointmentsController : ControllerBase +{ + private readonly IAppointmentService _appointmentService; + + public AppointmentsController(IAppointmentService appointmentService) + { + _appointmentService = appointmentService; + } + + /// + /// ½ÓÊÜԤԼдÈë + /// + /// + /// + [AllowAnonymous] + [Transactional] + [IgnoreTenant] + [HttpPost("receive")] + public async Task ReceiveAsync(AppointmentReceiveRequest request) + { + await _appointmentService.ReceiveAsync(request); + } + + /// + /// ԤԼ·Öҳ + /// + /// + /// + [HttpGet("page")] + public async Task> GetPageAsync([FromQuery] AppointmentPageRequest request) + { + return await _appointmentService.GetPageAsync(request); + } + + /// + /// ȷÈϵ½´ï + /// + /// + /// + [HttpPost("confirm")] + public async Task ConfirmAsync(AppointmentConfirmRequest request) + { + await _appointmentService.ConfirmAsync(request); + } + + /// + /// ¸ù¾ÝÉí·Ý֤»ñȡµ±Ìì·ÿÍԤԼ + /// + /// + /// + [AllowAnonymous] + [HttpGet("today")] + public async Task GetTodayByIdNoAsync( + [FromQuery] + [StringLength(18, MinimumLength = 18, ErrorMessage = "Éí·Ý֤´íÎó")] + [Required(ErrorMessage = "Éí·Ý֤²»¿ÉΪ¿Õ")]string idNo) + { + return await _appointmentService.GetTodayByIdNoAsync(idNo); + } + + [AllowAnonymous] + [HttpGet("idno/page")] + public async Task> GetRecordPageByIdNoAsync([FromQuery] AppointmentIdNoPageRequest request) + { + return await _appointmentService.GetRecordPageByIdNoAsync(request); + } +} diff --git a/Src/Dlhis.Visitor/Appointment/Controllers/ApponintmentAreasController.cs b/Src/Dlhis.Visitor/Appointment/Controllers/ApponintmentAreasController.cs new file mode 100644 index 00000000..c7055988 --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Controllers/ApponintmentAreasController.cs @@ -0,0 +1,68 @@ +using Dlhis.Visitor.Appointment.Request; +using Dlhis.Visitor.Appointment.Response; +using Dlhis.Visitor.Appointment.Services; +using Kurisu.Core.DataAccess.Dto; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Dlhis.Visitor.Appointment.Controllers; + +/// +/// 预约区域 +/// +[Authorize] +[Route("api/[controller]")] +[ApiController] +public class ApponintmentAreasController : ControllerBase +{ + private readonly IApponintmentAreaService _apponintmentAreaService; + + public ApponintmentAreasController(IApponintmentAreaService apponintmentAreaService) + { + _apponintmentAreaService = apponintmentAreaService; + } + + /// + /// 预约区域 + /// + /// + /// + [HttpGet("page")] + public async Task> GetPageAsync([FromQuery] PageDto request) + { + return await _apponintmentAreaService.GetPageAsync(request); + } + + /// + /// 保存 + /// + /// + /// + [HttpPost("save")] + public async Task SaveAsync(AppointmentAreaSaveRequest request) + { + await _apponintmentAreaService.SaveAsync(request); + } + + + /// + /// 删除 + /// + /// + /// + [HttpDelete("{id}")] + public async Task DeleteAsync(long id) + { + await _apponintmentAreaService.DeleteAsync(id); + } + + /// + /// 分配设备组 + /// + /// + [HttpPost("assign")] + public async Task AssignAsync(AppointmentAreaAssignRequest request) + { + await _apponintmentAreaService.AssignAsync(request); + } +} diff --git a/Src/Dlhis.Visitor/Appointment/Dto/AppointmentReceiveItemDto.cs b/Src/Dlhis.Visitor/Appointment/Dto/AppointmentReceiveItemDto.cs new file mode 100644 index 00000000..57cf552c --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Dto/AppointmentReceiveItemDto.cs @@ -0,0 +1,31 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dlhis.Visitor.Appointment.Dto; + +public class AppointmentReceiveItemDto +{ + /// + /// 姓名 + /// + [Required(ErrorMessage = "姓名必填")] + public string Name { get; set; } + + /// + /// 手机号 + /// + [StringLength(11, MinimumLength = 11)] + [Required(ErrorMessage = "手机号必填")] + public string Phone { get; set; } + + /// + /// 身份证 + /// + [StringLength(18, MinimumLength = 18)] + [Required(ErrorMessage = "身份证必填")] + public string IdNo { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } +} diff --git a/Src/Dlhis.Visitor/Appointment/Request/AppointmentAreaAssignRequest.cs b/Src/Dlhis.Visitor/Appointment/Request/AppointmentAreaAssignRequest.cs new file mode 100644 index 00000000..7ef2b7e9 --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Request/AppointmentAreaAssignRequest.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dlhis.Visitor.Appointment.Request; + +public class AppointmentAreaAssignRequest +{ + /// + /// 预约区域编码 + /// + [Required] + public string CustomCode { get; set; } + + + /// + /// 分组 + /// + public List GroupCodes { get; set; } +} diff --git a/Src/Dlhis.Visitor/Appointment/Request/AppointmentAreaSaveRequest.cs b/Src/Dlhis.Visitor/Appointment/Request/AppointmentAreaSaveRequest.cs new file mode 100644 index 00000000..7a0ba649 --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Request/AppointmentAreaSaveRequest.cs @@ -0,0 +1,35 @@ +using System.ComponentModel.DataAnnotations; +using Dlhis.Entity.Visitor.Enums; + +namespace Dlhis.Visitor.Appointment.Request; + +public class AppointmentAreaSaveRequest +{ + /// + /// 数据id + /// + public long? Id { get; set; } + + /// + /// 区域 AppointmentAreaEnumType + /// + [EnumDataType(typeof(AppointmentAreaEnumType))] + public AppointmentAreaEnumType Type { get; set; } + + /// + /// 预期编码 + /// + [Required] + public string CustomCode { get; set; } + + /// + /// 姓名 + /// + [Required] + public string Name { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } +} diff --git a/Src/Dlhis.Visitor/Appointment/Request/AppointmentConfirmRequest.cs b/Src/Dlhis.Visitor/Appointment/Request/AppointmentConfirmRequest.cs new file mode 100644 index 00000000..240e79d2 --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Request/AppointmentConfirmRequest.cs @@ -0,0 +1,6 @@ +namespace Dlhis.Visitor.Appointment.Request; + +public class AppointmentConfirmRequest +{ + public long Id { get; set; } +} diff --git a/Src/Dlhis.Visitor/Appointment/Request/AppointmentIdNoPageRequest.cs b/Src/Dlhis.Visitor/Appointment/Request/AppointmentIdNoPageRequest.cs new file mode 100644 index 00000000..bca1f311 --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Request/AppointmentIdNoPageRequest.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; +using Kurisu.Core.DataAccess.Dto; + +namespace Dlhis.Visitor.Appointment.Request; + +public class AppointmentIdNoPageRequest : PageDto +{ + /// + /// 身份证 + /// + [StringLength(18, MinimumLength = 18, ErrorMessage = "身份证错误")] + [Required(ErrorMessage = "身份证不可为空")] + public string IdNo { get; set; } +} diff --git a/Src/Dlhis.Visitor/Appointment/Request/AppointmentPageRequest.cs b/Src/Dlhis.Visitor/Appointment/Request/AppointmentPageRequest.cs new file mode 100644 index 00000000..88d7be1c --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Request/AppointmentPageRequest.cs @@ -0,0 +1,9 @@ +using Kurisu.Core.CustomClass; +using Kurisu.Core.DataAccess.Dto; + +namespace Dlhis.Visitor.Appointment.Request; + +public class AppointmentPageRequest : PageDto +{ + public DateTimePeriod SearchDateTimePeriod { get; set; } +} diff --git a/Src/Dlhis.Visitor/Appointment/Request/AppointmentReceiveRequest.cs b/Src/Dlhis.Visitor/Appointment/Request/AppointmentReceiveRequest.cs new file mode 100644 index 00000000..3028e970 --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Request/AppointmentReceiveRequest.cs @@ -0,0 +1,83 @@ +using System.ComponentModel.DataAnnotations; +using Dlhis.Visitor.Appointment.Dto; + +namespace Dlhis.Visitor.Appointment.Request; + +public class AppointmentReceiveRequest : IValidatableObject +{ + /// + /// 流水号 + /// + [Required(ErrorMessage = "流水号必填")] + public string FlowId { get; set; } + + /// + /// 标题 + /// + [Required(ErrorMessage = "标题必填")] + public string Title { get; set; } + + /// + /// 对接人工号 + /// + [Required(ErrorMessage = "对接人工号必填")] + public string Code { get; set; } + + /// + /// 对接人姓名 + /// + [Required(ErrorMessage = "对接人姓名必填")] + public string Name { get; set; } + + /// + /// 申请时间 + /// + [Required(ErrorMessage = "申请时间必填")] + public DateTime ApplyTime { get; set; } + + /// + /// 预约区域 + /// + [Required(ErrorMessage = "申请预约区域必填")] + public string ApplyArea { get; set; } + + /// + /// 来源公司 + /// + [Required(ErrorMessage = "来源公司")] + public string Company { get; set; } + + /// + /// 来访时间 + /// + public DateTime Start { get; set; } + + /// + /// 离开时间 + /// + public DateTime End { get; set; } + + /// + /// 描述 + /// + public string Description { get; set; } + + /// + /// 厂区 + /// + public string Factory { get; set; } + + /// + /// 明细 + /// + [MinLength(1, ErrorMessage = "明细必填")] + public List Items { get; set; } + + public IEnumerable Validate(ValidationContext validationContext) + { + if (Start >= End) + { + yield return new ValidationResult("来访时间不能大于等于离开时间", new[] { nameof(Start), nameof(End) }); + } + } +} diff --git a/Src/Dlhis.Visitor/Appointment/Request/ApponintmentAreaSaveRequest.cs b/Src/Dlhis.Visitor/Appointment/Request/ApponintmentAreaSaveRequest.cs new file mode 100644 index 00000000..40005e9d --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Request/ApponintmentAreaSaveRequest.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; +using Dlhis.Entity.Visitor.Enums; + +namespace Dlhis.Visitor.Appointment.Request +{ + public class ApponintmentAreaSaveRequest + { + public long? Id { get; set; } + + /// + /// + /// + [EnumDataType(typeof(AppointmentAreaEnumType))] + public AppointmentAreaEnumType Type { get; set; } + + public string CustomCode { get; set; } + } +} diff --git a/Src/Dlhis.Visitor/Appointment/Response/AppointmentDetailResponse.cs b/Src/Dlhis.Visitor/Appointment/Response/AppointmentDetailResponse.cs new file mode 100644 index 00000000..322e396b --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Response/AppointmentDetailResponse.cs @@ -0,0 +1,56 @@ +using Dlhis.Entity.Visitor.Enums; +using Kurisu.AspNetCore.Utils.Extensions; + +namespace Dlhis.Visitor.Appointment.Response; + +public class AppointmentDetailResponse +{ + public long Id { get; set; } + + public long AppointmentId { get; set; } + + /// + /// 流水号 + /// + public string FlowId { get; set; } + + /// + /// 访客名称 + /// + public string Name { get; set; } + + /// + /// 手机号 + /// + public string Phone { get; set; } + + /// + /// 身份证 + /// + public string IdNo { get; set; } + + /// + /// 预计到达 + /// + public DateTime Start { get; set; } + + /// + /// 预计离开 + /// + public DateTime End { get; set; } + + /// + /// 状态 + /// + public AppointmentDetailEnumType Status { get; set; } + + /// + /// 状态 + /// + public string StatusDesc => Status.GetDescription(); + + /// + /// 备注 + /// + public string Remark { get; set; } +} diff --git a/Src/Dlhis.Visitor/Appointment/Response/AppointmentPageResponse.cs b/Src/Dlhis.Visitor/Appointment/Response/AppointmentPageResponse.cs new file mode 100644 index 00000000..8a0de429 --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Response/AppointmentPageResponse.cs @@ -0,0 +1,22 @@ +namespace Dlhis.Visitor.Appointment.Response; + +public class AppointmentPageResponse +{ + public string FlowId { get; set; } + + public string Title { get; set; } + + public string Code { get; set; } + + public string Name { get; set; } + + public string Description { get; set; } + + public string DepartmentNo { get; set; } + + public string DepartmentName { get; set; } + + public string Company { get; set; } + + public DateTime ApplyTime { get; set; } +} diff --git a/Src/Dlhis.Visitor/Appointment/Response/ApponintmentAreaPageResponse.cs b/Src/Dlhis.Visitor/Appointment/Response/ApponintmentAreaPageResponse.cs new file mode 100644 index 00000000..6197d54f --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Response/ApponintmentAreaPageResponse.cs @@ -0,0 +1,34 @@ +using Dlhis.Entity.Visitor.Enums; +using Kurisu.AspNetCore.Utils.Extensions; + +namespace Dlhis.Visitor.Appointment.Response; + +public class ApponintmentAreaPageResponse +{ + public long Id { get; set; } + + /// + /// 区域类型 + /// + public AppointmentAreaEnumType Type { get; set; } + + /// + /// 区域类型 + /// + public string TypeDesc => Type.GetDescription(); + + /// + /// 自定义编码 + /// + public string CustomCode { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } +} diff --git a/Src/Dlhis.Visitor/Appointment/Services/IAppointmentService.cs b/Src/Dlhis.Visitor/Appointment/Services/IAppointmentService.cs new file mode 100644 index 00000000..f020bfb9 --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Services/IAppointmentService.cs @@ -0,0 +1,42 @@ +using Dlhis.Visitor.Appointment.Request; +using Dlhis.Visitor.Appointment.Response; +using Kurisu.Core.DataAccess.Dto; +using Microsoft.AspNetCore.Mvc; + +namespace Dlhis.Visitor.Appointment.Services; + +public interface IAppointmentService : IScopeDependency +{ + Task ReceiveAsync(AppointmentReceiveRequest request); + + /// + /// 预约分页 + /// + /// + /// + Task> GetPageAsync(AppointmentPageRequest request); + + /// + /// 查看明细 + /// + /// + /// + Task> GetAppointmentDetailsByIdAsync(long id); + + /// + /// 确认到达 + /// + /// + Task ConfirmAsync(AppointmentConfirmRequest request); + + + /// + /// 根据身份证获取最新访客预约 + /// + /// + /// + Task GetTodayByIdNoAsync(string idNo); + + + Task> GetRecordPageByIdNoAsync([FromQuery] AppointmentIdNoPageRequest request); +} diff --git a/Src/Dlhis.Visitor/Appointment/Services/IApponintmentAreaService.cs b/Src/Dlhis.Visitor/Appointment/Services/IApponintmentAreaService.cs new file mode 100644 index 00000000..71804a2d --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Services/IApponintmentAreaService.cs @@ -0,0 +1,17 @@ +using Dlhis.Visitor.Appointment.Request; +using Dlhis.Visitor.Appointment.Response; +using Kurisu.Core.DataAccess.Dto; + +namespace Dlhis.Visitor.Appointment.Services; + +public interface IApponintmentAreaService : IScopeDependency +{ + Task> GetPageAsync(PageDto request); + + Task SaveAsync(AppointmentAreaSaveRequest request); + + Task DeleteAsync(long id); + + + Task AssignAsync(AppointmentAreaAssignRequest request); +} \ No newline at end of file diff --git a/Src/Dlhis.Visitor/Appointment/Services/Implements/AppointmentService.cs b/Src/Dlhis.Visitor/Appointment/Services/Implements/AppointmentService.cs new file mode 100644 index 00000000..c1a65242 --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Services/Implements/AppointmentService.cs @@ -0,0 +1,189 @@ +using Dlhis.Basic.Api; +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Device.Entities; +using Dlhis.Entity.Device.Enums; +using Dlhis.Entity.Visitor.Entity; +using Dlhis.Entity.Visitor.Enums; +using Dlhis.Visitor.Appointment.Request; +using Dlhis.Visitor.Appointment.Response; +using Kurisu.AspNetCore.Utils.Extensions; +using Kurisu.Core.DataAccess.Dto; +using Kurisu.SqlSugar.Extensions; +using Kurisu.SqlSugar.Services; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; + +namespace Dlhis.Visitor.Appointment.Services.Implements; + +public class AppointmentService : IAppointmentService +{ + private readonly IDbContext _dbContext; + private readonly IDeviceGroupApi _deviceGroupApi; + + public AppointmentService(IDbContext dbContext, IDeviceGroupApi deviceGroupApi) + { + _dbContext = dbContext; + _deviceGroupApi = deviceGroupApi; + } + + public async Task ReceiveAsync(AppointmentReceiveRequest request) + { + var exists = await _dbContext.Queryable().Where(x => x.FlowId == request.FlowId).AnyAsync(); + exists.ThrowIfTrue("已经存在申请"); + + var area = await _dbContext.Queryable() + .Where(x => x.Name == request.ApplyArea) + .Where(x => x.TenantId == request.Factory) + .FirstAsync(); + area.ThrowIfNull("预约区域不存在"); + + var where = LinqExpressionExtensions.False(); + request.Items.ForEach(item => + { + where = where.Or(x => !(x.End < request.Start || x.Start > request.End)).And(x => x.IdNo == item.IdNo); + }); + + var existsDetails = await _dbContext.Queryable() + .Where(where) + .Where(x => x.Status == AppointmentDetailEnumType.Wait || x.Status == AppointmentDetailEnumType.Arrived) + .ToListAsync(); + + existsDetails.ThrowIfExists($"{existsDetails.Select(x => x.Name).Join(",")}存在预约时间冲突,请检查"); + + var id = await _dbContext.InsertReturnIdentityAsync(new VisitorAppointmentEntity + { + FlowId = request.FlowId, + Name = request.Name, + Code = request.Code, + Description = request.Description, + Title = request.Title, + Company = request.Company, + ApplyTime = request.ApplyTime, + AreaCustomCode = area.CustomCode, + }); + + foreach (var item in request.Items) + { + var isExternal = !await _dbContext.Queryable().Where(x => x.IdNo == item.IdNo).AnyAsync(); + if (isExternal) + { + var gainfoExternal = await _dbContext.Queryable().Where(x => x.IdNo == item.IdNo).FirstAsync(); + if (gainfoExternal == null) + { + gainfoExternal = new GainfoExternalEntity + { + No = Guid.NewGuid().ToString(), + Code = item.IdNo, + IdNo = item.IdNo, + Name = item.Name, + Company = request.Company, + Phone = item.Phone + }; + await _dbContext.InsertAsync(gainfoExternal); + } + else + { + gainfoExternal.Phone = item.Phone; + gainfoExternal.Company = request.Company; + + await _dbContext.UpdateAsync(gainfoExternal); + } + } + + var detail = new VisitorAppointmentDetailEntity + { + AppointmentId = id, + FlowId = request.FlowId, + Start = request.Start, + End = request.End, + IdNo = item.IdNo, + Name = item.Name, + Phone = item.Phone, + Remark = item.Remark, + Status = AppointmentDetailEnumType.Wait, + IsExternal = isExternal, + }; + + await _dbContext.InsertAsync(detail); + } + } + + public async Task> GetPageAsync(AppointmentPageRequest request) + { + return await _dbContext.Queryable() + .WhereIF(request.SearchDateTimePeriod?.Start.HasValue == true && request.SearchDateTimePeriod?.End.HasValue == true, + x => x.ApplyTime >= request.SearchDateTimePeriod.Start && x.ApplyTime <= request.SearchDateTimePeriod.End) + .WhereIF(request.Search.IsPresent(), x => x.Code == request.Search || x.Name == request.Search) + .Select() + .ToPageListAsync(request); + } + + public async Task> GetAppointmentDetailsByIdAsync(long id) + { + return await _dbContext.Queryable() + .Where(x => x.AppointmentId == id) + .Select() + .ToListAsync(); + } + + public async Task ConfirmAsync(AppointmentConfirmRequest request) + { + var detail = await _dbContext.Queryable().Where(x => x.Id == request.Id).SingleAsync(); + detail.ThrowIfNull("预约信息不存在"); + + //todo生成下发任务 + var mst = await _dbContext.Queryable().Where(x => x.Id == detail.AppointmentId).FirstAsync(); + var deviceGroup = await _dbContext.Queryable() + .Where(x => x.CustomCode == mst.AreaCustomCode) + .Select(x => x.GroupCode) + .FirstAsync(); + + var deviceCodesResult = await _deviceGroupApi.GetDevicesByCodeAsync(deviceGroup); + var deviceCodes = deviceCodesResult.Data; + + var userNo = detail.IsExternal + ? await _dbContext.Queryable().Where(x => x.IdNo == detail.IdNo).Select(x => x.No).FirstAsync() + : await _dbContext.Queryable().Where(x => x.IdNo == detail.IdNo).Select(x => x.No).FirstAsync(); + + await _dbContext.InsertAsync(deviceCodes.Select(x => new DeviceTaskEntity + { + CancellationId = 0, + DeviceType = DeviceTypeEnumType.Door, + DeviceUniqueNo = x.UniqueNo, + Status = DeviceTaskStatusEnumType.Wait, + UserNo = userNo, + Type = DeviceTaskEnumType.Add, + Priority = 100, + Version = 0, + }).ToList()); + + detail.Status = AppointmentDetailEnumType.Arrived; + await _dbContext.UpdateAsync(detail); + } + + + //********************************************************** 用户操作 ******************************************************************* + + public async Task GetTodayByIdNoAsync(string idNo) + { + var detail = await _dbContext.Queryable() + .Where(x => x.IdNo == idNo) + .Where(x => SqlFunc.DateIsSame(x.Start, DateTime.Today, DateType.Day)) + .OrderBy(x => x.Start) + .Select() + .FirstAsync(); + + return detail; + } + + public async Task> GetRecordPageByIdNoAsync([FromQuery] AppointmentIdNoPageRequest request) + { + var page = await _dbContext.Queryable() + .Where(x => x.IdNo == request.IdNo) + .OrderBy(x => x.Start) + .Select() + .ToPageListAsync(request); + + return page; + } +} diff --git a/Src/Dlhis.Visitor/Appointment/Services/Implements/ApponintmentAreaService.cs b/Src/Dlhis.Visitor/Appointment/Services/Implements/ApponintmentAreaService.cs new file mode 100644 index 00000000..64e6d6e5 --- /dev/null +++ b/Src/Dlhis.Visitor/Appointment/Services/Implements/ApponintmentAreaService.cs @@ -0,0 +1,93 @@ +using Dlhis.Entity.Visitor.Entity; +using Dlhis.Visitor.Appointment.Request; +using Dlhis.Visitor.Appointment.Response; +using Kurisu.AspNetCore.Utils.Extensions; +using Kurisu.Core.DataAccess.Dto; +using Kurisu.SqlSugar.Extensions; +using Kurisu.SqlSugar.Services; +using Mapster; + +namespace Dlhis.Visitor.Appointment.Services.Implements; + +public class ApponintmentAreaService : IApponintmentAreaService +{ + private readonly IDbContext _dbContext; + + public ApponintmentAreaService(IDbContext dbContext) + { + _dbContext = dbContext; + } + + public async Task> GetPageAsync(PageDto request) + { + return await _dbContext.Queryable() + .Select() + .ToPageListAsync(request); + } + + + public async Task SaveAsync(AppointmentAreaSaveRequest request) + { + await CheckCustomCodeDuplicateAsync(request); + + if (!request.Id.HasValue) + { + var entity = request.Adapt(); + entity.Type = request.Type; + entity.CustomCode = request.CustomCode; + + await _dbContext.InsertAsync(entity); + } + else + { + var entity = await _dbContext.Queryable().Where(x => x.Id == request.Id).SingleAsync(); + entity.ThrowIfNull("预约区域不存在"); + + request.Adapt(entity); + + await _dbContext.UpdateAsync(entity); + } + } + + + public async Task DeleteAsync(long id) + { + var entity = await _dbContext.Queryable().Where(x => x.Id == id).SingleAsync(); + await _dbContext.DeleteAsync(entity); + } + + + public async Task AssignAsync(AppointmentAreaAssignRequest request) + { + await _dbContext.Client.Deleteable() + .Where(x => x.CustomCode == request.CustomCode) + .ExecuteCommandAsync(); + + var data = request.GroupCodes.Select(x => new AppointmentAreaAssignmentEntity + { + CustomCode = request.CustomCode, + GroupCode = x, + }) + .ToList(); + + await _dbContext.InsertAsync(data); + } + + + //********************************************************* help methods *************************************************************** + + /// + /// 检查编码重复 + /// + /// + /// + private async Task CheckCustomCodeDuplicateAsync(AppointmentAreaSaveRequest request) + { + var exists = await _dbContext.Queryable() + .Where(x => x.CustomCode == request.CustomCode) + .WhereIF(request.Id.HasValue, x => x.Id == request.Id) + .AnyAsync(); + + exists.ThrowIfTrue("重复区域编码,请检查"); + } +} diff --git a/Src/Dlhis.Visitor/Dlhis.Visitor.csproj b/Src/Dlhis.Visitor/Dlhis.Visitor.csproj new file mode 100644 index 00000000..1c1ea281 --- /dev/null +++ b/Src/Dlhis.Visitor/Dlhis.Visitor.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + disable + enable + True + + + + + + + + + + + + + + + + diff --git a/Src/Dlhis.Visitor/Packs/SqlSugarPack.cs b/Src/Dlhis.Visitor/Packs/SqlSugarPack.cs new file mode 100644 index 00000000..fc4bf67f --- /dev/null +++ b/Src/Dlhis.Visitor/Packs/SqlSugarPack.cs @@ -0,0 +1,36 @@ +using Kurisu.AspNetCore.Startup; +using Kurisu.SqlSugar.Extensions; +using SqlSugar; + +namespace Dlhis.Visitor.Packs; + +public class SqlSugarPack : BaseAppPack +{ + public override bool IsBeforeUseRouting { get; } + + public override void ConfigureServices(IServiceCollection services) + { + services.AddSqlSugar(sp => + { + var configuration = sp.GetService(); + + return new List + { + new() + { + ConfigId = "face", + + ConnectionString = configuration.GetSection("SqlSugarOptions:FaceConnectionString").Value, + DbType = DbType.MySqlConnector, + InitKeyType = InitKeyType.Attribute, + IsAutoCloseConnection = true, + + MoreSettings = new ConnMoreSettings + { + DisableNvarchar = true, + } + } + }; + }); + } +} \ No newline at end of file diff --git a/Src/Dlhis.Visitor/Program.cs b/Src/Dlhis.Visitor/Program.cs new file mode 100644 index 00000000..db27a2eb --- /dev/null +++ b/Src/Dlhis.Visitor/Program.cs @@ -0,0 +1,21 @@ +using Kurisu.AspNetCore.Startup; +using Kurisu.Startup; +using Microsoft.IdentityModel.Logging; + +namespace Dlhis.Visitor; + +class Program +{ + static void Main(string[] args) + { + KurisuHost.Run(args); + } +} + +public class Startup : DefaultStartup +{ + public Startup(IConfiguration configuration) : base(configuration) + { + IdentityModelEventSource.ShowPII = true; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Visitor/Properties/launchSettings.json b/Src/Dlhis.Visitor/Properties/launchSettings.json new file mode 100644 index 00000000..bdb16e59 --- /dev/null +++ b/Src/Dlhis.Visitor/Properties/launchSettings.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "Dlhis.Visitor": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "launchUrl": "weatherforecast", + "applicationUrl": "http://localhost:5021", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/Src/Dlhis.Visitor/appsettings.Development.json b/Src/Dlhis.Visitor/appsettings.Development.json new file mode 100644 index 00000000..7bacdb83 --- /dev/null +++ b/Src/Dlhis.Visitor/appsettings.Development.json @@ -0,0 +1,35 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "InternalRequest": { + "BasicRequestUrl": "http://localhost:5002" + }, + "SwaggerOptions": { + "Enable": true, + "Authority": "https://yikatong.isawesome.cn/oauth2", + "ClientId": "4fb184324eac4180", + "ClientSecret": "8ac8f235152f1524", + "Scopes": { + "openid": "openid", + "profile": "profile", + "yikatong": "yikatong" + } + }, + "IdentityServerOptions": { + "Authority": "https://yikatong.isawesome.cn/oauth2", + "RequireHttpsMetadata": true, + "Issuer": "identity.isawesome.cn", + "Audience": "" + }, + "SqlSugarOptions": { + "DefaultConnectionString": "server=192.168.199.124;port=3306;userid=root;password=dlhis123;database=yikatong;charset=utf8mb4;", + "SlaveConnectionString": [], + "Timeout": 30, + "SlowSqlTime": 1, + "EnableSqlLog": true + } +} diff --git a/Src/Dlhis.Visitor/appsettings.json b/Src/Dlhis.Visitor/appsettings.json new file mode 100644 index 00000000..45833522 --- /dev/null +++ b/Src/Dlhis.Visitor/appsettings.json @@ -0,0 +1,75 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "InternalRequest": { + "BasicRequestUrl": "http://basic" + }, + "AllowedHosts": "*", + "SqlSugarOptions": { + "DefaultConnectionString": "server=192.168.199.124;port=3306;userid=root;password=dlhis123;database=yikatong;charset=utf8mb4;", + "SlaveConnectionString": [], + "Timeout": 30, + "SlowSqlTime": 1, + "EnableSqlLog": false + }, + "SwaggerOptions": { + "Enable": true, + "Authority": "http://identity.oauth.svc.cluster.local", + "ClientId": "4fb184324eac4180", + "ClientSecret": "8ac8f235152f1524", + "Scopes": { + "openid": "openid", + "profile": "profile", + "yikatong": "yikatong" + } + }, + "IdentityServerOptions": { + "Authority": "http://identity.oauth.svc.cluster.local", + "RequireHttpsMetadata": false, + "Issuer": "identity.isawesome.cn", + "Audience": "", + "Pat": { + "Enable": false, + "Scheme": "token", + "ClientId": "reference", + "ClientSecret": "123456" + } + }, + "Serilog": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "System": "Warning", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "WriteTo": [ + { + "Name": "Async", + "Args": { + "configure": [ + { + "Name": "Console", + "Args": { + "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "MySQL", + "Args": { + "connectionString": "server=192.168.199.124;port=3306;userid=root;password=dlhis123;database=logs;charset=utf8mb4;", + "tableName": "Logs", + "autoCreateSqlTable": true + } + } + ] + } + } + ] + } +}