Squashed commit of the following:

commit 528cdd51c05d26437f0b23f415e06311b667e9f7
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Wed Apr 17 15:37:30 2024 +0800

    feat 访客预约

commit e73a3fcd9307f86aba2c39578495c03cde1d41f9
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Tue Apr 16 16:15:16 2024 +0800

    feat 业务curd

commit b98b6e2764fea875866e11f790f388ccf3c234b5
Merge: a3dcec3 965e84b
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Tue Apr 16 14:56:30 2024 +0800

    Merge branch 'feat-visitorAppointments' of https://git.dlhis.com/liguoyang/jinko.yikatong into feat-visitorAppointments

commit a3dcec30e1289fbb09de8f85009d3931d971337a
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Fri Apr 12 17:57:49 2024 +0800

    fix appsettings

commit 766fbec0c45a3852a75a7a37686b885ac3b0a77a
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Fri Apr 12 17:37:01 2024 +0800

    add dockerfile

commit 86731d41fee97ba073065ed1b807987760a371a7
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Sun Apr 14 20:11:56 2024 +0800

    fix 测试websocket链接

commit 1301b126a9ba9a7d97cf45967cf2915e1169c505
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Fri Apr 12 17:57:49 2024 +0800

    fix appsettings

commit 081f3a67896c67891c3f80edde82a440b8736851
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Fri Apr 12 17:37:01 2024 +0800

    add dockerfile

commit 271b6c5898b5732a35ccfa0629ce89442ac49143
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Fri Apr 12 17:34:26 2024 +0800

    test 提交测试代码

commit 965e84b6f3b7f925f8021c9b996cce961b896dea
Merge: 578eb6a 6a6fad1
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Mon Apr 15 17:06:45 2024 +0800

    Merge branch 'feat-visitorAppointments' of https://git.dlhis.com/liguoyang/jinko.yikatong into feat-visitorAppointments

commit 578eb6afbd96f0bfe4aaf8058fd4743309c74d62
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Sun Apr 14 20:11:56 2024 +0800

    fix 测试websocket链接

commit 114511f1daea64b7dbf9c3c38b73e28b6d0301e6
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Fri Apr 12 17:57:49 2024 +0800

    fix appsettings

commit 5eacfa8af8087eade8553266a12a2cf42305716b
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Fri Apr 12 17:37:01 2024 +0800

    add dockerfile

commit b2ffff1f099be343d89690014d05cb859776acbb
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Fri Apr 12 17:34:26 2024 +0800

    test 提交测试代码

commit 6a6fad1d1b8772eebf5df12cd74cfd5c955ff560
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Sun Apr 14 20:11:56 2024 +0800

    fix 测试websocket链接

commit 9ce3c4d6f63957c175d65370d9a6b80e10f4254f
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Fri Apr 12 17:57:49 2024 +0800

    fix appsettings

commit c637fd89850cf289d7da457c6c6f47354b5beed3
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Fri Apr 12 17:37:01 2024 +0800

    add dockerfile

commit 58c39815b1c45a99aea0caf503fcb1365c957f03
Author: liguoyang <Ligy.97@foxmail.com>
Date:   Fri Apr 12 17:34:26 2024 +0800

    test 提交测试代码
This commit is contained in:
2024-04-17 15:38:25 +08:00
parent 4b6d29291f
commit f8d1997ddd
68 changed files with 2086 additions and 412 deletions

View File

@@ -35,12 +35,18 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "External", "External", "{48
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.External", "Src\Dlhis.External\Dlhis.External.csproj", "{8472596E-0DE7-4A17-93D6-F0FC7D44FDF5}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.External", "Src\Dlhis.External\Dlhis.External.csproj", "{8472596E-0DE7-4A17-93D6-F0FC7D44FDF5}"
EndProject 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 EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.Canteen", "Src\Dlhis.Canteen\Dlhis.Canteen.csproj", "{A54426E2-1CA0-48AB-BBA6-07CDE2807E35}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.Canteen", "Src\Dlhis.Canteen\Dlhis.Canteen.csproj", "{A54426E2-1CA0-48AB-BBA6-07CDE2807E35}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.Canteen.Api", "Src\Dlhis.Canteen.Api\Dlhis.Canteen.Api.csproj", "{D4043506-7247-4DDC-9751-927403515669}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.Canteen.Api", "Src\Dlhis.Canteen.Api\Dlhis.Canteen.Api.csproj", "{D4043506-7247-4DDC-9751-927403515669}"
EndProject 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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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}.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.ActiveCfg = Release|Any CPU
{D4043506-7247-4DDC-9751-927403515669}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -120,6 +134,8 @@ Global
{9EA85FB2-F320-4F97-B278-00652CF35BD8} = {AA987BDF-EF63-467B-AD04-59F9B10D9000} {9EA85FB2-F320-4F97-B278-00652CF35BD8} = {AA987BDF-EF63-467B-AD04-59F9B10D9000}
{A54426E2-1CA0-48AB-BBA6-07CDE2807E35} = {3D8A98C1-83C9-4375-AEAB-4F72AFAF365B} {A54426E2-1CA0-48AB-BBA6-07CDE2807E35} = {3D8A98C1-83C9-4375-AEAB-4F72AFAF365B}
{D4043506-7247-4DDC-9751-927403515669} = {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 EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7439494A-E2FD-4FEA-8ABF-74AE57A4A5A0} SolutionGuid = {7439494A-E2FD-4FEA-8ABF-74AE57A4A5A0}

View File

@@ -10,8 +10,4 @@
<PackageReference Include="Kurisu.RemoteCall" Version="0.0.3" /> <PackageReference Include="Kurisu.RemoteCall" Version="0.0.3" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Response\" />
</ItemGroup>
</Project> </Project>

View File

@@ -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
{
/// <summary>
/// 获取分组下的设备
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
[Auth]
[Get("/api/deviceGroups/devices")]
Task<DefaultApiResult<List<DeviceUnderGroupResponse>>> GetDevicesByCodeAsync(Guid code);
}

View File

@@ -0,0 +1,21 @@
namespace Dlhis.Basic.Api.Response;
public class DeviceUnderGroupResponse
{
public Guid Code { get; set; }
/// <summary>
/// 设备唯一码,IP/MAC/SNO
/// </summary>
public string UniqueNo { get; set; }
/// <summary>
/// 品牌
/// </summary>
public string Brand { get; set; }
/// <summary>
/// 是否启用
/// </summary>
public bool Enable { get; set; }
}

View File

@@ -71,4 +71,14 @@ public class DeviceGroupsController : ControllerBase
{ {
await _deviceGroupService.AssignDevicesAsync(request); await _deviceGroupService.AssignDevicesAsync(request);
} }
/// <summary>
/// 获取用于预约的设备组
/// </summary>
/// <returns></returns>
[HttpGet("type/appointment")]
public async Task<List<DeviceGroupResponse>> GetAppointmentGroupsAsync()
{
return await _deviceGroupService.GetAppointmentGroupsAsync();
}
} }

View File

@@ -1,8 +0,0 @@
namespace Dlhis.Basic.Device.Dtos
{
public class IPPortDto
{
public string IP { get; set; }
public int Port { get; set; }
}
}

View File

@@ -1,9 +1,10 @@
using Dlhis.Entity.Device.Enums; using Dlhis.Entity.Device.Enums;
using Kurisu.AspNetCore.Utils.Extensions;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace Dlhis.Basic.Device.Request; namespace Dlhis.Basic.Device.Request;
public class DeviceGroupSaveRequest public class DeviceGroupSaveRequest : IValidatableObject
{ {
public long? Id { get; set; } public long? Id { get; set; }
@@ -22,10 +23,23 @@ public class DeviceGroupSaveRequest
/// 分类类型 DeviceTypeEnumType /// 分类类型 DeviceTypeEnumType
/// </summary> /// </summary>
[EnumDataType(typeof(DeviceTypeEnumType))] [EnumDataType(typeof(DeviceTypeEnumType))]
public DeviceTypeEnumType? Type { get; set; } public DeviceTypeEnumType Type { get; set; }
/// <summary>
/// 可作为预约分组
/// </summary>
public bool AsAppointment { get; set; }
/// <summary> /// <summary>
/// 备注 /// 备注
/// </summary> /// </summary>
public string Remark { get; set; } public string Remark { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (AsAppointment && Type != DeviceTypeEnumType.Door)
{
yield return new ValidationResult($"作为预约分组必要为{DeviceTypeEnumType.Door.GetDescription()}类型", new[] { nameof(Type) });
}
}
} }

