From efa0962f73dc3e442949c460b010a81cb34ac905 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Thu, 9 Oct 2025 14:31:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=80=9A=E8=A1=8C=E5=92=8C=E7=A9=BA?= =?UTF-8?q?=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dlhis.Jinko.Face.slnx | 1 + .../Dlhis.Dormitory.Api.csproj | 17 ++ .../DormitoryRemoteCallResultHandler.cs | 27 ++++ .../IDormitoryRoomPowerSwitchApi.cs | 16 ++ .../Request/PowerSwitchRequest.cs | 21 +++ .../Entity/DormitoryRoomPersonEntity.cs | 2 +- .../Handler/DormitoryPowerSwitchHandler.cs | 12 ++ .../Message/DormitoryPowerSwitchMessage.cs | 8 + .../Response/DormitoryResponse.cs | 18 +++ .../Implements/DeviceUploadLogService.cs | 145 +++++++++++++++++- .../Dlhis.ScheduledTask.csproj | 4 + Src/Dlhis.ScheduledTask/Dockerfile | 15 +- 12 files changed, 274 insertions(+), 12 deletions(-) create mode 100644 Src/Dlhis.Dormitory.Api/Dlhis.Dormitory.Api.csproj create mode 100644 Src/Dlhis.Dormitory.Api/DormitoryRemoteCallResultHandler.cs create mode 100644 Src/Dlhis.Dormitory.Api/IDormitoryRoomPowerSwitchApi.cs create mode 100644 Src/Dlhis.Dormitory.Api/Request/PowerSwitchRequest.cs create mode 100644 Src/Dlhis.ScheduledTask/DeviceUploadLog/EventBus/Handler/DormitoryPowerSwitchHandler.cs create mode 100644 Src/Dlhis.ScheduledTask/DeviceUploadLog/EventBus/Message/DormitoryPowerSwitchMessage.cs create mode 100644 Src/Dlhis.ScheduledTask/DeviceUploadLog/Response/DormitoryResponse.cs diff --git a/Dlhis.Jinko.Face.slnx b/Dlhis.Jinko.Face.slnx index 6115dc44..feeb2dfc 100644 --- a/Dlhis.Jinko.Face.slnx +++ b/Dlhis.Jinko.Face.slnx @@ -18,6 +18,7 @@ + diff --git a/Src/Dlhis.Dormitory.Api/Dlhis.Dormitory.Api.csproj b/Src/Dlhis.Dormitory.Api/Dlhis.Dormitory.Api.csproj new file mode 100644 index 00000000..3c1b5c9d --- /dev/null +++ b/Src/Dlhis.Dormitory.Api/Dlhis.Dormitory.Api.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + disable + + + + + + + + + + + diff --git a/Src/Dlhis.Dormitory.Api/DormitoryRemoteCallResultHandler.cs b/Src/Dlhis.Dormitory.Api/DormitoryRemoteCallResultHandler.cs new file mode 100644 index 00000000..133a33ff --- /dev/null +++ b/Src/Dlhis.Dormitory.Api/DormitoryRemoteCallResultHandler.cs @@ -0,0 +1,27 @@ +using System.Net; +using Kurisu.RemoteCall.Abstractions; +using Newtonsoft.Json; + +namespace Dlhis.Dormitory.Api; + +public class DormitoryRemoteCallResultHandler : IRemoteCallResultHandler +{ + public TResult Handle(HttpStatusCode statusCode, string responseBody) + { + ApiResult apiResult = JsonConvert.DeserializeObject>(responseBody); + if ((statusCode < HttpStatusCode.OK ? 0 : (statusCode <= (HttpStatusCode)299 ? 1 : 0)) != 0 && apiResult.Code == 200) + return apiResult.Data; + if (!string.IsNullOrEmpty(apiResult?.Message)) + throw new Exception(apiResult.Message); + throw new HttpRequestException($"{statusCode.ToString()} {((int)statusCode).ToString()}"); + } + + internal class ApiResult + { + public string Message { get; set; } + + public T Data { get; set; } + + public int Code { get; set; } + } +} \ No newline at end of file diff --git a/Src/Dlhis.Dormitory.Api/IDormitoryRoomPowerSwitchApi.cs b/Src/Dlhis.Dormitory.Api/IDormitoryRoomPowerSwitchApi.cs new file mode 100644 index 00000000..e31b9bca --- /dev/null +++ b/Src/Dlhis.Dormitory.Api/IDormitoryRoomPowerSwitchApi.cs @@ -0,0 +1,16 @@ +using Dlhis.Dormitory.Api.Request; +using Kurisu.RemoteCall.Attributes; + +namespace Dlhis.Dormitory.Api; + +[RequestLog] +[RequestResultHandler(typeof(DormitoryRemoteCallResultHandler))] +[EnableRemoteClient(Name = "dormitory-service", BaseUrl = "https://apartment.jinkosolar.com/pcapi")] +public interface IDormitoryRoomPowerSwitchApi +{ + [Post("/api/Energy/DhIccElectricityControl")] + Task SwitchAsync(PowerSwitchRequest request); + + [Get("/api/Users/GetDormitoryInfoByUserCode")] + Task GetUserRoomInfoAsync(string userCode); +} \ No newline at end of file diff --git a/Src/Dlhis.Dormitory.Api/Request/PowerSwitchRequest.cs b/Src/Dlhis.Dormitory.Api/Request/PowerSwitchRequest.cs new file mode 100644 index 00000000..09f46e05 --- /dev/null +++ b/Src/Dlhis.Dormitory.Api/Request/PowerSwitchRequest.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json; + +namespace Dlhis.Dormitory.Api.Request; + +public class PowerSwitchRequest +{ + public PowerSwitchRequest(string roomid, int power) + { + this.RoomId = roomid; + this.Power = power; + } + + [JsonProperty("roomid")] + public string RoomId { get; set; } + + /// + /// 0 断电 1 上电 + /// + [JsonProperty("power")] + public int Power { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Dormitory/Entity/DormitoryRoomPersonEntity.cs b/Src/Dlhis.Entity/Dormitory/Entity/DormitoryRoomPersonEntity.cs index 611fafb8..f6a88f21 100644 --- a/Src/Dlhis.Entity/Dormitory/Entity/DormitoryRoomPersonEntity.cs +++ b/Src/Dlhis.Entity/Dormitory/Entity/DormitoryRoomPersonEntity.cs @@ -10,6 +10,6 @@ public class DormitoryRoomPersonEntity : SugarBaseEntity, ISoftDeleted public string RoomId { get; set; } public string UserCode { get; set; } public string UserName { get; set; } - public bool? In { get; set; } + public bool In { get; set; } public bool IsDeleted { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.ScheduledTask/DeviceUploadLog/EventBus/Handler/DormitoryPowerSwitchHandler.cs b/Src/Dlhis.ScheduledTask/DeviceUploadLog/EventBus/Handler/DormitoryPowerSwitchHandler.cs new file mode 100644 index 00000000..99df1d99 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/DeviceUploadLog/EventBus/Handler/DormitoryPowerSwitchHandler.cs @@ -0,0 +1,12 @@ +using Dlhis.ScheduledTask.DeviceUploadLog.EventBus.Message; +using Kurisu.AspNetCore.EventBus.Abstractions.Handler; + +namespace Dlhis.ScheduledTask.DeviceUploadLog.EventBus.Handler; + +public class DormitoryPowerSwitchHandler : IAsyncChannelHandler +{ + public async Task InvokeAsync(IServiceProvider serviceProvider, DormitoryPowerSwitchMessage message) + { + await Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Src/Dlhis.ScheduledTask/DeviceUploadLog/EventBus/Message/DormitoryPowerSwitchMessage.cs b/Src/Dlhis.ScheduledTask/DeviceUploadLog/EventBus/Message/DormitoryPowerSwitchMessage.cs new file mode 100644 index 00000000..0acd6cff --- /dev/null +++ b/Src/Dlhis.ScheduledTask/DeviceUploadLog/EventBus/Message/DormitoryPowerSwitchMessage.cs @@ -0,0 +1,8 @@ +using Kurisu.AspNetCore.EventBus.Abstractions; + +namespace Dlhis.ScheduledTask.DeviceUploadLog.EventBus.Message; + +public class DormitoryPowerSwitchMessage : IAsyncChannelMessage +{ + +} \ No newline at end of file diff --git a/Src/Dlhis.ScheduledTask/DeviceUploadLog/Response/DormitoryResponse.cs b/Src/Dlhis.ScheduledTask/DeviceUploadLog/Response/DormitoryResponse.cs new file mode 100644 index 00000000..9a44609e --- /dev/null +++ b/Src/Dlhis.ScheduledTask/DeviceUploadLog/Response/DormitoryResponse.cs @@ -0,0 +1,18 @@ +namespace Dlhis.ScheduledTask.DeviceUploadLog.Response; + +public class DormitoryResponse +{ + public string RoomId { get; set; } + public string RoomNo { get; set; } + public string HotelId { get; set; } + + public bool MCB { get; set; } + + public List Persons { get; set; } +} + +public class DormitoryPerson +{ + public string UserCode { get; set; } + public string UserName { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs b/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs index 0ae6ed35..3e1fa1e6 100644 --- a/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs +++ b/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs @@ -1,11 +1,14 @@ using Dlhis.Basic.Api; using Dlhis.Basic.Api.Requests; using Dlhis.Constants; +using Dlhis.Dormitory.Api; +using Dlhis.Dormitory.Api.Request; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Basic.Enums; using Dlhis.Entity.Device.Entities; using Dlhis.Entity.Device.Enums; using Dlhis.Entity.Device.Models; +using Dlhis.Entity.Dormitory.Entity; using Dlhis.Jip.Api; using Dlhis.Jip.Api.Requests; using Dlhis.ScheduledTask.DeviceUploadLog.Request; @@ -22,18 +25,21 @@ namespace Dlhis.ScheduledTask.DeviceUploadLog.Services.Implements; public class DeviceUploadLogService : IDeviceUploadLogService { private readonly IDbContext _dbContext; + private readonly IDormitoryRoomPowerSwitchApi _dormitoryRoomPowerSwitchApi; private readonly ICurrentUser _currentUser; private readonly IJinkoJipApi _jinkoJipApi; private readonly ILogger _logger; private readonly IDingTalkApi _dingTalkApi; public DeviceUploadLogService(IDbContext dbContext, + IDormitoryRoomPowerSwitchApi dormitoryRoomPowerSwitchApi, ICurrentUser currentUser, IJinkoJipApi jinkoJipApi, ILogger logger, IDingTalkApi dingTalkApi) { _dbContext = dbContext; + _dormitoryRoomPowerSwitchApi = dormitoryRoomPowerSwitchApi; _currentUser = currentUser; _jinkoJipApi = jinkoJipApi; _logger = logger; @@ -44,7 +50,11 @@ public class DeviceUploadLogService : IDeviceUploadLogService { var deviceUniqueNos = requests.Select(x => x.DeviceUniqueNo).Distinct().ToList(); var devices = await _dbContext.Queryable().Where(x => deviceUniqueNos.Contains(x.UniqueNo)).ToListAsync(); - var existsDeviceUniqueNos = devices.Select(x => x.UniqueNo).ToList(); + var existsDeviceUniqueNos = devices.Select(x => x.UniqueNo).ToList(); + + var deviceCodes = devices.Where(x => x.DeployDirection.HasValue).Select(x => x.Code).Distinct().ToList(); + var eFenceDeviceRelations = await _dbContext.Queryable().Where(x => deviceCodes.Contains(x.DeviceCode)).ToListAsync(); + var eFenceDeviceMap = eFenceDeviceRelations.ToDictionary(x => x.DeviceCode, x => x.EFenceCode); var userCodes = requests.Where(x => x.UserUniqueNo.IsPresent()).Select(x => x.UserUniqueNo).Distinct().ToList(); var gainfo1 = await _dbContext.Queryable().Where(x => userCodes.Contains(x.Code)).Select(x => new { x.Code, x.Name, x.Type }).ToListAsync(); @@ -111,6 +121,11 @@ public class DeviceUploadLogService : IDeviceUploadLogService ? DeviceUploadLogTypeEnumType.Attendance : DeviceUploadLogTypeEnumType.Door; + if (eFenceDeviceMap.TryGetValue(device.Code, out var eFenceCore)) + { + await HandlerPowerSwitchAsync(eFenceCore, request.UserUniqueNo, device.DeployDirection.Value); + } + var workGridInfo = new WorkGridInfo(); var currentWorkGridTimePeriods = workGridTimePeriods.Where(x => x.TenantId == device.TenantId).ToList(); var currentWorkGridSchedules = workGridSchedules.Where(x => x.UserCode == request.UserUniqueNo).ToList(); @@ -262,6 +277,134 @@ public class DeviceUploadLogService : IDeviceUploadLogService await _dbContext.InsertAsync(inserts); } + + /// + /// 宿舍只能空开触发 + /// + /// + /// + /// + private async Task HandlerPowerSwitchAsync(Guid eFenceCode, string userCode, DeviceDeployDirectionEnumType directionType) + { + try + { + //调用获取人员信息接口 + var roomInfo = await _dormitoryRoomPowerSwitchApi.GetUserRoomInfoAsync(userCode); + if (!roomInfo.MCB) + { + return; + } + + var room = await _dbContext.Queryable().Where(x => x.RoomId == roomInfo.RoomId).SingleAsync(); + if (room == null) + { + room = new DormitoryRoomEntity + { + EFenceCode = eFenceCode, + RoomId = roomInfo.RoomId, + RoomNo = roomInfo.RoomNo, + HotelId = roomInfo.HotelId, + PowerSwitch = true + }; + + await _dbContext.InsertAsync(room); + + var personEntities = roomInfo.Persons.Select(x => new DormitoryRoomPersonEntity + { + RoomId = roomInfo.RoomId, + UserCode = x.UserCode, + UserName = x.UserName, + In = true, + IsDeleted = false + }) + .ToList(); + + await _dbContext.InsertAsync(personEntities); + + var person = await _dbContext.Queryable() + .Where(x => x.RoomId != roomInfo.RoomId && x.UserCode == userCode) + .FirstAsync(); + if (person != null) + { + await _dbContext.DeleteAsync(person); + } + } + else + { + var existsPersons = await _dbContext.Queryable() + .Where(x => x.RoomId == roomInfo.RoomId) + .ToListAsync(); + + //根据roomInfo.Persons和existsPersons不在当前房间的人 + var toDeletePersons = existsPersons.Where(x => roomInfo.Persons.All(p => p.UserCode != x.UserCode)).ToList(); + if (toDeletePersons.Any()) + { + await _dbContext.DeleteAsync(toDeletePersons); + } + + //需要新增的 + var toAddPersons = roomInfo.Persons.Where(x => existsPersons.All(p => p.UserCode != x.UserCode)).ToList(); + if (toAddPersons.Any()) + { + var personEntities = toAddPersons.Select(x => new DormitoryRoomPersonEntity() + { + RoomId = roomInfo.RoomId, + UserCode = x.UserCode, + UserName = x.UserName, + In = true, + IsDeleted = false + }).ToList(); + + await _dbContext.InsertAsync(personEntities); + } + + room.EFenceCode = eFenceCode; + await _dbContext.UpdateAsync(room); + } + + + //如果DormitoryRoomPersonEntity.in都为false,断电, 否则上电(前提是DormitoryRoomEntity.PowerSwitch==false) + // 查询房间所有人员 + var persons = await _dbContext.Queryable() + .Where(x => x.RoomId == roomInfo.RoomId) + .ToListAsync(); + + persons.ForEach(x => + { + if (x.UserCode == userCode) + { + x.In = directionType == DeviceDeployDirectionEnumType.Entry; + } + }); + await _dbContext.UpdateAsync(persons); + + // 如果所有人都不在房间,且当前房间是通电状态,则断电 + if (persons.All(x => !x.In)) + { + if (room.PowerSwitch) + { + room.PowerSwitch = false; // 断电 + await _dbContext.UpdateAsync(room); + await _dormitoryRoomPowerSwitchApi.SwitchAsync(new PowerSwitchRequest(room.RoomId, 0)); + } + } + else + { + // 只在房间断电状态时才上电 + if (!room.PowerSwitch) + { + room.PowerSwitch = true; // 上电 + await _dbContext.UpdateAsync(room); + await _dormitoryRoomPowerSwitchApi.SwitchAsync(new PowerSwitchRequest(room.RoomId, 1)); + } + } + } + catch (Exception e) + { + _logger.LogError(e, "宿舍空开触发失败, userCode:{userCode} directionType:{directionType} error:{error}", userCode, directionType, e.Message); + } + } + public async Task> GetMyRecordsAsync(DeviceUploadLogMyRecordRequest request) { var jinkoCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode) ?? string.Empty; diff --git a/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj b/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj index 01b99815..15f3bc42 100644 --- a/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj +++ b/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj @@ -16,6 +16,9 @@ + + .dockerignore + @@ -34,6 +37,7 @@ + diff --git a/Src/Dlhis.ScheduledTask/Dockerfile b/Src/Dlhis.ScheduledTask/Dockerfile index dadbd4fe..dc0b574f 100644 --- a/Src/Dlhis.ScheduledTask/Dockerfile +++ b/Src/Dlhis.ScheduledTask/Dockerfile @@ -1,12 +1,8 @@ -# 请参阅 https://aka.ms/customizecontainer 以了解如何自定义调试容器,以及 Visual Studio 如何使用此 Dockerfile 生成映像以更快地进行调试。 - -# 此阶段用于在快速模式(默认为调试配置)下从 VS 运行时 -FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 80 +EXPOSE 443 - -# 此阶段用于生成服务项目 FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build ARG BUILD_CONFIGURATION=Release WORKDIR /src @@ -18,18 +14,17 @@ COPY ["Src/Dlhis.Entity/Dlhis.Entity.csproj", "Src/Dlhis.Entity/"] COPY ["Src/Dlhis.DataPermission.Model/Dlhis.DataPermission.Model.csproj", "Src/Dlhis.DataPermission.Model/"] COPY ["Src/Dlhis.Jip.Api/Dlhis.Jip.Api.csproj", "Src/Dlhis.Jip.Api/"] COPY ["Src/Dlhis.Sys.Api/Dlhis.Sys.Api.csproj", "Src/Dlhis.Sys.Api/"] -RUN dotnet restore "./Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj" +COPY ["Src/Dlhis.Dormitory.Api/Dlhis.Dormitory.Api.csproj", "Src/Dlhis.Dormitory.Api/"] +RUN dotnet restore "Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj" COPY . . WORKDIR "/src/Src/Dlhis.ScheduledTask" RUN dotnet build "./Dlhis.ScheduledTask.csproj" -c $BUILD_CONFIGURATION -o /app/build -# 此阶段用于发布要复制到最终阶段的服务项目 FROM build AS publish ARG BUILD_CONFIGURATION=Release RUN dotnet publish "./Dlhis.ScheduledTask.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false -# 此阶段在生产中使用,或在常规模式下从 VS 运行时使用(在不使用调试配置时为默认值) FROM base AS final WORKDIR /app COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "Dlhis.ScheduledTask.dll"] \ No newline at end of file +ENTRYPOINT ["dotnet", "Dlhis.ScheduledTask.dll"]