diff --git a/Src/Dlhis.Middle/Api/FaceBearerTokenHandler.cs b/Src/Dlhis.Middle/Api/FaceBearerTokenHandler.cs new file mode 100644 index 00000000..a0e806ff --- /dev/null +++ b/Src/Dlhis.Middle/Api/FaceBearerTokenHandler.cs @@ -0,0 +1,37 @@ +using System.Text; +using Dlhis.Middle.Response; +using Kurisu.AspNetCore.UnifyResultAndValidation; +using Kurisu.RemoteCall.Abstractions; +using Microsoft.Extensions.Caching.Memory; +using Newtonsoft.Json; + +namespace Dlhis.Middle.Api +{ + public class FaceBearerTokenHandler : IAuthTokenHandler + { + /// + public string GetToken(IServiceProvider serviceProvider) + { + var cache = serviceProvider.GetService(); + if (cache.TryGetValue("token", out string token)) return "Bearer " + token; + + var httpClient = serviceProvider.GetService().CreateClient("face"); + var hostName = serviceProvider.GetService().GetSection("HostName").Value; + + var tokenResponse = httpClient.PostAsync($"https://{hostName}/api/user/oauth2/clientgrant", new StringContent(JsonConvert.SerializeObject(new + { + ClientId = "e509c2aaa98e300c", + ClientSecret = "6184d8979fc48105" + }), Encoding.UTF8, "application/json")).GetAwaiter().GetResult(); + + var tokenJson = tokenResponse.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + var tokenInfo = JsonConvert.DeserializeObject>(tokenJson); + + token = tokenInfo.Data.AccessToken; + + cache.Set("token", token, TimeSpan.FromSeconds(tokenInfo.Data.Expires)); + + return token; + } + } +} \ No newline at end of file diff --git a/Src/Dlhis.Middle/Api/IAssignmentDeviceTaskApi.cs b/Src/Dlhis.Middle/Api/IAssignmentDeviceTaskApi.cs new file mode 100644 index 00000000..8c856a82 --- /dev/null +++ b/Src/Dlhis.Middle/Api/IAssignmentDeviceTaskApi.cs @@ -0,0 +1,14 @@ +using Dlhis.Middle.Request; +using Dlhis.Middle.Response; +using Kurisu.AspNetCore.UnifyResultAndValidation; +using Kurisu.RemoteCall.Attributes; + +namespace Dlhis.Middle.Api; + +[EnableRemoteClient(Name = "face-service", BaseUrl = "${Authority}")] +public interface IAssignmentDeviceTaskApi +{ + [Auth(TokenHandler = typeof(FaceBearerTokenHandler))] + [Post("/api/scheduled/assignments/deviceTasks")] + Task>> DeviceGetTasksAsync(DeviceTaskGetRequest request); +} \ No newline at end of file diff --git a/Src/Dlhis.Middle/Api/ICanteenApi.cs b/Src/Dlhis.Middle/Api/ICanteenApi.cs new file mode 100644 index 00000000..a48aa144 --- /dev/null +++ b/Src/Dlhis.Middle/Api/ICanteenApi.cs @@ -0,0 +1,15 @@ +using Dlhis.Middle.Request; +using Dlhis.Middle.Response; +using Kurisu.AspNetCore.UnifyResultAndValidation; +using Kurisu.RemoteCall.Attributes; + +namespace Dlhis.Middle.Api; + +[EnableRemoteClient(Name = "face-service", BaseUrl = "${Authority}")] +public interface ICanteenApi +{ + + [Auth(TokenHandler = typeof(FaceBearerTokenHandler))] + [Post("/api/canteen/orders")] + Task> AddAsync(OrderAddRequest request); +} \ No newline at end of file diff --git a/Src/Dlhis.Middle/Controllers/AssignmentsController.cs b/Src/Dlhis.Middle/Controllers/AssignmentsController.cs new file mode 100644 index 00000000..86107959 --- /dev/null +++ b/Src/Dlhis.Middle/Controllers/AssignmentsController.cs @@ -0,0 +1,76 @@ +using Dlhis.Entity.Device.Enums; +using Dlhis.Middle.Api; +using Dlhis.Middle.Request; +using Dlhis.Middle.Response; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop; +using Kurisu.AspNetCore.UnifyResultAndValidation; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.WebUtilities; +using Newtonsoft.Json.Linq; + +namespace Dlhis.Middle.Controllers; + +/// +/// 任务分配 +/// +[Route("api/scheduled/[controller]")] +[ApiController] +public class AssignmentsController : ControllerBase +{ + private readonly IAssignmentDeviceTaskApi _assignmentDeviceTaskApi; + private readonly string _internalIp; + + public AssignmentsController(IAssignmentDeviceTaskApi assignmentDeviceTaskApi, IConfiguration configuration) + { + _assignmentDeviceTaskApi = assignmentDeviceTaskApi; + _internalIp = configuration.GetSection("InternalIP").Value; + } + + /// + /// 获取设备任务(按设备) + /// + /// + [IgnoreTenant] + [HttpGet("deviceTasks")] + public async Task>> DeviceGetTasksGetAsync([FromQuery] DeviceTaskGetRequest request) + { + var result = await _assignmentDeviceTaskApi.DeviceGetTasksAsync(request); + foreach (var data in result.Data) + { + foreach (var task in data.Tasks.Where(x => x.Type != DeviceTaskEnumType.Delete)) + { + var currentUser = JObject.FromObject(task.Info).ToObject(); + var token = QueryHelpers.ParseQuery(currentUser.Face).First().Value; + currentUser.Face = $"http://{_internalIp}/api/basic/gainfos/face?token=" + token; + + task.Info = currentUser; + } + } + + return result; + } + + /// + /// 获取设备任务(按设备) + /// + /// + [HttpPost("deviceTasks")] + [IgnoreTenant] + public async Task>> DeviceGetTasksPostAsync(DeviceTaskGetRequest request) + { + var result = await _assignmentDeviceTaskApi.DeviceGetTasksAsync(request); + foreach (var data in result.Data) + { + foreach (var task in data.Tasks.Where(x => x.Type != DeviceTaskEnumType.Delete)) + { + var currentUser = JObject.FromObject(task.Info).ToObject(); + var token = QueryHelpers.ParseQuery(currentUser.Face).First().Value; + currentUser.Face = $"http://{_internalIp}/api/basic/gainfos/face?token=" + token; + + task.Info = currentUser; + } + } + + return result; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Middle/Controllers/GainfosController.cs b/Src/Dlhis.Middle/Controllers/GainfosController.cs new file mode 100644 index 00000000..dc60ef38 --- /dev/null +++ b/Src/Dlhis.Middle/Controllers/GainfosController.cs @@ -0,0 +1,52 @@ +using Dlhis.Middle.Filters; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Dlhis.Middle.Controllers; + +/// +/// sap档案表 +/// +[Route("api/basic/[controller]")] +[ApiController] +public class GainfosController : ControllerBase +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly IConfiguration _configuration; + + public GainfosController(IHttpClientFactory httpClientFactory, IConfiguration configuration) + { + _httpClientFactory = httpClientFactory; + _configuration = configuration; + } + + /// + /// 通过token获取人脸照片,失效或者找不到返回HttpStatus404状态码 + /// + /// + /// + [NotFound] + [AllowAnonymous] + [HttpGet("face")] + public async Task GetFaceAsync(string token) + { + var hostName = _configuration.GetSection("HostName").Value; + var httpClient = _httpClientFactory.CreateClient(); + + try + { + var faceBytes = await httpClient.GetByteArrayAsync($"https://{hostName}/api/basic/gainfos/face?token={token}"); + + if (faceBytes.Length == 0) + { + return new NotFoundResult(); + } + + return new FileContentResult(faceBytes, "image/png"); + } + catch (Exception) + { + return new NotFoundResult(); + } + } +} \ No newline at end of file diff --git a/Src/Dlhis.Middle/Controllers/OrdersController.cs b/Src/Dlhis.Middle/Controllers/OrdersController.cs index cadefa56..0813c676 100644 --- a/Src/Dlhis.Middle/Controllers/OrdersController.cs +++ b/Src/Dlhis.Middle/Controllers/OrdersController.cs @@ -1,9 +1,8 @@ -using Dlhis.Middle.Request; +using Dlhis.Middle.Api; +using Dlhis.Middle.Request; using Dlhis.Middle.Response; -using Dlhis.Middle.Services; using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop; using Kurisu.AspNetCore.UnifyResultAndValidation; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace Dlhis.Middle.Controllers; @@ -15,11 +14,11 @@ namespace Dlhis.Middle.Controllers; [ApiController] public class OrdersController : ControllerBase { - private readonly IOrderService _orderService; + private readonly ICanteenApi _canteenApi; - public OrdersController(IOrderService orderService) + public OrdersController(ICanteenApi canteenApi) { - _orderService = orderService; + _canteenApi = canteenApi; } /// @@ -31,6 +30,6 @@ public class OrdersController : ControllerBase [IgnoreTenant] public async Task> AddAsync(OrderAddRequest request) { - return await _orderService.AddAsync(request); + return await _canteenApi.AddAsync(request); } } \ No newline at end of file diff --git a/Src/Dlhis.Middle/Dlhis.Middle.csproj b/Src/Dlhis.Middle/Dlhis.Middle.csproj index 1b0aef9f..accf19a9 100644 --- a/Src/Dlhis.Middle/Dlhis.Middle.csproj +++ b/Src/Dlhis.Middle/Dlhis.Middle.csproj @@ -17,6 +17,7 @@ + diff --git a/Src/Dlhis.ScheduledTask/TaskAssignment/Response/TaskCombineDto.cs b/Src/Dlhis.Middle/Dto/TaskCombineDto.cs similarity index 90% rename from Src/Dlhis.ScheduledTask/TaskAssignment/Response/TaskCombineDto.cs rename to Src/Dlhis.Middle/Dto/TaskCombineDto.cs index 6b1526c8..92119602 100644 --- a/Src/Dlhis.ScheduledTask/TaskAssignment/Response/TaskCombineDto.cs +++ b/Src/Dlhis.Middle/Dto/TaskCombineDto.cs @@ -1,7 +1,7 @@ using Dlhis.Entity.Device.Enums; using Kurisu.AspNetCore.Utils.Extensions; -namespace Dlhis.ScheduledTask.TaskAssignment.Response; +namespace Dlhis.Middle.Dto; public class TaskCombineDto { diff --git a/Src/Dlhis.Middle/Filters/NotFoundAttribute.cs b/Src/Dlhis.Middle/Filters/NotFoundAttribute.cs new file mode 100644 index 00000000..015f49f9 --- /dev/null +++ b/Src/Dlhis.Middle/Filters/NotFoundAttribute.cs @@ -0,0 +1,30 @@ +using Kurisu.AspNetCore.UnifyResultAndValidation; +using Kurisu.AspNetCore.UnifyResultAndValidation.Abstractions; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; + +namespace Dlhis.Middle.Filters; + +[AttributeUsage(AttributeTargets.Method)] +public class NotFoundAttribute : Attribute, IAsyncResultFilter +{ + public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) + { + if (context.Result is ObjectResult result) + { + var type = result.Value?.GetType(); + if (type.IsGenericType && type.IsAssignableTo(typeof(IApiResult))) + { + var apiResult = result.Value as DefaultApiResult; + + if (apiResult.Data is ProblemDetails _) + { + context.Result = new NotFoundResult(); + //context.HttpContext.Response + } + } + } + + await next(); + } +} diff --git a/Src/Dlhis.Middle/Program.cs b/Src/Dlhis.Middle/Program.cs index d57384c4..30cb0fdd 100644 --- a/Src/Dlhis.Middle/Program.cs +++ b/Src/Dlhis.Middle/Program.cs @@ -1,5 +1,6 @@ using Dlhis.Middle.Services; using Dlhis.Middle.Services.Implements; +using Kurisu.AspNetCore; using Kurisu.AspNetCore.Startup; using Microsoft.IdentityModel.Logging; @@ -23,6 +24,8 @@ public class Startup : DefaultStartup public override void ConfigureServices(IServiceCollection services) { base.ConfigureServices(services); + + services.AddRemoteCall(App.ActiveTypes); services.AddHttpClient("face").ConfigurePrimaryHttpMessageHandler(() => { var handler = new HttpClientHandler diff --git a/Src/Dlhis.Middle/Request/DeviceTaskGetRequest.cs b/Src/Dlhis.Middle/Request/DeviceTaskGetRequest.cs new file mode 100644 index 00000000..f065e67a --- /dev/null +++ b/Src/Dlhis.Middle/Request/DeviceTaskGetRequest.cs @@ -0,0 +1,42 @@ +using System.ComponentModel.DataAnnotations; +using Dlhis.Entity.Device.Enums; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.Utils.Extensions; + +namespace Dlhis.Middle.Request; + +public class DeviceTaskGetRequest : PageDto, IValidatableObject +{ + /// + /// 品牌 + /// + public string Brand { get; set; } + + /// + /// 设备号 + /// + public string DeviceUniqueNo { get; set; } + + /// + /// 任务类型 + /// + public List Types { get; set; } + + /// + /// 获取处理中的任务 + /// + public bool IsProcess { get; set; } = false; + + /// + /// 厂区 + /// + public string Factory { get; set; } + + public IEnumerable Validate(ValidationContext validationContext) + { + if (Brand.IsEmpty() && DeviceUniqueNo.IsEmpty() && Factory.IsEmpty()) + { + yield return new ValidationResult("设备品牌,设备号和厂区不能都为空", new[] { nameof(Brand), nameof(DeviceUniqueNo), nameof(Factory) }); + } + } +} \ No newline at end of file diff --git a/Src/Dlhis.Middle/Response/DeviceTaskToDeviceResponse.cs b/Src/Dlhis.Middle/Response/DeviceTaskToDeviceResponse.cs new file mode 100644 index 00000000..9980ab39 --- /dev/null +++ b/Src/Dlhis.Middle/Response/DeviceTaskToDeviceResponse.cs @@ -0,0 +1,29 @@ +using Dlhis.Middle.Dto; + +namespace Dlhis.Middle.Response; + +/// +/// 设备任务 +/// +public class DeviceTaskToDeviceByDeviceResponse +{ + /// + /// 品牌 + /// + public string Brand { get; set; } + + /// + /// 设备唯一号 + /// + public string DeviceUniqueNo { get; set; } + + /// + /// 设备信息 + /// + public object DeviceInfo { get; set; } + + /// + /// 任务 + /// + public List Tasks { get; set; } +} diff --git a/Src/Dlhis.Middle/Response/UploadRecordToDeviceResponse.cs b/Src/Dlhis.Middle/Response/UploadRecordToDeviceResponse.cs new file mode 100644 index 00000000..7c9ca6dc --- /dev/null +++ b/Src/Dlhis.Middle/Response/UploadRecordToDeviceResponse.cs @@ -0,0 +1,8 @@ +using Kurisu.AspNetCore.CustomClass; + +namespace Dlhis.Middle.Response; + +public class UploadRecordToDeviceResponse +{ + public DateTimePeriod DateTimePeriod { get; set; } +} diff --git a/Src/Dlhis.Middle/Response/UserToDeviceResponse.cs b/Src/Dlhis.Middle/Response/UserToDeviceResponse.cs new file mode 100644 index 00000000..8e143a4b --- /dev/null +++ b/Src/Dlhis.Middle/Response/UserToDeviceResponse.cs @@ -0,0 +1,71 @@ +using Kurisu.AspNetCore.CustomClass; + +namespace Dlhis.Middle.Response; + +public class UserToDeviceResponse +{ + /// + /// 人员唯一id + /// + public long UserId { get; set; } + + /// + /// 人员档案号 + /// + public string UserNo { get; set; } + + /// + /// 老系统档案号 + /// + public string OldUserNo { 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 string Face { get; set; } + + /// + /// 有效日期范围 + /// + public DatePeriod ValidDatePeriod { get; set; } + + /// + /// 控制门[1,2,3....] + /// + public List Doors { get; set; } + + /// + /// 时段[1,2,3....] + /// + public List TimePeriods { get; set; } + + /// + /// 假期计划id + /// + public int Schedule { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.ScheduledTask/TaskAssignment/Response/ScheduleDto.cs b/Src/Dlhis.ScheduledTask/TaskAssignment/Dto/ScheduleDto.cs similarity index 84% rename from Src/Dlhis.ScheduledTask/TaskAssignment/Response/ScheduleDto.cs rename to Src/Dlhis.ScheduledTask/TaskAssignment/Dto/ScheduleDto.cs index 357d80ca..4e9bcd1a 100644 --- a/Src/Dlhis.ScheduledTask/TaskAssignment/Response/ScheduleDto.cs +++ b/Src/Dlhis.ScheduledTask/TaskAssignment/Dto/ScheduleDto.cs @@ -1,6 +1,6 @@ using Kurisu.AspNetCore.CustomClass; -namespace Dlhis.ScheduledTask.TaskAssignment.Response; +namespace Dlhis.ScheduledTask.TaskAssignment.Dto; public class ScheduleDto { diff --git a/Src/Dlhis.ScheduledTask/TaskAssignment/Dto/TaskCombineDto.cs b/Src/Dlhis.ScheduledTask/TaskAssignment/Dto/TaskCombineDto.cs new file mode 100644 index 00000000..944cb431 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/TaskAssignment/Dto/TaskCombineDto.cs @@ -0,0 +1,27 @@ +using Dlhis.Entity.Device.Enums; +using Kurisu.AspNetCore.Utils.Extensions; + +namespace Dlhis.ScheduledTask.TaskAssignment.Dto; + +public class TaskCombineDto +{ + /// + /// 任务id + /// + public long TaskId { get; set; } + + /// + /// 任务类型 + /// + public DeviceTaskEnumType Type { get; set; } + + /// + /// 任务类型描述 + /// + public string TypeDesc => Type.GetDescription(); + + /// + /// 下发信息 + /// + public object Info { get; set; } +} diff --git a/Src/Dlhis.ScheduledTask/TaskAssignment/Response/DeviceTaskToDeviceResponse.cs b/Src/Dlhis.ScheduledTask/TaskAssignment/Response/DeviceTaskToDeviceResponse.cs index 5c9846e8..2ce0d786 100644 --- a/Src/Dlhis.ScheduledTask/TaskAssignment/Response/DeviceTaskToDeviceResponse.cs +++ b/Src/Dlhis.ScheduledTask/TaskAssignment/Response/DeviceTaskToDeviceResponse.cs @@ -1,4 +1,6 @@ -namespace Dlhis.ScheduledTask.TaskAssignment.Response; +using Dlhis.ScheduledTask.TaskAssignment.Dto; + +namespace Dlhis.ScheduledTask.TaskAssignment.Response; /// /// 设备任务 diff --git a/Src/Dlhis.ScheduledTask/TaskAssignment/Response/ScheduleToDeviceResponse.cs b/Src/Dlhis.ScheduledTask/TaskAssignment/Response/ScheduleToDeviceResponse.cs index 4f8515b1..24a9062d 100644 --- a/Src/Dlhis.ScheduledTask/TaskAssignment/Response/ScheduleToDeviceResponse.cs +++ b/Src/Dlhis.ScheduledTask/TaskAssignment/Response/ScheduleToDeviceResponse.cs @@ -1,4 +1,6 @@ -namespace Dlhis.ScheduledTask.TaskAssignment.Response; +using Dlhis.ScheduledTask.TaskAssignment.Dto; + +namespace Dlhis.ScheduledTask.TaskAssignment.Response; public class ScheduleToDeviceResponse { diff --git a/Src/Dlhis.ScheduledTask/TaskAssignment/Response/UserToDeviceResponse.cs b/Src/Dlhis.ScheduledTask/TaskAssignment/Response/UserToDeviceResponse.cs index 7a6254c6..ee84c43e 100644 --- a/Src/Dlhis.ScheduledTask/TaskAssignment/Response/UserToDeviceResponse.cs +++ b/Src/Dlhis.ScheduledTask/TaskAssignment/Response/UserToDeviceResponse.cs @@ -14,6 +14,11 @@ public class UserToDeviceResponse /// public string UserNo { get; set; } + /// + /// 老系统档案号 + /// + public string OldUserNo { get; set; } + /// /// 人员学工号 /// diff --git a/Src/Dlhis.ScheduledTask/TaskAssignment/Services/Implements/AssignmentService.cs b/Src/Dlhis.ScheduledTask/TaskAssignment/Services/Implements/AssignmentService.cs index e12e1230..b3764a68 100644 --- a/Src/Dlhis.ScheduledTask/TaskAssignment/Services/Implements/AssignmentService.cs +++ b/Src/Dlhis.ScheduledTask/TaskAssignment/Services/Implements/AssignmentService.cs @@ -51,7 +51,7 @@ public class AssignmentService : IAssignmentService var dc = x.Key.DeviceConnectionInfo ?? "{}"; var func = x.Key.FuncStr ?? "[]"; - var jobj = new JObject + var jObj = new JObject { { "connectionInfo", JToken.Parse(dc) }, { "function", JArray.Parse(func) } @@ -61,7 +61,7 @@ public class AssignmentService : IAssignmentService { Brand = b, DeviceUniqueNo = d, - DeviceInfo = jobj, + DeviceInfo = jObj, Tasks = x.Select(item => { var key = $"face:{item.UserCode}"; @@ -83,7 +83,7 @@ public class AssignmentService : IAssignmentService { dto.Info = new UserToDeviceResponse { - UserId = item.UserId.HasValue ? item.UserId.Value : 0, + UserId = item.UserId ?? 0, UserNo = item.UserNo, UserCode = item.UserCode, UserName = item.UserName,