View File

@@ -0,0 +1,19 @@
namespace Dlhis.Basic.Device.Response;
public class DeviceGroupResponse
{
/// <summary>
/// id
/// </summary>
public long Id { get; set; }
/// <summary>
/// code
/// </summary>
public Guid Code { get; set; }
/// <summary>
/// 分组名
/// </summary>
public string Name { get; set; }
}

View File

@@ -13,4 +13,6 @@ public interface IDeviceGroupService : IScopeDependency
Task<List<DeviceUnderGroupResponse>> GetDevicesAsync(Guid code); Task<List<DeviceUnderGroupResponse>> GetDevicesAsync(Guid code);
Task AssignDevicesAsync(DeviceAssignRequest requests); Task AssignDevicesAsync(DeviceAssignRequest requests);
Task<List<DeviceGroupResponse>> GetAppointmentGroupsAsync();
} }

View File

@@ -1,15 +1,14 @@
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using Dlhis.Basic.Device.Dtos;
using Dlhis.Basic.Device.Request; using Dlhis.Basic.Device.Request;
using Dlhis.Basic.Device.Response; using Dlhis.Basic.Device.Response;
using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Device.Entities; using Dlhis.Entity.Device.Entities;
using Dlhis.Entity.Device.Enums; using Dlhis.Entity.Device.Enums;
using Kurisu.AspNetCore.Utils.Extensions; using Kurisu.AspNetCore.Utils.Extensions;
using Kurisu.Core.CustomClass;
using Kurisu.SqlSugar.Services; using Kurisu.SqlSugar.Services;
using Mapster; using Mapster;
using Newtonsoft.Json;
namespace Dlhis.Basic.Device.Services.Implements; namespace Dlhis.Basic.Device.Services.Implements;

View File

@@ -78,14 +78,6 @@ public class DeviceGroupService : IDeviceGroupService
} }
} }
public async Task DeleteAsync(long id)
{
var deviceGroup = await _dbContext.Queryable<DeviceGroupEntity>().Where(x => x.Id == id).FirstAsync();
deviceGroup.ThrowIfNull("设备分组不存在,无需删除");
await _dbContext.DeleteAsync(deviceGroup);
}
public async Task AssignDevicesAsync(DeviceAssignRequest request) public async Task AssignDevicesAsync(DeviceAssignRequest request)
{ {
@@ -117,14 +109,39 @@ public class DeviceGroupService : IDeviceGroupService
public async Task<List<DeviceUnderGroupResponse>> GetDevicesAsync(Guid code) public async Task<List<DeviceUnderGroupResponse>> GetDevicesAsync(Guid code)
{ {
var relationships = await _dbContext.Queryable<DeviceGroupRelationshipEntity>().Where(x => x.GroupCode == code).ToListAsync(); var relationships = await _dbContext.Queryable<DeviceGroupRelationshipEntity>()
.Where(x => x.GroupCode == code)
.ToListAsync();
var deviceCodes = relationships.Select(x => x.DeviceCode); var deviceCodes = relationships.Select(x => x.DeviceCode);
return await _dbContext.Queryable<DeviceEntity>() return await _dbContext.Queryable<DeviceEntity>()
.LeftJoin<DeviceTemplateEntity>((x, dt) => x.TemplateCode == dt.Code)
.Where(x => deviceCodes.Contains(x.Code)) .Where(x => deviceCodes.Contains(x.Code))
.Select<DeviceUnderGroupResponse>() .Select((x, dt) => new DeviceUnderGroupResponse
{
UniqueNo = x.UniqueNo,
Type = x.Type,
Code = x.Code,
Enable = x.Enable,
Brand = dt.Brand
})
.ToListAsync(); .ToListAsync();
}
public async Task<List<DeviceGroupResponse>> GetAppointmentGroupsAsync()
{
return await _dbContext.Queryable<DeviceGroupEntity>()
.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 *********************************************************/ /****************************************************** help methods *********************************************************/

View File

@@ -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;
/// <summary>
/// 人员face
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class GainfoFacesController : ControllerBase
{
private readonly IGainfoFaceService _gainfoFaceService;
public GainfoFacesController(IGainfoFaceService gainfoFaceService)
{
_gainfoFaceService = gainfoFaceService;
}
/// <summary>
/// 上传外部人员人脸照片
/// </summary>
/// <returns></returns>
[AllowAnonymous]
[HttpPost("external/face")]
public async Task UploadExternalFaceAsync(GainfoUploadFaceRequest request)
{
await _gainfoFaceService.UploadExternalFaceAsync(request);
}
}

View File

@@ -18,21 +18,12 @@ namespace Dlhis.Basic.MealUser.Controllers;
public class GainfosController : ControllerBase public class GainfosController : ControllerBase
{ {
private readonly IGainfoService _gainfoService; private readonly IGainfoService _gainfoService;
private readonly IGainfoFaceService _gainfoFaceService;
public GainfosController(IGainfoService gainfoService) public GainfosController(IGainfoService gainfoService, IGainfoFaceService gainfoFaceService)
{ {
_gainfoService = gainfoService; _gainfoService = gainfoService;
} _gainfoFaceService = gainfoFaceService;
/// <summary>
/// 档案表保存
/// </summary>
/// <param name="requests"></param>
/// <returns></returns>
[HttpPost("save")]
public async Task SaveAsync(List<GainfoSaveRequest> requests)
{
await _gainfoService.SaveAsync(requests);
} }
/// <summary> /// <summary>
@@ -80,6 +71,17 @@ public class GainfosController : ControllerBase
await _gainfoService.UploadFaceAsync(request); await _gainfoService.UploadFaceAsync(request);
} }
/// <summary>
/// 上传外部人员人脸照片
/// </summary>
/// <returns></returns>
[AllowAnonymous]
[HttpPost("external/face")]
public async Task UploadExternalFaceAsync(GainfoUploadFaceRequest request)
{
await _gainfoFaceService.UploadExternalFaceAsync(request);
}
/// <summary> /// <summary>
/// 批量上传人脸照片 /// 批量上传人脸照片
/// </summary> /// </summary>
@@ -161,5 +163,18 @@ public class GainfosController : ControllerBase
{ {
await _gainfoService.MigrationAsync(request); await _gainfoService.MigrationAsync(request);
} }
/// <summary>
/// 检查idno和名称是否匹配
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpPost("check/idnoWithName")]
public async Task CheckIdNoAndNameMatchAsync(GainfoCheckIdNoAndNameRequest request)
{
await _gainfoService.CheckIdNoAndNameMatchAsync(request);
}
} }

View File

@@ -0,0 +1,19 @@
using System.ComponentModel.DataAnnotations;
namespace Dlhis.Basic.Organization.Request;
public class GainfoCheckIdNoAndNameRequest
{
/// <summary>
/// 身份证
/// </summary>
[Required(ErrorMessage = "身份证不可为空")]
[StringLength(18, ErrorMessage = "身份证位数错误", MinimumLength = 18)]
public string IdNo { get; set; }
/// <summary>
/// 姓名
/// </summary>
[Required(ErrorMessage = "姓名不可为空")]
public string Name { get; set; }
}

View File

@@ -11,14 +11,6 @@ public interface IGainfoService : IScopeDependency
Task<Pagination<GainfoAllPageResponse>> GetPageByCodeAsync(string code); Task<Pagination<GainfoAllPageResponse>> GetPageByCodeAsync(string code);
Task SaveAsync(List<GainfoSaveRequest> requests);
Task UpdateAsync(GainfoSaveRequest request);
Task DimissionAsync(GainfoDimissionRequest request);
Task OnboardingAsync(GainfoDimissionRequest request);
Task<GainfoCurrentResponse> CurrentUserInfoAsync(); Task<GainfoCurrentResponse> CurrentUserInfoAsync();
Task UploadFaceAsync(GainfoUploadFaceRequest request); Task UploadFaceAsync(GainfoUploadFaceRequest request);
@@ -37,4 +29,6 @@ public interface IGainfoService : IScopeDependency
Task MigrationAsync(MigrationRequest request); Task MigrationAsync(MigrationRequest request);
Task<string> CheckIdNoAndNameMatchAsync(GainfoCheckIdNoAndNameRequest request);
} }

View File

