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
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+}