@@ -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.Request;
using Dlhis.Basic.Organization.Response; using Dlhis.Basic.Organization.Response;
using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Basic.Entity;
@@ -13,7 +14,6 @@ using Kurisu.Core.DataAccess.Dto;
using Kurisu.Core.User.Abstractions; using Kurisu.Core.User.Abstractions;
using Kurisu.SqlSugar.Extensions; using Kurisu.SqlSugar.Extensions;
using Kurisu.SqlSugar.Services; using Kurisu.SqlSugar.Services;
using Mapster;
using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@@ -23,10 +23,10 @@ public class GainfoService : IGainfoService
{ {
private readonly IGainfoStore _gainfoStore; private readonly IGainfoStore _gainfoStore;
private readonly IDbContext _dbContext; private readonly IDbContext _dbContext;
private readonly IDataProtectionProvider _dataProtectionProvider;
private readonly ICurrentUser _currentUser; private readonly ICurrentUser _currentUser;
private readonly IDevicePermissionService _devicePermissionService; private readonly IDevicePermissionService _devicePermissionService;
private readonly RedisCache _redisCache; private readonly RedisCache _redisCache;
private readonly IServiceProvider _serviceProvider;
private readonly IConfiguration _configuration; private readonly IConfiguration _configuration;
private readonly ITenantApi _tenantApi; private readonly ITenantApi _tenantApi;
private readonly IHangfireApi _hangfireApi; private readonly IHangfireApi _hangfireApi;
@@ -34,10 +34,10 @@ public class GainfoService : IGainfoService
public GainfoService(IGainfoStore gainfoStore, public GainfoService(IGainfoStore gainfoStore,
IDbContext dbContext, IDbContext dbContext,
IDataProtectionProvider dataProtectionProvider,
ICurrentUser currentUser, ICurrentUser currentUser,
IDevicePermissionService devicePermissionService, IDevicePermissionService devicePermissionService,
RedisCache redisCache, RedisCache redisCache,
IServiceProvider serviceProvider,
IConfiguration configuration, IConfiguration configuration,
ITenantApi tenantApi, ITenantApi tenantApi,
IHangfireApi hangfireApi, IHangfireApi hangfireApi,
@@ -45,10 +45,10 @@ public class GainfoService : IGainfoService
{ {
_gainfoStore = gainfoStore; _gainfoStore = gainfoStore;
_dbContext = dbContext; _dbContext = dbContext;
_dataProtectionProvider = dataProtectionProvider;
_currentUser = currentUser; _currentUser = currentUser;
_devicePermissionService = devicePermissionService; _devicePermissionService = devicePermissionService;
_redisCache = redisCache; _redisCache = redisCache;
_serviceProvider = serviceProvider;
_configuration = configuration; _configuration = configuration;
_tenantApi = tenantApi; _tenantApi = tenantApi;
_hangfireApi = hangfireApi; _hangfireApi = hangfireApi;
@@ -80,10 +80,8 @@ public class GainfoService : IGainfoService
.WhereIF(request.DepartmentSelections.IsEmpty(), gainfo => gainfo.Factory == currentTenantId) .WhereIF(request.DepartmentSelections.IsEmpty(), gainfo => gainfo.Factory == currentTenantId)
.WhereIF(request.Search.IsPresent(), gainfo => .WhereIF(request.Search.IsPresent(), gainfo =>
gainfo.Name.Contains(request.Search) gainfo.Name.Contains(request.Search)
|| gainfo.Code.Contains(request.Search) || gainfo.Code == request.Search
|| gainfo.IdNo.Contains(request.Search) || gainfo.IdNo == request.Search)
|| gainfo.Werks.Contains(request.Search)
)
.Select<GainfoPageResponse>() .Select<GainfoPageResponse>()
.ToPageListAsync(request); .ToPageListAsync(request);
@@ -109,78 +107,6 @@ public class GainfoService : IGainfoService
return page; return page;
} }
/// <summary>
///保存档案号
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task SaveAsync(List<GainfoSaveRequest> request)
{
//todo check
var entities = request.Adapt<List<GainfoEntity>>();
entities.ForEach(x =>
{
if (x.No.IsEmpty())
{
x.No = "F" + Guid.NewGuid().ToString();
}
});
await _gainfoStore.InsertAsync(entities);
}
/// <summary>
///修改档案号
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
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);
}
/// <summary>
/// 正式转离职
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
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);
}
/// <summary>
/// 临时转正式
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
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<GainfoCurrentResponse> CurrentUserInfoAsync() public async Task<GainfoCurrentResponse> CurrentUserInfoAsync()
{ {
var code = _currentUser.GetUserClaim("jinko-code"); var code = _currentUser.GetUserClaim("jinko-code");
@@ -239,9 +165,7 @@ public class GainfoService : IGainfoService
public async Task<IActionResult> GetFaceAsync(string token) public async Task<IActionResult> GetFaceAsync(string token)
{ {
var timeLimitedDataProtector = _serviceProvider.GetService<IDataProtectionProvider>() var timeLimitedDataProtector = _dataProtectionProvider.CreateProtector("down:face").ToTimeLimitedDataProtector();
.CreateProtector("down:face")
.ToTimeLimitedDataProtector();
try try
{ {
@@ -263,7 +187,6 @@ public class GainfoService : IGainfoService
return new NotFoundResult(); return new NotFoundResult();
} }
await _redisCache.HashSetAsync("faces", userCode, face.Face);
return new FileContentResult(Convert.FromBase64String(face.Face), "image/png"); return new FileContentResult(Convert.FromBase64String(face.Face), "image/png");
} }
catch (Exception ex) catch (Exception ex)
@@ -373,9 +296,7 @@ public class GainfoService : IGainfoService
face.ThrowIfNull("人脸照片尚未录入"); face.ThrowIfNull("人脸照片尚未录入");
var timeLimitedDataProtector = _serviceProvider.GetService<IDataProtectionProvider>() var timeLimitedDataProtector = _dataProtectionProvider.CreateProtector("down:face").ToTimeLimitedDataProtector();
.CreateProtector("down:face")
.ToTimeLimitedDataProtector();
var faceUrl = _configuration.GetSection("FaceUrlOptions:Url").Value; var faceUrl = _configuration.GetSection("FaceUrlOptions:Url").Value;
var limit = _configuration.GetSection("FaceUrlOptions:Limit").Get<int>(); var limit = _configuration.GetSection("FaceUrlOptions:Limit").Get<int>();
@@ -404,6 +325,20 @@ public class GainfoService : IGainfoService
return faceDictionary; return faceDictionary;
} }
public async Task<string> 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;
}
/// <summary> /// <summary>
/// 档案列表 /// 档案列表
/// </summary> /// </summary>

View File

@@ -53,8 +53,8 @@ public class SqlSugarPack : BaseAppPack
public override void Configure(IApplicationBuilder app, IWebHostEnvironment env) public override void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{ {
var siGenerate = Configuration.GetSection("SqlSugarOptions").GetValue<bool>("Generate"); var isGenerate = Configuration.GetSection("SqlSugarOptions").GetValue<bool>("Generate");
if (siGenerate) if (isGenerate)
{ {
using var scope = app.ApplicationServices.CreateScope(); using var scope = app.ApplicationServices.CreateScope();
var db = scope.ServiceProvider.GetService<IDbContext>(); var db = scope.ServiceProvider.GetService<IDbContext>();

View File

@@ -5,7 +5,6 @@
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
}, },
"EightThirtyPM": "20:30:00",
"InternalRequest": { "InternalRequest": {
"CommonRequestUrl": "http://localhost:5001", "CommonRequestUrl": "http://localhost:5001",
"SysRequestUrl": "http://localhost:5003", "SysRequestUrl": "http://localhost:5003",

View File

@@ -62,7 +62,7 @@ public class GainfoEntity : SugarBaseEntity
/// <summary> /// <summary>
/// 身份证号 /// 身份证号
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "身份证号")] [SugarColumn(ColumnDescription = "身份证号", UniqueGroupNameList = new[] { "idx_Gainfo_IdNo" })]
public string IdNo { get; set; } public string IdNo { get; set; }
/// <summary> /// <summary>
@@ -211,22 +211,4 @@ public class GainfoExternalEntity : GainfoEntity
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "公司", IsNullable = false)] [SugarColumn(ColumnDescription = "公司", IsNullable = false)]
public string Company { get; set; } public string Company { get; set; }
/// <summary>
/// 到达时间
/// </summary>
[SugarColumn(ColumnDescription = "到达时间")]
public DateTime From { get; set; }
/// <summary>
/// 离开时间
/// </summary>
[SugarColumn(ColumnDescription = "离开时间")]
public DateTime To { get; set; }
/// <summary>
/// 对接人<see cref="GainfoEntity"/>No
/// </summary>
[SugarColumn(ColumnDescription = "对接人", IsNullable = false)]
public string JinkoNo { get; set; }
} }

View File

@@ -55,6 +55,12 @@ public class DeviceGroupEntity : SugarBaseEntity, ITenantId, ISoftDeleted
[SugarColumn(IsNullable = true)] [SugarColumn(IsNullable = true)]
public string Remark { get; set; } public string Remark { get; set; }
/// <summary>
/// 可作为预约分组
/// </summary>
[SugarColumn(ColumnDataType = "bit", DefaultValue = "0")]
public bool AsAppointment { get; set; } = false;
public string TenantId { get; set; } public string TenantId { get; set; }

View File

@@ -15,7 +15,7 @@ public class DeviceTaskEntity : SugarBaseEntity, ITenantId, IVersion
/// <summary> /// <summary>
/// 任务类型 /// 任务类型
/// </summary> /// </summary>
[SugarColumn(ColumnDataType = "varchar(50)", SqlParameterDbType = typeof(EnumToStringConvert))] [SugarColumn(ColumnDataType = "varchar(50)", SqlParameterDbType = typeof(EnumToStringConvert), IndexGroupNameList = new[] { "idx_DeviceTask_Type" })]
public DeviceTaskEnumType Type { get; set; } public DeviceTaskEnumType Type { get; set; }
/// <summary> /// <summary>
@@ -44,7 +44,7 @@ public class DeviceTaskEntity : SugarBaseEntity, ITenantId, IVersion
/// <summary> /// <summary>
/// 任务下发状态 /// 任务下发状态
/// </summary> /// </summary>
[SugarColumn(ColumnDataType = "varchar(50)", SqlParameterDbType = typeof(EnumToStringConvert))] [SugarColumn(ColumnDataType = "varchar(50)", SqlParameterDbType = typeof(EnumToStringConvert), IndexGroupNameList = new[] { "idx_DeviceTask_Status" })]
public DeviceTaskStatusEnumType Status { get; set; } public DeviceTaskStatusEnumType Status { get; set; }
/// <summary> /// <summary>

View File

@@ -6,10 +6,6 @@
<Nullable>disable</Nullable> <Nullable>disable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<None Include="..\..\.editorconfig" Link=".editorconfig" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Kurisu.SqlSugar" Version="0.3.2" /> <PackageReference Include="Kurisu.SqlSugar" Version="0.3.2" />
</ItemGroup> </ItemGroup>

View File

@@ -0,0 +1,28 @@
using Kurisu.Core.DataAccess.Entity;
using Kurisu.SqlSugar;
using SqlSugar;
namespace Dlhis.Entity.Visitor.Entity;
/// <summary>
/// 预约区域分配
/// </summary>
[SugarTable(TableName = "AppointmentAreaAssignment", TableDescription = "预约区域分配")]
public class AppointmentAreaAssignmentEntity : SugarBaseEntity, ITenantId
{
/// <summary>
/// 预约区域编码
/// </summary>
[SugarColumn(IsNullable = false, ColumnDescription = "预约区域编码")]
public string CustomCode { get; set; }
/// <summary>
/// 分组code
/// </summary>
[SugarColumn(IsNullable = false, ColumnDescription = "分组code")]
public Guid GroupCode { get; set; }
//UniqueGroupNameList = new[] { "idx_aaa_cc_grpc_tid" }
[SugarColumn()]
public string TenantId { get; set; }
}

View File

@@ -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;
/// <summary>
/// 预约区域
/// </summary>
[SugarTable(TableName = "AppointmentArea", TableDescription = "预约区域")]
public class AppointmentAreaEntity : SugarBaseEntity, ITenantId, ISoftDeleted
{
/// <summary>
/// 区域类型
/// </summary>
[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; }
/// <summary>
/// 自定义编码
/// </summary>
[AdaptIgnore(MemberSide.Destination)]
[SugarColumn(IsNullable = false, ColumnDescription = "自定义编码",
UniqueGroupNameList = new[] { "idx_ApponintmentArea_t_cc_tid" })]
public string CustomCode { get; set; }
/// <summary>
/// 名称
/// </summary>
[SugarColumn(IsNullable = false, ColumnDescription = "名称")]
public string Name { get; set; }
/// <summary>
/// 备注
/// </summary>
[SugarColumn(IsNullable = true, ColumnDescription = "备注")]
public string Remark { get; set; }
/// <summary>
/// 基地/租户
/// </summary>
[SugarColumn(IsNullable = false, ColumnDescription = " 基地/租户",
UniqueGroupNameList = new[] { "idx_ApponintmentArea_t_cc_tid" })]
public string TenantId { get; set; }
public bool IsDeleted { get; set; }
}

View File

@@ -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;
/// <summary>
/// 预约区域
/// </summary>
[SugarTable(TableName = "ApponintmentArea", TableDescription = "预约区域")]
public class ApponintmentAreaEntity : SugarBaseEntity, ITenantId
{
/// <summary>
/// 区域类型
/// </summary>
[SugarColumn(IsNullable = false, ColumnDescription = "区域类型", ColumnDataType = "varchar(50)", SqlParameterDbType = typeof(EnumToStringConvert))]
public AppointmentAreaEnumType Type { get; set; }
/// <summary>
/// 自定义编码
/// </summary>
[SugarColumn(IsNullable = false, ColumnDescription = "自定义编码", UniqueGroupNameList = new[] { "idx_aa_cc_tid" })]
public string CustomCode { get; set; }
/// <summary>
/// 名称
/// </summary>
[SugarColumn(IsNullable = false, ColumnDescription = "名称")]
public string Name { get; set; }
/// <summary>
/// 备注
/// </summary>
[SugarColumn(IsNullable = true, ColumnDescription = "备注")]
public string Remark { get; set; }
/// <summary>
/// 基地/租户
/// </summary>
[SugarColumn(IsNullable = false, ColumnDescription = " 基地/租户", UniqueGroupNameList = new[] { "idx_aa_cc_tid" })]
public string TenantId { get; set; }
}

View File

@@ -0,0 +1,73 @@
using Dlhis.Entity.Visitor.Enums;
using Kurisu.SqlSugar;
using SqlSugar;
using SqlSugar.DbConvert;
namespace Dlhis.Entity.Visitor.Entity;
/// <summary>
/// 预约明细
/// </summary>
[SugarTable(TableName = "VisitorAppointmentDetail", TableDescription = "访客预约")]
public class VisitorAppointmentDetailEntity : SugarBaseEntity
{
[SugarColumn(IsNullable = false, ColumnDescription = "父id")]
public long AppointmentId { get; set; }
/// <summary>
/// 流水号
/// </summary>
[SugarColumn(IsNullable = false, ColumnDescription = "流水号")]
public string FlowId { get; set; }
/// <summary>
/// 访客名称
/// </summary>
[SugarColumn(IsNullable = false, ColumnDescription = "访客名称")]
public string Name { get; set; }
/// <summary>
/// 手机号
/// </summary>
[SugarColumn(IsNullable = false, ColumnDescription = "手机号")]
public string Phone { get; set; }
/// <summary>
/// 是否外部人员
/// </summary>
[SugarColumn(IsNullable = false, ColumnDataType = "bit")]
public bool IsExternal { get; set; }
/// <summary>
/// 身份证
/// </summary>
/// <remarks>
/// 使用身份证字段作为申请人唯一标识
/// </remarks>
[SugarColumn(IsNullable = false, ColumnDescription = "身份证")]
public string IdNo { get; set; }
/// <summary>
/// 预计到达
/// </summary>
[SugarColumn(IsNullable = false, ColumnDescription = "预计到达")]
public DateTime Start { get; set; }
/// <summary>
/// 预计离开
/// </summary>
[SugarColumn(IsNullable = false, ColumnDescription = "预计离开")]
public DateTime End { get; set; }
/// <summary>
/// 状态
/// </summary>
[SugarColumn(IsNullable = false, ColumnDescription = "状态", ColumnDataType = "varchar(50)", SqlParameterDbType = typeof(EnumToStringConvert))]
public AppointmentDetailEnumType Status { get; set; }
/// <summary>
/// 备注
/// </summary>
[SugarColumn(IsNullable = true, ColumnDescription = "备注")]
public string Remark { get; set; }
}

View File

@@ -0,0 +1,30 @@
using Kurisu.SqlSugar;
using SqlSugar;
namespace Dlhis.Entity.Visitor.Entity;
[SugarTable(TableName = "VisitorAppointment", TableDescription = "访客预约")]
public class VisitorAppointmentEntity : SugarBaseEntity
{
/// <summary>
/// 流水号
/// </summary>
[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; }
}

View File

@@ -0,0 +1,22 @@
using System.ComponentModel;
namespace Dlhis.Entity.Visitor.Enums;
/// <summary>
/// 预约区域类型
/// </summary>
[Description("预约区域类型")]
public enum AppointmentAreaEnumType
{
/// <summary>
/// 门岗
/// </summary>
[Description("门岗")]
Door = 1,
/// <summary>
/// 车间
/// </summary>
[Description("车间")]
Workshop = 2,
}

View File

@@ -0,0 +1,35 @@
using System.ComponentModel;
namespace Dlhis.Entity.Visitor.Enums;
/// <summary>
/// 访客预约明细状态
/// </summary>
[Description("预约状态")]
public enum AppointmentDetailEnumType
{
/// <summary>
/// 待来访
/// </summary>
[Description("待来访")]
Wait = 0,
/// <summary>
/// 取消
/// </summary>
[Description("取消")]
Cancel = 5,
/// <summary>
/// 到达
/// </summary>
[Description("到达")]
Arrived = 10,
/// <summary>
/// 离开
/// </summary>
[Description("离开")]
Leave = 99
}

View File

@@ -0,0 +1,19 @@
using System.ComponentModel;
namespace Dlhis.Entity.Visitor.Enums;
[Description("预约区域")]
public enum ApponintmentAreaEnumType
{
/// <summary>
/// 门岗
/// </summary>
[Description("门岗")]
Door = 1,
/// <summary>
/// 车间
/// </summary>
[Description("车间")]
Workshop = 2,
}

View File

@@ -0,0 +1,22 @@
using System.ComponentModel;
namespace Dlhis.Entity.Visitor.Enums;
/// <summary>
/// 访客预约明细状态
/// </summary>
[Description("访客预约状态")]
public enum VisitorAppointmentDetailEnumType
{
/// <summary>
/// 到达
/// </summary>
[Description("到达")]
Arrived = 1,
/// <summary>
/// 离开
/// </summary>
[Description("离开")]
Leave = 99
}

View File

@@ -0,0 +1,26 @@
using Dlhis.Message.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
namespace Dlhis.Message.Controllers;
/// <summary>
///
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class AppointmentPushController : ControllerBase
{
private readonly IHubContext<VisitorAppointmentHub, IVisitorAppointmentService> _hubContext;
public AppointmentPushController(IHubContext<VisitorAppointmentHub, IVisitorAppointmentService> hubContext)
{
_hubContext = hubContext;
}
[HttpPost("push")]
public async Task PushAsync(Dictionary<string, string> values)
{
await _hubContext.Clients.All.Raise(values);
}
}

View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>..\..</DockerfileContext>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Kurisu.AspNetCore" Version="0.8.3" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
</ItemGroup>
</Project>

View File

@@ -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"]

View File

@@ -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<VisitorAppointmentHub>("/hub/appointment");
});
}
}

View File

@@ -0,0 +1,20 @@
using Kurisu.AspNetCore.Startup;
using Kurisu.Startup;
using Microsoft.IdentityModel.Logging;
class Program
{
static void Main(string[] args)
{
KurisuHost.Run<Startup>(true, args);
}
}
public class Startup : DefaultStartup
{
public Startup(IConfiguration configuration) : base(configuration)
{
IdentityModelEventSource.ShowPII = true;
}
}

View File

@@ -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"
}

View File

@@ -0,0 +1,6 @@
namespace Dlhis.Message.Services;
public interface IVisitorAppointmentService
{
Task Raise(Dictionary<string, string> obj);
}

View File

@@ -0,0 +1,26 @@

using Dlhis.Message.Services;
using Microsoft.AspNetCore.SignalR;
namespace Dlhis.Message
{
public class TestBackgroundService : BackgroundService, ISingletonDependency
{
private readonly IHubContext<VisitorAppointmentHub, IVisitorAppointmentService> _hubContext;
public TestBackgroundService(IHubContext<VisitorAppointmentHub, IVisitorAppointmentService> hubContext)
{
_hubContext = hubContext;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await _hubContext.Clients.All.Raise(new Dictionary<string, string> { ["name"] = "ligy" });
await Task.Delay(1000 * 10);
}
}
}
}

View File

@@ -0,0 +1,19 @@
using Dlhis.Message.Services;
using Microsoft.AspNetCore.SignalR;
namespace Dlhis.Message;
public class VisitorAppointmentHub : Hub<IVisitorAppointmentService>
{
private readonly ILogger<VisitorAppointmentHub> _logger;
public VisitorAppointmentHub(ILogger<VisitorAppointmentHub> logger)
{
_logger = logger;
}
public override async Task OnConnectedAsync()
{
_logger.LogInformation("链接");
}
}

View File

@@ -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": ""
}
}

View File

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

View File

@@ -30,7 +30,7 @@ public abstract class BaseJob : IJob
sqlSugarOptionsService.IgnoreTenant = true; sqlSugarOptionsService.IgnoreTenant = true;
var name = this.GetType().GetCustomAttribute<RecurringJobAttribute>()!.Name; var name = this.GetType().GetCustomAttribute<RecurringJobAttribute>()!.Name;
Logger.LogInformation("[{name}]开始执行...", name); Logger.LogDebug("[{name}]开始执行...", name);
try try
{ {
@@ -42,7 +42,7 @@ public abstract class BaseJob : IJob
} }
finally finally
{ {
Logger.LogInformation("[{name}]执行结束...", name); Logger.LogDebug("[{name}]执行结束...", name);
DbContext.Client.QueryFilter.Restore(); DbContext.Client.QueryFilter.Restore();
sqlSugarOptionsService.IgnoreTenant = false; sqlSugarOptionsService.IgnoreTenant = false;
} }

View File

@@ -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; }
}

View File

@@ -13,6 +13,7 @@ using Newtonsoft.Json.Linq;
using Kurisu.Core.CustomClass; using Kurisu.Core.CustomClass;
using Kurisu.AspNetCore; using Kurisu.AspNetCore;
using Kurisu.AspNetCore.Utils; using Kurisu.AspNetCore.Utils;
using Dlhis.ScheduledTask.TaskAssignment.Dto;
namespace Dlhis.ScheduledTask.TaskAssignment.Services.Implements; namespace Dlhis.ScheduledTask.TaskAssignment.Services.Implements;
@@ -21,248 +22,158 @@ public class AssignmentService : IAssignmentService
private readonly IDbContext _dbContext; private readonly IDbContext _dbContext;
private readonly IDataProtectionProvider _dataProtectionProvider; private readonly IDataProtectionProvider _dataProtectionProvider;
private readonly FaceUrlOptions _faceUrlOptions; private readonly FaceUrlOptions _faceUrlOptions;
private readonly ILogger<AssignmentService> _logger;
public AssignmentService(IDbContext dbContext, public AssignmentService(IDbContext dbContext,
IDataProtectionProvider dataProtectionProvider, IDataProtectionProvider dataProtectionProvider,
IOptions<FaceUrlOptions> options, IOptions<FaceUrlOptions> options)
ILogger<AssignmentService> logger)
{ {
_dbContext = dbContext; _dbContext = dbContext;
_dataProtectionProvider = dataProtectionProvider; _dataProtectionProvider = dataProtectionProvider;
_faceUrlOptions = options.Value; _faceUrlOptions = options.Value;
_logger = logger;
} }
public async Task<List<DeviceTaskToDeviceByDeviceResponse>> DeviceGetTasksAsync(DeviceTaskGetRequest request) public async Task<List<DeviceTaskToDeviceByDeviceResponse>> DeviceGetTasksAsync(DeviceTaskGetRequest request)
{ {
////获取心跳设备 todo var data = await GetDataAsync(request);
//var key = "heardbeat-devices"; if (data.IsEmpty()) return new List<DeviceTaskToDeviceByDeviceResponse>();
//var heartbeatDeviceNos = (await _redisCache.ListRangeAsync(key))?.Select(x => x.ToString()).ToList();
var data = await CommonHelper.RetryAsync(async () => var deviceUploadInfos = await GetDeviceUploadRecordInfosAsync(data);
{
var page = await _dbContext.Queryable<DeviceTaskEntity>()
.LeftJoin<DeviceEntity>((deviceTask, deivce) => deviceTask.DeviceUniqueNo == deivce.UniqueNo)
.LeftJoin<DeviceTemplateEntity>((deviceTask, deivce, deivceTamplate) => deivceTamplate.Code == deivce.TemplateCode)
.LeftJoin<GainfoEntity>((deviceTask, deivce, deivceTamplate, ga) => deviceTask.UserNo == ga.No)
.LeftJoin<GainfoLeaveEntity>((deviceTask, deivce, deivceTamplate, ga, galeave) => deviceTask.UserNo == galeave.No)
.LeftJoin<DepartmentEntity>((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<DeviceTaskEntity>();
taskIdVs.ForEach(p =>
{
where = where.Or(x => x.Id == p.TaskId && x.Version == p.Version && x.Status != DeviceTaskStatusEnumType.Success);
});
var effecet = await _dbContext.Updateable<DeviceTaskEntity>()
.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<DeviceTaskToDeviceByDeviceResponse>();
}
Dictionary<string, DateTime?> deviceUploadInfos = null;
if (data.Any(x => x.Type == DeviceTaskEnumType.UploadRecord))
{
var deviceNos = data.Select(x => x.DeviceUniqueNo).Distinct();
deviceUploadInfos = new Dictionary<string, DateTime?>(deviceNos.Count());
var logInfos = await _dbContext.Queryable<DeviceUploadLogEntity>().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 timeLimitedDataProtector = _dataProtectionProvider var timeLimitedDataProtector = _dataProtectionProvider
.CreateProtector("down:face") .CreateProtector("down:face")
.ToTimeLimitedDataProtector(); .ToTimeLimitedDataProtector();
return data.GroupBy(x => new { x.Brand, x.DeviceUniqueNo, x.DeviceConnectionInfo, x.FuncStr }) return data.GroupBy(x => new { x.Brand, x.DeviceUniqueNo, x.DeviceConnectionInfo, x.FuncStr })
.Select(x => .Select(x =>
{ {
var b = x.Key.Brand; var b = x.Key.Brand;
var d = x.Key.DeviceUniqueNo; var d = x.Key.DeviceUniqueNo;
var dc = x.Key.DeviceConnectionInfo ?? "{}"; var dc = x.Key.DeviceConnectionInfo ?? "{}";
var func = x.Key.FuncStr ?? "[]"; var func = x.Key.FuncStr ?? "[]";
var jobj = new JObject var jobj = new JObject
{ {
{ "connectionInfo", JToken.Parse(dc) }, { "connectionInfo", JToken.Parse(dc) },
{ "function", JArray.Parse(func) } { "function", JArray.Parse(func) }
}; };
return new DeviceTaskToDeviceByDeviceResponse return new DeviceTaskToDeviceByDeviceResponse
{ {
Brand = b, Brand = b,
DeviceUniqueNo = d, DeviceUniqueNo = d,
DeviceInfo = jobj, DeviceInfo = jobj,
Tasks = x.AsEnumerable().Select(item => Tasks = x.Select(item =>
{ {
var key = $"face:{item.UserCode}"; var key = $"face:{item.UserCode}";
var token = item.Type == DeviceTaskEnumType.Delete var token = item.Type == DeviceTaskEnumType.Delete
? string.Empty ? string.Empty
: timeLimitedDataProtector.Protect(key, TimeSpan.FromSeconds(_faceUrlOptions.Limit)); : timeLimitedDataProtector.Protect(key, TimeSpan.FromSeconds(_faceUrlOptions.Limit));
var dto = new TaskCombineDto var dto = new TaskCombineDto
{ {
TaskId = item.TaskId, TaskId = item.TaskId,
Type = item.Type, Type = item.Type,
}; };
switch (dto.Type) switch (dto.Type)
{ {
case DeviceTaskEnumType.Add: case DeviceTaskEnumType.Add:
case DeviceTaskEnumType.Delete: case DeviceTaskEnumType.Delete:
case DeviceTaskEnumType.Update: case DeviceTaskEnumType.Update:
{ {
dto.Info = new UserToDeviceResponse dto.Info = new UserToDeviceResponse
{ {
UserId = item.UserId.Value, UserId = item.UserId.HasValue ? item.UserId.Value : 0,
UserNo = item.UserNo, UserNo = item.UserNo,
UserCode = item.UserCode, UserCode = item.UserCode,
UserName = item.UserName, UserName = item.UserName,
DepartmentNo = item.DepartmentNo, DepartmentNo = item.DepartmentNo,
DepartmentName = item.DepartmentName, DepartmentName = item.DepartmentName,
CardNo = item.Type == DeviceTaskEnumType.Delete ? string.Empty : item.CardNo, CardNo = item.Type == DeviceTaskEnumType.Delete ? string.Empty : item.CardNo,
Face = item.Type == DeviceTaskEnumType.Delete ? string.Empty : _faceUrlOptions.Url + token,//下发才附带照片信息 Face = item.Type == DeviceTaskEnumType.Delete ? string.Empty : _faceUrlOptions.Url + token,//下发才附带照片信息
ValidDatePeriod = new DatePeriod ValidDatePeriod = new DatePeriod
{ {
Start = DateOnly.FromDateTime(DateTime.Now.AddDays(-1)), Start = DateOnly.FromDateTime(DateTime.Now.AddDays(-1)),
End = DateOnly.FromDateTime(DateTime.Now.AddYears(20)), End = DateOnly.FromDateTime(DateTime.Now.AddYears(20)),
}, },
TimePeriods = new List<int> { 1 }, TimePeriods = new List<int> { 1 },
Doors = new List<int> { 1 }, Doors = new List<int> { 1 },
Schedule = 1 Schedule = 1
}; };
} }
break; break;
case DeviceTaskEnumType.TimePeriodAdd: case DeviceTaskEnumType.TimePeriodAdd:
case DeviceTaskEnumType.TimePeriodDelete: case DeviceTaskEnumType.TimePeriodDelete:
{ {
dto.Info = new TimePeriodToDeviceResponse dto.Info = new TimePeriodToDeviceResponse
{ {
Id = 1, Id = 1,
Name = "小白领", Name = "小白领",
Enable = true, Enable = true,
Sections = new List<TimePeriodWeekDaySection>() Sections = new List<TimePeriodWeekDaySection>()
{ {
new() new()
{ {
DayOfWeek= DayOfWeek.Monday, DayOfWeek= DayOfWeek.Monday,
TimePeriods = new List<TimePeriod>() TimePeriods = new List<TimePeriod>()
{
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<ScheduleDto>
{
new()
{
Name = "国庆节",
DateTimePeriod = new DateTimePeriod
{ {
Start = new DateTime(2024,10,1), new()
End = new DateTime(2024,10,7) {
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<ScheduleDto>
{
new()
{
Name = "国庆节",
DateTimePeriod = new DateTimePeriod
{
Start = new DateTime(2024,10,1),
End = new DateTime(2024,10,7)
}
}
}
};
}
break;
case DeviceTaskEnumType.UploadRecord: case DeviceTaskEnumType.UploadRecord:
{ {
dto.Info = new UploadRecordToDeviceResponse dto.Info = new UploadRecordToDeviceResponse
{ {
DateTimePeriod = new DateTimePeriod DateTimePeriod = new DateTimePeriod
{ {
Start = deviceUploadInfos[d] ?? DateTime.Now, Start = deviceUploadInfos[d] ?? DateTime.Now,
End = DateTime.Now.AddDays(1) End = DateTime.Now.AddDays(1)
} }
}; };
} }
break; break;
default: default:
break; break;
} }
return dto; return dto;
}).ToList() }).ToList()
}; };
}).ToList(); }).ToList();
} }
/// <summary> /// <summary>
@@ -314,4 +225,101 @@ public class AssignmentService : IAssignmentService
await _dbContext.UpdateAsync(deviceTasks); await _dbContext.UpdateAsync(deviceTasks);
} }
//**************************************************** help method **************************************************
private async Task<List<TaskDto>> GetDataAsync(DeviceTaskGetRequest request)
{
var data = await CommonHelper.RetryAsync(async () =>
{
var page = await _dbContext.Queryable<DeviceTaskEntity>()
.LeftJoin<DeviceEntity>((deviceTask, deivce) => deviceTask.DeviceUniqueNo == deivce.UniqueNo)
.LeftJoin<DeviceTemplateEntity>((deviceTask, deivce, deivceTamplate) => deivceTamplate.Code == deivce.TemplateCode)
.LeftJoin<GainfoEntity>((deviceTask, deivce, deivceTamplate, ga) => deviceTask.UserNo == ga.No)
.LeftJoin<GainfoLeaveEntity>((deviceTask, deivce, deivceTamplate, ga, galeave) => deviceTask.UserNo == galeave.No)
.LeftJoin<DepartmentEntity>((deviceTask, deivce, deivceTamplate, ga, galeave, department) => department.No == ga.DepartmentNo)
.LeftJoin<GainfoExternalEntity>((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<DeviceTaskEntity>();
//taskIdVs.ForEach(p =>
//{
// where = where.Or(x => x.Id == p.TaskId && x.Version == p.Version && x.Status == p.Status);
//});
//var effecet = await _dbContext.Updateable<DeviceTaskEntity>()
// .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<Dictionary<string, DateTime?>> GetDeviceUploadRecordInfosAsync(List<TaskDto> data)
{
if (data.Any(x => x.Type == DeviceTaskEnumType.UploadRecord))
{
var deviceNos = data.Select(x => x.DeviceUniqueNo).Distinct();
var result = new Dictionary<string, DateTime?>(deviceNos.Count());
//日志数据最后一条
var logInfos = await _dbContext.Queryable<DeviceUploadLogEntity>().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<string, DateTime?>();
}
} }

View File

@@ -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;
/// <summary>
/// ԤԼ
/// </summary>
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class AppointmentsController : ControllerBase
{
private readonly IAppointmentService _appointmentService;
public AppointmentsController(IAppointmentService appointmentService)
{
_appointmentService = appointmentService;
}
/// <summary>
/// <20><><EFBFBD><EFBFBD>ԤԼд<D4BC><D0B4>
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[AllowAnonymous]
[Transactional]
[IgnoreTenant]
[HttpPost("receive")]
public async Task ReceiveAsync(AppointmentReceiveRequest request)
{
await _appointmentService.ReceiveAsync(request);
}
/// <summary>
/// ԤԼ<D4A4><D4BC>ҳ
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet("page")]
public async Task<Pagination<AppointmentPageResponse>> GetPageAsync([FromQuery] AppointmentPageRequest request)
{
return await _appointmentService.GetPageAsync(request);
}
/// <summary>
/// ȷ<>ϵ<EFBFBD><CFB5><EFBFBD>
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost("confirm")]
public async Task ConfirmAsync(AppointmentConfirmRequest request)
{
await _appointmentService.ConfirmAsync(request);
}
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֤<EFBFBD><D6A4>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD>ÿ<EFBFBD>ԤԼ
/// </summary>
/// <param name="idNo"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpGet("today")]
public async Task<AppointmentDetailResponse> GetTodayByIdNoAsync(
[FromQuery]
[StringLength(18, MinimumLength = 18, ErrorMessage = "<22><><EFBFBD><EFBFBD>֤<EFBFBD><D6A4><EFBFBD><EFBFBD>")]
[Required(ErrorMessage = "<22><><EFBFBD><EFBFBD>֤<EFBFBD><D6A4><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>")]string idNo)
{
return await _appointmentService.GetTodayByIdNoAsync(idNo);
}
[AllowAnonymous]
[HttpGet("idno/page")]
public async Task<Pagination<AppointmentDetailResponse>> GetRecordPageByIdNoAsync([FromQuery] AppointmentIdNoPageRequest request)
{
return await _appointmentService.GetRecordPageByIdNoAsync(request);
}
}

View File

@@ -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;
/// <summary>
/// 预约区域
/// </summary>
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class ApponintmentAreasController : ControllerBase
{
private readonly IApponintmentAreaService _apponintmentAreaService;
public ApponintmentAreasController(IApponintmentAreaService apponintmentAreaService)
{
_apponintmentAreaService = apponintmentAreaService;
}
/// <summary>
/// 预约区域
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet("page")]
public async Task<Pagination<ApponintmentAreaPageResponse>> GetPageAsync([FromQuery] PageDto request)
{
return await _apponintmentAreaService.GetPageAsync(request);
}
/// <summary>
/// 保存
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost("save")]
public async Task SaveAsync(AppointmentAreaSaveRequest request)
{
await _apponintmentAreaService.SaveAsync(request);
}
/// <summary>
/// 删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpDelete("{id}")]
public async Task DeleteAsync(long id)
{
await _apponintmentAreaService.DeleteAsync(id);
}
/// <summary>
/// 分配设备组
/// </summary>
/// <returns></returns>
[HttpPost("assign")]
public async Task AssignAsync(AppointmentAreaAssignRequest request)
{
await _apponintmentAreaService.AssignAsync(request);
}
}

View File

@@ -0,0 +1,31 @@
using System.ComponentModel.DataAnnotations;
namespace Dlhis.Visitor.Appointment.Dto;
public class AppointmentReceiveItemDto
{
/// <summary>
/// 姓名
/// </summary>
[Required(ErrorMessage = "姓名必填")]
public string Name { get; set; }
/// <summary>
/// 手机号
/// </summary>
[StringLength(11, MinimumLength = 11)]
[Required(ErrorMessage = "手机号必填")]
public string Phone { get; set; }
/// <summary>
/// 身份证
/// </summary>
[StringLength(18, MinimumLength = 18)]
[Required(ErrorMessage = "身份证必填")]
public string IdNo { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}

View File

@@ -0,0 +1,18 @@
using System.ComponentModel.DataAnnotations;
namespace Dlhis.Visitor.Appointment.Request;
public class AppointmentAreaAssignRequest
{
/// <summary>
/// 预约区域编码
/// </summary>
[Required]
public string CustomCode { get; set; }
/// <summary>
/// 分组
/// </summary>
public List<Guid> GroupCodes { get; set; }
}

View File

@@ -0,0 +1,35 @@
using System.ComponentModel.DataAnnotations;
using Dlhis.Entity.Visitor.Enums;
namespace Dlhis.Visitor.Appointment.Request;
public class AppointmentAreaSaveRequest
{
/// <summary>
/// 数据id
/// </summary>
public long? Id { get; set; }
/// <summary>
/// 区域 AppointmentAreaEnumType
/// </summary>
[EnumDataType(typeof(AppointmentAreaEnumType))]
public AppointmentAreaEnumType Type { get; set; }
/// <summary>
/// 预期编码
/// </summary>
[Required]
public string CustomCode { get; set; }
/// <summary>
/// 姓名
/// </summary>
[Required]
public string Name { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}

View File

@@ -0,0 +1,6 @@
namespace Dlhis.Visitor.Appointment.Request;
public class AppointmentConfirmRequest
{
public long Id { get; set; }
}

View File

@@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;
using Kurisu.Core.DataAccess.Dto;
namespace Dlhis.Visitor.Appointment.Request;
public class AppointmentIdNoPageRequest : PageDto
{
/// <summary>
/// 身份证
/// </summary>
[StringLength(18, MinimumLength = 18, ErrorMessage = "身份证错误")]
[Required(ErrorMessage = "身份证不可为空")]
public string IdNo { get; set; }
}

View File

@@ -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; }
}

View File

@@ -0,0 +1,83 @@
using System.ComponentModel.DataAnnotations;
using Dlhis.Visitor.Appointment.Dto;
namespace Dlhis.Visitor.Appointment.Request;
public class AppointmentReceiveRequest : IValidatableObject
{
/// <summary>
/// 流水号
/// </summary>
[Required(ErrorMessage = "流水号必填")]
public string FlowId { get; set; }
/// <summary>
/// 标题
/// </summary>
[Required(ErrorMessage = "标题必填")]
public string Title { get; set; }
/// <summary>
/// 对接人工号
/// </summary>
[Required(ErrorMessage = "对接人工号必填")]
public string Code { get; set; }
/// <summary>
/// 对接人姓名
/// </summary>
[Required(ErrorMessage = "对接人姓名必填")]
public string Name { get; set; }
/// <summary>
/// 申请时间
/// </summary>
[Required(ErrorMessage = "申请时间必填")]
public DateTime ApplyTime { get; set; }
/// <summary>
/// 预约区域
/// </summary>
[Required(ErrorMessage = "申请预约区域必填")]
public string ApplyArea { get; set; }
/// <summary>
/// 来源公司
/// </summary>
[Required(ErrorMessage = "来源公司")]
public string Company { get; set; }
/// <summary>
/// 来访时间
/// </summary>
public DateTime Start { get; set; }
/// <summary>
/// 离开时间
/// </summary>
public DateTime End { get; set; }
/// <summary>
/// 描述
/// </summary>
public string Description { get; set; }
/// <summary>
/// 厂区
/// </summary>
public string Factory { get; set; }
/// <summary>
/// 明细
/// </summary>
[MinLength(1, ErrorMessage = "明细必填")]
public List<AppointmentReceiveItemDto> Items { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (Start >= End)
{
yield return new ValidationResult("来访时间不能大于等于离开时间", new[] { nameof(Start), nameof(End) });
}
}
}

View File

@@ -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; }
/// <summary>
///
/// </summary>
[EnumDataType(typeof(AppointmentAreaEnumType))]
public AppointmentAreaEnumType Type { get; set; }
public string CustomCode { get; set; }
}
}

View File

@@ -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; }
/// <summary>
/// 流水号
/// </summary>
public string FlowId { get; set; }
/// <summary>
/// 访客名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 手机号
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 身份证
/// </summary>
public string IdNo { get; set; }
/// <summary>
/// 预计到达
/// </summary>
public DateTime Start { get; set; }
/// <summary>
/// 预计离开
/// </summary>
public DateTime End { get; set; }
/// <summary>
/// 状态
/// </summary>
public AppointmentDetailEnumType Status { get; set; }
/// <summary>
/// 状态
/// </summary>
public string StatusDesc => Status.GetDescription();
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}

View File

@@ -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; }
}

View File

@@ -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; }
/// <summary>
/// 区域类型
/// </summary>
public AppointmentAreaEnumType Type { get; set; }
/// <summary>
/// 区域类型
/// </summary>
public string TypeDesc => Type.GetDescription();
/// <summary>
/// 自定义编码
/// </summary>
public string CustomCode { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}

View File

@@ -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);
/// <summary>
/// 预约分页
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
Task<Pagination<AppointmentPageResponse>> GetPageAsync(AppointmentPageRequest request);
/// <summary>
/// 查看明细
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task<List<AppointmentDetailResponse>> GetAppointmentDetailsByIdAsync(long id);
/// <summary>
/// 确认到达
/// </summary>
/// <returns></returns>
Task ConfirmAsync(AppointmentConfirmRequest request);
/// <summary>
/// 根据身份证获取最新访客预约
/// </summary>
/// <param name="idNo"></param>
/// <returns></returns>
Task<AppointmentDetailResponse> GetTodayByIdNoAsync(string idNo);
Task<Pagination<AppointmentDetailResponse>> GetRecordPageByIdNoAsync([FromQuery] AppointmentIdNoPageRequest request);
}

View File

@@ -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<Pagination<ApponintmentAreaPageResponse>> GetPageAsync(PageDto request);
Task SaveAsync(AppointmentAreaSaveRequest request);
Task DeleteAsync(long id);
Task AssignAsync(AppointmentAreaAssignRequest request);
}

View File

@@ -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<VisitorAppointmentEntity>().Where(x => x.FlowId == request.FlowId).AnyAsync();
exists.ThrowIfTrue("已经存在申请");
var area = await _dbContext.Queryable<AppointmentAreaEntity>()
.Where(x => x.Name == request.ApplyArea)
.Where(x => x.TenantId == request.Factory)
.FirstAsync();
area.ThrowIfNull("预约区域不存在");
var where = LinqExpressionExtensions.False<VisitorAppointmentDetailEntity>();
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<VisitorAppointmentDetailEntity>()
.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<GainfoEntity>().Where(x => x.IdNo == item.IdNo).AnyAsync();
if (isExternal)
{
var gainfoExternal = await _dbContext.Queryable<GainfoExternalEntity>().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<Pagination<AppointmentPageResponse>> GetPageAsync(AppointmentPageRequest request)
{
return await _dbContext.Queryable<VisitorAppointmentEntity>()
.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<AppointmentPageResponse>()
.ToPageListAsync(request);
}
public async Task<List<AppointmentDetailResponse>> GetAppointmentDetailsByIdAsync(long id)
{
return await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
.Where(x => x.AppointmentId == id)
.Select<AppointmentDetailResponse>()
.ToListAsync();
}
public async Task ConfirmAsync(AppointmentConfirmRequest request)
{
var detail = await _dbContext.Queryable<VisitorAppointmentDetailEntity>().Where(x => x.Id == request.Id).SingleAsync();
detail.ThrowIfNull("预约信息不存在");
//todo生成下发任务
var mst = await _dbContext.Queryable<VisitorAppointmentEntity>().Where(x => x.Id == detail.AppointmentId).FirstAsync();
var deviceGroup = await _dbContext.Queryable<AppointmentAreaAssignmentEntity>()
.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<GainfoExternalEntity>().Where(x => x.IdNo == detail.IdNo).Select(x => x.No).FirstAsync()
: await _dbContext.Queryable<GainfoEntity>().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<AppointmentDetailResponse> GetTodayByIdNoAsync(string idNo)
{
var detail = await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
.Where(x => x.IdNo == idNo)
.Where(x => SqlFunc.DateIsSame(x.Start, DateTime.Today, DateType.Day))
.OrderBy(x => x.Start)
.Select<AppointmentDetailResponse>()
.FirstAsync();
return detail;
}
public async Task<Pagination<AppointmentDetailResponse>> GetRecordPageByIdNoAsync([FromQuery] AppointmentIdNoPageRequest request)
{
var page = await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
.Where(x => x.IdNo == request.IdNo)
.OrderBy(x => x.Start)
.Select<AppointmentDetailResponse>()
.ToPageListAsync(request);
return page;
}
}

View File

@@ -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<Pagination<ApponintmentAreaPageResponse>> GetPageAsync(PageDto request)
{
return await _dbContext.Queryable<AppointmentAreaEntity>()
.Select<ApponintmentAreaPageResponse>()
.ToPageListAsync(request);
}
public async Task SaveAsync(AppointmentAreaSaveRequest request)
{
await CheckCustomCodeDuplicateAsync(request);
if (!request.Id.HasValue)
{
var entity = request.Adapt<AppointmentAreaEntity>();
entity.Type = request.Type;
entity.CustomCode = request.CustomCode;
await _dbContext.InsertAsync(entity);
}
else
{
var entity = await _dbContext.Queryable<AppointmentAreaEntity>().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<AppointmentAreaEntity>().Where(x => x.Id == id).SingleAsync();
await _dbContext.DeleteAsync(entity);
}
public async Task AssignAsync(AppointmentAreaAssignRequest request)
{
await _dbContext.Client.Deleteable<AppointmentAreaAssignmentEntity>()
.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 ***************************************************************
/// <summary>
/// 检查编码重复
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
private async Task CheckCustomCodeDuplicateAsync(AppointmentAreaSaveRequest request)
{
var exists = await _dbContext.Queryable<AppointmentAreaEntity>()
.Where(x => x.CustomCode == request.CustomCode)
.WhereIF(request.Id.HasValue, x => x.Id == request.Id)
.AnyAsync();
exists.ThrowIfTrue("重复区域编码,请检查");
}
}

View File

@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>disable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<Folder Include="Appointment\Response\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Kurisu.AspNetCore" Version="0.8.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Dlhis.Basic.Api\Dlhis.Basic.Api.csproj" />
<ProjectReference Include="..\Dlhis.Entity\Dlhis.Entity.csproj" />
</ItemGroup>
</Project>

View File

@@ -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<IConfiguration>();
return new List<ConnectionConfig>
{
new()
{
ConfigId = "face",
ConnectionString = configuration.GetSection("SqlSugarOptions:FaceConnectionString").Value,
DbType = DbType.MySqlConnector,
InitKeyType = InitKeyType.Attribute,
IsAutoCloseConnection = true,
MoreSettings = new ConnMoreSettings
{
DisableNvarchar = true,
}
}
};
});
}
}

View File

@@ -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<Startup>(args);
}
}
public class Startup : DefaultStartup
{
public Startup(IConfiguration configuration) : base(configuration)
{
IdentityModelEventSource.ShowPII = true;
}
}

View File

@@ -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"
}
}
}
}

View File

@@ -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
}
}

View File

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