Merge branch 'development'
This commit is contained in:
@@ -29,6 +29,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.Canteen", "Src\Dlhis.
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.Sys.Api", "Src\Dlhis.Sys.Api\Dlhis.Sys.Api.csproj", "{85A345C7-913E-4C1B-BE1C-600DE408A02F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.Basic.Api", "Src\Dlhis.Basic.Api\Dlhis.Basic.Api.csproj", "{1F337648-8A22-4601-A842-0F634FBA2825}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -71,6 +73,10 @@ Global
|
||||
{85A345C7-913E-4C1B-BE1C-600DE408A02F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{85A345C7-913E-4C1B-BE1C-600DE408A02F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{85A345C7-913E-4C1B-BE1C-600DE408A02F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1F337648-8A22-4601-A842-0F634FBA2825}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1F337648-8A22-4601-A842-0F634FBA2825}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1F337648-8A22-4601-A842-0F634FBA2825}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1F337648-8A22-4601-A842-0F634FBA2825}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -84,6 +90,7 @@ Global
|
||||
{925048C9-5940-4B51-8480-4DC908C754A1} = {57074FD8-1A2F-40C7-8476-001778A3F65D}
|
||||
{8317C526-3523-4195-9B19-2F17CFD71927} = {3D8A98C1-83C9-4375-AEAB-4F72AFAF365B}
|
||||
{85A345C7-913E-4C1B-BE1C-600DE408A02F} = {57074FD8-1A2F-40C7-8476-001778A3F65D}
|
||||
{1F337648-8A22-4601-A842-0F634FBA2825} = {4EBCE46B-CE3A-4A47-9432-82A1854CA58A}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {7439494A-E2FD-4FEA-8ABF-74AE57A4A5A0}
|
||||
13
Src/Dlhis.Basic.Api/Dlhis.Basic.Api.csproj
Normal file
13
Src/Dlhis.Basic.Api/Dlhis.Basic.Api.csproj
Normal file
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Kurisu.RemoteCall" Version="0.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
12
Src/Dlhis.Basic.Api/IDevicePermissionApi.cs
Normal file
12
Src/Dlhis.Basic.Api/IDevicePermissionApi.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Kurisu.Core.Result;
|
||||
using Kurisu.RemoteCall.Attributes;
|
||||
|
||||
namespace Dlhis.Basic.Api;
|
||||
|
||||
[EnableRemoteClient(Name = "basic-service", BaseUrl = "${InternalRequest:BasicRequestUrl}")]
|
||||
public interface IDevicePermissionApi
|
||||
{
|
||||
[Auth]
|
||||
[Get("/api/devicepermissions/canteen/uniqueNos")]
|
||||
Task<DefaultApiResult<List<string>>> GetCanteenDeviceUniqueNosByUserNoAsync(string userNo);
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using Dlhis.Basic.BusinessPlace.Response;
|
||||
using Dlhis.Basic.BusinessPlace.Services;
|
||||
using Dlhis.Basic.BusinessShift.Services;
|
||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -58,12 +59,24 @@ public class BusinessPlacesController : ControllerBase
|
||||
await _businessPlaceService.SaveAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 营业点保存餐次
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("shift/save")]
|
||||
public async Task SaveShiftAsync(BusinessPlaceSaveShiftRequest request)
|
||||
{
|
||||
await _businessPlaceService.SaveShiftAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据手工号获取餐别
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("shifts")]
|
||||
[IgnoreTenant]
|
||||
public async Task<BusinessPlaceWithShiftResponse> GetShiftsByPlaceCustomCodeHttpPostAsync(BusinessPlaceGetShiftsRequest request)
|
||||
{
|
||||
return await _businessPlaceShiftService.GetShiftsByPlaceCustomCodeAsync(request.CustomCode);
|
||||
@@ -75,8 +88,20 @@ public class BusinessPlacesController : ControllerBase
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("shifts")]
|
||||
[IgnoreTenant]
|
||||
public async Task<BusinessPlaceWithShiftResponse> GetShiftsByPlaceCustomCodeHttpGetAsync([FromQuery] BusinessPlaceGetShiftsRequest request)
|
||||
{
|
||||
return await _businessPlaceShiftService.GetShiftsByPlaceCustomCodeAsync(request.CustomCode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据营业点获取下面的设备
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("devicenos")]
|
||||
public async Task<Pagination<DeviceCodeNameDetail>> GetDevicesByCode([FromQuery]BusinessPlaceGetByCodeRequest request)
|
||||
{
|
||||
return await _businessPlaceShiftService.GetDevicesByCode(request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dlhis.Basic.BusinessPlace.Request
|
||||
{
|
||||
public class BusinessPlaceGetByCodeRequest : PageDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 营业点号
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "营业点号不能为空")]
|
||||
public string Code { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Dlhis.Basic.BusinessPlace.Request;
|
||||
|
||||
public class BusinessPlaceSaveShiftRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 营业点id
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 餐次code
|
||||
/// </summary>
|
||||
public Guid ShiftCode { get; set; }
|
||||
}
|
||||
@@ -35,9 +35,21 @@ public class BusinessPlaceResponse
|
||||
public CanteenBusinessPlaceSourceEnumType Source { get; set; }
|
||||
public string SourceDesc => Source.GetDescription();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 分类,超市/餐厅/食堂
|
||||
/// </summary>
|
||||
public CanteenBusinessPlaceCatalogEnumType Catalog { get; set; }
|
||||
public string CatalogDesc => Catalog.GetDescription();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 餐次code
|
||||
/// </summary>
|
||||
public Guid? ShiftCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 餐次名称
|
||||
/// </summary>
|
||||
public string ShiftName { get; set; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Dlhis.Basic.BusinessPlace.Response
|
||||
{
|
||||
public class DeviceCodeNameDetail
|
||||
{
|
||||
public string UniqueNo { get; set; }
|
||||
public string UniqueName { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,16 @@
|
||||
using Dlhis.Basic.BusinessPlace.Request;
|
||||
using Dlhis.Basic.BusinessPlace.Response;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Kurisu.SqlSugar.Attributes;
|
||||
|
||||
namespace Dlhis.Basic.BusinessPlace.Services;
|
||||
|
||||
public interface IBusinessPlaceService : IScopeDependency
|
||||
{
|
||||
/// <summary>
|
||||
/// 营业点分页
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
Task<Pagination<BusinessPlaceResponse>> GetPageAsync(BusinessPlacePageRequest request);
|
||||
|
||||
/// <summary>
|
||||
@@ -15,6 +19,17 @@ public interface IBusinessPlaceService : IScopeDependency
|
||||
/// <returns></returns>
|
||||
Task<List<BusinessPlaceResponse>> GetOpenedListAsync();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 保存营业点
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
Task SaveAsync(BusinessPlaceSaveRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// 营业点保存餐次
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
Task SaveShiftAsync(BusinessPlaceSaveShiftRequest request);
|
||||
}
|
||||
|
||||
@@ -22,46 +22,83 @@ public class BusinessPlaceService : IBusinessPlaceService
|
||||
|
||||
public async Task<Pagination<BusinessPlaceResponse>> GetPageAsync(BusinessPlacePageRequest request)
|
||||
{
|
||||
var page = await _dbContext.Queryable<CanteenBusinessPlaceEntity>()
|
||||
.WhereIF(request.Search.IsPresent(), x => x.CustomCode.Contains(request.Search))
|
||||
var page = await _dbContext.Queryable<BusinessPlaceEntity>()
|
||||
.LeftJoin<BusinessPlaceShiftRelationshipEntity>((x, ps) => x.Code == ps.PlaceCode)
|
||||
.LeftJoin<BusinessShiftEntity>((x, ps, s) => s.Code == ps.ShiftCode)
|
||||
.WhereIF(request.Search.IsPresent(), x => x.CustomCode.Contains(request.Search)
|
||||
|| x.Code.ToString().Contains(request.Search) || x.Name.Contains(request.Search))
|
||||
.WhereIF(request.Catalog.HasValue, x => x.Catalog == request.Catalog)
|
||||
.WhereIF(request.Status.HasValue, x => x.Status == request.Status)
|
||||
.WhereIF(request.Source.HasValue, x => x.Source == request.Source)
|
||||
.Select<BusinessPlaceResponse>()
|
||||
.Select((x, ps, s) => new BusinessPlaceResponse
|
||||
{
|
||||
Id = x.Id,
|
||||
Code = x.Code,
|
||||
Status = x.Status,
|
||||
Name = x.Name,
|
||||
Catalog = x.Catalog,
|
||||
CustomCode = x.CustomCode,
|
||||
Source = x.Source,
|
||||
|
||||
ShiftCode = s.Code,
|
||||
ShiftName = s.Name
|
||||
})
|
||||
.ToPageListAsync(request);
|
||||
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<BusinessPlaceResponse>> GetOpenedListAsync()
|
||||
{
|
||||
return await _dbContext.Queryable<CanteenBusinessPlaceEntity>()
|
||||
return await _dbContext.Queryable<BusinessPlaceEntity>()
|
||||
.Where(x => x.Status == CanteenBusinessPlaceStatusEnumType.Opened)
|
||||
.Select<BusinessPlaceResponse>()
|
||||
.ToListAsync();
|
||||
.Select<BusinessPlaceResponse>()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task SaveAsync(BusinessPlaceSaveRequest request)
|
||||
{
|
||||
await CheckExistsCustomCodeAsync(request);
|
||||
|
||||
if (!request.Id.HasValue)
|
||||
{
|
||||
var entity = request.Adapt<CanteenBusinessPlaceEntity>();
|
||||
var entity = request.Adapt<BusinessPlaceEntity>();
|
||||
entity.Code = Guid.NewGuid();
|
||||
await _dbContext.InsertAsync(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
var entity = await _dbContext.Queryable<CanteenBusinessPlaceEntity>().FirstAsync(x => x.Id == request.Id);
|
||||
var entity = await _dbContext.Queryable<BusinessPlaceEntity>().FirstAsync(x => x.Id == request.Id);
|
||||
request.Adapt(entity);
|
||||
|
||||
await _dbContext.UpdateAsync(entity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task SaveShiftAsync(BusinessPlaceSaveShiftRequest request)
|
||||
{
|
||||
var place = await _dbContext.Queryable<BusinessPlaceEntity>().Where(x => x.Id == request.Id).FirstAsync();
|
||||
place.ThrowIfNull("营业点不存在");
|
||||
|
||||
var relationship = await _dbContext.Queryable<BusinessPlaceShiftRelationshipEntity>().Where(x => x.PlaceCode == place.Code).FirstAsync();
|
||||
if (relationship == null)
|
||||
{
|
||||
await _dbContext.InsertAsync(new BusinessPlaceShiftRelationshipEntity
|
||||
{
|
||||
PlaceCode = place.Code,
|
||||
ShiftCode = request.ShiftCode,
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
relationship.ShiftCode = request.ShiftCode;
|
||||
await _dbContext.UpdateAsync(relationship);
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************************** help methods ***************************************************//
|
||||
|
||||
/// <summary>
|
||||
@@ -71,7 +108,7 @@ public class BusinessPlaceService : IBusinessPlaceService
|
||||
/// <returns></returns>
|
||||
private async Task CheckExistsCustomCodeAsync(BusinessPlaceSaveRequest request)
|
||||
{
|
||||
var existsSameCustomCode = await _dbContext.Queryable<CanteenBusinessPlaceEntity>()
|
||||
var existsSameCustomCode = await _dbContext.Queryable<BusinessPlaceEntity>()
|
||||
.Where(x => x.CustomCode == request.CustomCode)
|
||||
.WhereIF(request.Id.HasValue, x => x.Id != request.Id)
|
||||
.AnyAsync();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Dlhis.Basic.BusinessShift.Request;
|
||||
using Dlhis.Basic.BusinessShift.Response;
|
||||
using Dlhis.Basic.BusinessShift.Services;
|
||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -33,14 +34,36 @@ public class BusinessShiftsController : ControllerBase
|
||||
return await _businessPlaceShiftService.GetPageAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 餐次列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("list")]
|
||||
public async Task<List<BusinessPlaceShiftResponse>> GetListAsync()
|
||||
{
|
||||
return await _businessPlaceShiftService.GetListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 餐次保存
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("save")]
|
||||
public async Task SaveAsync(BusinessPlaceShiftSaveRequest request)
|
||||
public async Task<Guid> SaveAsync(BusinessPlaceShiftSaveRequest request)
|
||||
{
|
||||
await _businessPlaceShiftService.SaveAsync(request);
|
||||
return await _businessPlaceShiftService.SaveAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存餐次段
|
||||
/// </summary>
|
||||
/// <param name="requests"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("meal/save")]
|
||||
[Transactional]
|
||||
public async Task SaveMealShiftsAsync(List<BusinessPlaceShiftSaveMealShiftRequest> requests)
|
||||
{
|
||||
await _businessPlaceShiftService.SaveMealShiftsAsync(requests);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@ namespace Dlhis.Basic.BusinessShift.Request;
|
||||
|
||||
public class BusinessPlaceShiftPageRequest : PageDto
|
||||
{
|
||||
public Guid? BusinessPlaceCode { get; set; }
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Kurisu.Core.CustomClass;
|
||||
|
||||
namespace Dlhis.Basic.BusinessShift.Request;
|
||||
|
||||
public class BusinessPlaceShiftSaveMealShiftRequest : IValidatableObject
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 餐次Code
|
||||
/// </summary>
|
||||
public Guid ShiftCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// mealshift
|
||||
/// </summary>
|
||||
public string ShiftType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 序号
|
||||
/// </summary>
|
||||
public int Sequence { get; set; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// 时间段
|
||||
/// </summary>
|
||||
public TimePeriod TimePeriod { get; set; }
|
||||
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (TimePeriod.Start == TimePeriod.End)
|
||||
{
|
||||
yield return new ValidationResult("时间段设置区间有误,开始时段不能等于结束时段.", new[] { nameof(TimePeriod) });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,20 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Kurisu.Core.CustomClass;
|
||||
|
||||
namespace Dlhis.Basic.BusinessShift.Request;
|
||||
|
||||
public class BusinessPlaceShiftSaveRequest : IValidatableObject
|
||||
public class BusinessPlaceShiftSaveRequest
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 营业点代号
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "营业点不能为空")]
|
||||
public Guid BusinessPlaceCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义代号 mealshift
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "餐次编号不能为空")]
|
||||
[Required(ErrorMessage = "餐次手工号不能为空")]
|
||||
public string CustomCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 序号
|
||||
/// 餐次名称
|
||||
/// </summary>
|
||||
public int Sequence { get; set; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// 时间段
|
||||
/// </summary>
|
||||
public TimePeriod TimePeriod { get; set; }
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (TimePeriod.Start == TimePeriod.End)
|
||||
{
|
||||
yield return new ValidationResult("时间段设置区间有误,开始时段不能等于结束时段.", new[] { nameof(TimePeriod) });
|
||||
}
|
||||
}
|
||||
[Required(ErrorMessage = "餐次名称")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
@@ -4,21 +4,6 @@ public class BusinessPlaceShiftResponse
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 营业点代号
|
||||
/// </summary>
|
||||
public Guid BusinessPlaceCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 营业点手工号
|
||||
/// </summary>
|
||||
public string BusinessPlaceCustomCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 营业点
|
||||
/// </summary>
|
||||
public string BusinessPlace { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 代号
|
||||
/// </summary>
|
||||
@@ -35,12 +20,7 @@ public class BusinessPlaceShiftResponse
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 经营开始时间
|
||||
/// 就餐时间段
|
||||
/// </summary>
|
||||
public TimeOnly Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 经营结束时间
|
||||
/// </summary>
|
||||
public TimeOnly End { get; set; }
|
||||
public List<MealShiftResponse> MealShifts { get; set; }
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
public class BusinessPlaceShiftTinyResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// 自定义代号
|
||||
/// 无用字段,暂时不删除 //todo
|
||||
/// </summary>
|
||||
public string CustomCode { get; set; }
|
||||
|
||||
|
||||
17
Src/Dlhis.Basic/BusinessShift/Response/MealShiftResponse.cs
Normal file
17
Src/Dlhis.Basic/BusinessShift/Response/MealShiftResponse.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace Dlhis.Basic.BusinessShift.Response
|
||||
{
|
||||
public class MealShiftResponse
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public Guid ShiftCode { get; set; }
|
||||
|
||||
public string ShiftType { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public TimeOnly Start { get; set; }
|
||||
|
||||
public TimeOnly End { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Dlhis.Basic.BusinessPlace.Response;
|
||||
using Dlhis.Basic.BusinessPlace.Request;
|
||||
using Dlhis.Basic.BusinessPlace.Response;
|
||||
using Dlhis.Basic.BusinessShift.Request;
|
||||
using Dlhis.Basic.BusinessShift.Response;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
@@ -9,7 +10,13 @@ public interface IBusinessPlaceShiftService : IScopeDependency
|
||||
{
|
||||
Task<Pagination<BusinessPlaceShiftResponse>> GetPageAsync(BusinessPlaceShiftPageRequest request);
|
||||
|
||||
Task SaveAsync(BusinessPlaceShiftSaveRequest request);
|
||||
Task<List<BusinessPlaceShiftResponse>> GetListAsync();
|
||||
|
||||
Task<Guid> SaveAsync(BusinessPlaceShiftSaveRequest request);
|
||||
|
||||
Task SaveMealShiftsAsync(List<BusinessPlaceShiftSaveMealShiftRequest> requests);
|
||||
|
||||
Task<BusinessPlaceWithShiftResponse> GetShiftsByPlaceCustomCodeAsync(string placeCustomCode);
|
||||
|
||||
Task<Pagination<DeviceCodeNameDetail>> GetDevicesByCode(BusinessPlaceGetByCodeRequest request);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
using Dlhis.Basic.BusinessPlace.Response;
|
||||
using Dlhis.Basic.BusinessPlace.Request;
|
||||
using Dlhis.Basic.BusinessPlace.Response;
|
||||
using Dlhis.Basic.BusinessShift.Request;
|
||||
using Dlhis.Basic.BusinessShift.Response;
|
||||
using Dlhis.Entity.Basic.Entity;
|
||||
using Dlhis.Entity.Device.Entities;
|
||||
using Dlhis.Sys.Api;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
using Kurisu.Core.CustomClass;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Kurisu.Core.Result;
|
||||
using Kurisu.SqlSugar.Attributes;
|
||||
using Kurisu.SqlSugar.Extensions;
|
||||
using Kurisu.SqlSugar.Services;
|
||||
using Mapster;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Dlhis.Basic.BusinessShift.Services.Implements;
|
||||
|
||||
@@ -27,58 +29,109 @@ public class BusinessPlaceShiftService : IBusinessPlaceShiftService
|
||||
|
||||
public async Task<Pagination<BusinessPlaceShiftResponse>> GetPageAsync(BusinessPlaceShiftPageRequest request)
|
||||
{
|
||||
var page = await _dbContext.Queryable<CanteenBusinessShiftEntity>()
|
||||
.LeftJoin<CanteenBusinessPlaceEntity>((shift, place) => shift.BusinessPlaceCode == place.Code)
|
||||
.LeftJoin<BasicTypeEntity>((shift, place, type) => shift.Code.ToString() == type.Code)
|
||||
.WhereIF(request.Search.IsPresent(), (shift, place) => shift.CustomCode.Contains(request.Search))
|
||||
.WhereIF(request.BusinessPlaceCode.HasValue, (shift, place) => shift.BusinessPlaceCode == request.BusinessPlaceCode)
|
||||
.Select((shift, place, type) => new BusinessPlaceShiftResponse
|
||||
{
|
||||
Id = shift.Id,
|
||||
BusinessPlaceCode = place.Code,
|
||||
BusinessPlaceCustomCode = place.CustomCode,
|
||||
BusinessPlace = place.Name,
|
||||
Code = shift.Code,
|
||||
CustomCode = shift.CustomCode,
|
||||
Name = type.Display,
|
||||
Start = shift.Start,
|
||||
End = shift.End
|
||||
})
|
||||
var page = await _dbContext.Queryable<BusinessShiftEntity>()
|
||||
.WhereIF(request.Search.IsPresent(), (shift) => shift.CustomCode.Contains(request.Search) || shift.Name.Contains(request.Search))
|
||||
.Select<BusinessPlaceShiftResponse>()
|
||||
.ToPageListAsync(request);
|
||||
|
||||
var shiftCodes = page.Data.Select(x => x.Code).ToList();
|
||||
|
||||
//下级就餐时间段
|
||||
var mealShifts = await _dbContext.Queryable<BusinessShiftMealRelationshipEntity>()
|
||||
.LeftJoin<BasicTypeEntity>((x, bt) => x.ShiftType == bt.Code)
|
||||
.Where(x => shiftCodes.Contains(x.ShiftCode))
|
||||
.Select((x, bt) => new MealShiftResponse
|
||||
{
|
||||
Id = x.Id,
|
||||
ShiftCode = x.ShiftCode,
|
||||
ShiftType = bt.Code,
|
||||
Name = bt.Display,
|
||||
Start = x.Start,
|
||||
End = x.End,
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
page.Data.ForEach(x =>
|
||||
{
|
||||
x.MealShifts = mealShifts.Where(item => item.ShiftCode == x.Code).ToList();
|
||||
});
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
public async Task SaveAsync(BusinessPlaceShiftSaveRequest request)
|
||||
public async Task<List<BusinessPlaceShiftResponse>> GetListAsync()
|
||||
{
|
||||
await CheckExistsCustomCodeAsync(request);
|
||||
await DuplicateTimePeriodAsync(request);
|
||||
await CheckPlaceExistsAsync(request.BusinessPlaceCode);
|
||||
var result = await _dbContext.Queryable<BusinessShiftEntity>()
|
||||
.Select<BusinessPlaceShiftResponse>().ToListAsync();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Guid> SaveAsync(BusinessPlaceShiftSaveRequest request)
|
||||
{
|
||||
await CheckExistsAsync(request);
|
||||
|
||||
Guid code = Guid.Empty;
|
||||
if (!request.Id.HasValue)
|
||||
{
|
||||
var entity = request.Adapt<CanteenBusinessShiftEntity>();
|
||||
var entity = request.Adapt<BusinessShiftEntity>();
|
||||
|
||||
entity.Code = Guid.NewGuid();
|
||||
entity.Start = request.TimePeriod.Start.Value;
|
||||
entity.End = request.TimePeriod.End.Value;
|
||||
|
||||
await _dbContext.InsertAsync(entity);
|
||||
|
||||
code = entity.Code;
|
||||
}
|
||||
else
|
||||
{
|
||||
var entity = await _dbContext.Queryable<CanteenBusinessShiftEntity>().FirstAsync(x => x.Id == request.Id);
|
||||
entity.Adapt(request);
|
||||
var entity = await _dbContext.Queryable<BusinessShiftEntity>().FirstAsync(x => x.Id == request.Id);
|
||||
entity.ThrowIfNull("餐次不存在");
|
||||
|
||||
request.Adapt(entity);
|
||||
await _dbContext.UpdateAsync(entity);
|
||||
|
||||
code = entity.Code;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
public async Task SaveMealShiftsAsync(List<BusinessPlaceShiftSaveMealShiftRequest> requests)
|
||||
{
|
||||
var mealShifts = await GetMealShiftAsync();
|
||||
|
||||
foreach (var request in requests)
|
||||
{
|
||||
var shift = await CheckExistsShiftAsync(request.ShiftCode);
|
||||
await CheckExistsMealShiftAsync(request);
|
||||
await DuplicateTimePeriodAsync(request);
|
||||
mealShifts.Contains(request.ShiftType).ThrowIfFalse($"{request.ShiftType}不存在");
|
||||
|
||||
if (!request.Id.HasValue)
|
||||
{
|
||||
var entity = request.Adapt<BusinessShiftMealRelationshipEntity>();
|
||||
|
||||
entity.ShiftCode = shift.Code;
|
||||
entity.ShiftCustomCode = shift.CustomCode;
|
||||
entity.Start = request.TimePeriod.Start.Value;
|
||||
entity.End = request.TimePeriod.End.Value;
|
||||
|
||||
await _dbContext.InsertAsync(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
var entity = await _dbContext.Queryable<BusinessShiftMealRelationshipEntity>().FirstAsync(x => x.Id == request.Id);
|
||||
entity.ThrowIfNull("餐次段不存在");
|
||||
|
||||
request.Adapt(entity);
|
||||
await _dbContext.UpdateAsync(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreTenant]
|
||||
|
||||
public async Task<BusinessPlaceWithShiftResponse> GetShiftsByPlaceCustomCodeAsync(string placeCustomCode)
|
||||
{
|
||||
var place = await _dbContext.Queryable<CanteenBusinessPlaceEntity>().Where(x => x.CustomCode == placeCustomCode).FirstAsync();
|
||||
var place = await _dbContext.Queryable<BusinessPlaceEntity>().Where(x => x.CustomCode == placeCustomCode).FirstAsync();
|
||||
if (place == null)
|
||||
{
|
||||
return new BusinessPlaceWithShiftResponse()
|
||||
@@ -87,29 +140,45 @@ public class BusinessPlaceShiftService : IBusinessPlaceShiftService
|
||||
};
|
||||
}
|
||||
|
||||
var shifts = await _dbContext.Queryable<CanteenBusinessShiftEntity>()
|
||||
.Where(x => x.BusinessPlaceCode == place.Code)
|
||||
.OrderBy(x => x.Sequence) //排序
|
||||
.ToListAsync();
|
||||
|
||||
var tenantResult = await _tenantApi.GetTenantByCodeAsync(place.TenantId);
|
||||
(tenantResult.Code == ApiStateCode.Success).ThrowIfFalse(tenantResult.Msg);
|
||||
var tenantInfo = tenantResult.Data;
|
||||
|
||||
var relationship = await _dbContext.Queryable<BusinessPlaceShiftRelationshipEntity>().Where(x => x.PlaceCode == place.Code).FirstAsync();
|
||||
if (relationship == null)
|
||||
{
|
||||
return new BusinessPlaceWithShiftResponse()
|
||||
{
|
||||
CustomCode = placeCustomCode,
|
||||
Name = place.Name,
|
||||
TenantCode = tenantInfo.Code,
|
||||
TenantName = tenantInfo.Name,
|
||||
Shifts = new List<BusinessPlaceShiftTinyResponse>()
|
||||
};
|
||||
}
|
||||
|
||||
var shifts = await _dbContext.Queryable<BusinessShiftMealRelationshipEntity>()
|
||||
.Where(x => x.ShiftCode == relationship.ShiftCode)
|
||||
.OrderBy(x => x.Sequence) //排序
|
||||
.ToListAsync();
|
||||
|
||||
var list = new List<BusinessPlaceShiftTinyResponse>();
|
||||
foreach (CanteenBusinessShiftEntity shiftinfo in shifts)
|
||||
|
||||
foreach (BusinessShiftMealRelationshipEntity shiftinfo in shifts)
|
||||
{
|
||||
var name = _dbContext.Queryable<BasicTypeEntity>()
|
||||
.Where(x => x.Code == shiftinfo.CustomCode.ToString())
|
||||
.Where(x => x.Code == shiftinfo.ShiftType.ToString())
|
||||
.Select(x => x.Display)
|
||||
.First();
|
||||
|
||||
var shift = new BusinessPlaceShiftTinyResponse
|
||||
{
|
||||
CustomCode = shiftinfo.CustomCode,
|
||||
CustomCode = shiftinfo.Id.ToString(),
|
||||
Name = name,
|
||||
Start = shiftinfo.Start,
|
||||
End = shiftinfo.End
|
||||
};
|
||||
|
||||
list.Add(shift);
|
||||
}
|
||||
return new BusinessPlaceWithShiftResponse
|
||||
@@ -122,24 +191,58 @@ public class BusinessPlaceShiftService : IBusinessPlaceShiftService
|
||||
};
|
||||
}
|
||||
|
||||
//*********************************************** help methods ***************************************************//
|
||||
|
||||
|
||||
private async Task CheckPlaceExistsAsync(Guid code)
|
||||
public async Task<Pagination<DeviceCodeNameDetail>> GetDevicesByCode(BusinessPlaceGetByCodeRequest request)
|
||||
{
|
||||
var existsPlace = await _dbContext.Queryable<CanteenBusinessPlaceEntity>().AnyAsync(x => x.Code == code);
|
||||
existsPlace.ThrowIfFalse("营业点不存在,请检查.");
|
||||
var regiss = await _dbContext.Queryable<DeviceRegistryEntity>()
|
||||
.Where(x => x.BusinessPlaceCode.ToString() == request.Code)
|
||||
.ToListAsync();
|
||||
|
||||
var devices = await _dbContext.Queryable<DeviceEntity>().ToListAsync();
|
||||
|
||||
var list = new List<DeviceCodeNameDetail>();
|
||||
if (regiss.Count > 0)
|
||||
{
|
||||
foreach (var regis in regiss)
|
||||
{
|
||||
var device = devices.Where(x => x.UniqueNo == regis.DeviceUniqueNo)
|
||||
.FirstOrDefault();
|
||||
if (device != null)
|
||||
{
|
||||
var detail = new DeviceCodeNameDetail
|
||||
{
|
||||
UniqueNo = regis.DeviceUniqueNo,
|
||||
UniqueName = device.Supplier
|
||||
};
|
||||
list.Add(detail);
|
||||
}
|
||||
}
|
||||
}
|
||||
//分页
|
||||
var startIndex = (request.PageIndex - 1) * request.PageSize;
|
||||
var pagedData = list.Skip(startIndex).Take(request.PageSize).ToList();
|
||||
|
||||
var pagination = new Pagination<DeviceCodeNameDetail>
|
||||
{
|
||||
PageIndex = request.PageIndex,
|
||||
PageSize = request.PageSize,
|
||||
Total = list.Count, // 使用原始列表的总数进行分页
|
||||
Data = pagedData
|
||||
};
|
||||
|
||||
return pagination;
|
||||
}
|
||||
|
||||
//*********************************************** help methods ***************************************************//
|
||||
|
||||
/// <summary>
|
||||
/// 时间段重合检查
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
private async Task DuplicateTimePeriodAsync(BusinessPlaceShiftSaveRequest request)
|
||||
private async Task DuplicateTimePeriodAsync(BusinessPlaceShiftSaveMealShiftRequest request)
|
||||
{
|
||||
var periods = await _dbContext.Queryable<CanteenBusinessShiftEntity>()
|
||||
.Where(x => x.BusinessPlaceCode == request.BusinessPlaceCode)
|
||||
var periods = await _dbContext.Queryable<BusinessShiftMealRelationshipEntity>()
|
||||
.Where(x => x.ShiftCode == request.ShiftCode)
|
||||
.WhereIF(request.Id.HasValue, x => x.Id != request.Id)
|
||||
.Select(x => new TimePeriod
|
||||
{
|
||||
@@ -150,24 +253,47 @@ public class BusinessPlaceShiftService : IBusinessPlaceShiftService
|
||||
|
||||
foreach (var period in periods)
|
||||
{
|
||||
period.IsDuplicate(request.TimePeriod).ThrowIfTrue($"存在时间段重合[{period.Start}-{period.End}]");
|
||||
period.IsDuplicate1(request.TimePeriod).ThrowIfTrue($"存在时间段重合[{period.Start}-{period.End}]");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 检查重复手工号
|
||||
/// 检查重复
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
private async Task CheckExistsCustomCodeAsync(BusinessPlaceShiftSaveRequest request)
|
||||
private async Task CheckExistsAsync(BusinessPlaceShiftSaveRequest request)
|
||||
{
|
||||
var existsSameCustomCode = await _dbContext.Queryable<CanteenBusinessShiftEntity>()
|
||||
.Where(x => x.CustomCode == request.CustomCode)
|
||||
var existsSameCustomCode = await _dbContext.Queryable<BusinessShiftEntity>()
|
||||
.Where(x => x.CustomCode == request.CustomCode || x.Name == request.Name)
|
||||
.WhereIF(request.Id.HasValue, x => x.Id != request.Id)
|
||||
.AnyAsync();
|
||||
|
||||
existsSameCustomCode.ThrowIfTrue($"自定义手工号[{request.CustomCode}]存在重复,请检查.");
|
||||
existsSameCustomCode.ThrowIfTrue($"自定义手工号或者名称存在重复,请检查.");
|
||||
}
|
||||
|
||||
private async Task<BusinessShiftEntity> CheckExistsShiftAsync(Guid shiftCode)
|
||||
{
|
||||
var shift = await _dbContext.Queryable<BusinessShiftEntity>().Where(x => x.Code == shiftCode).FirstAsync();
|
||||
shift.ThrowIfNull("餐次不存在");
|
||||
|
||||
return shift;
|
||||
}
|
||||
|
||||
private async Task<List<string>> GetMealShiftAsync()
|
||||
{
|
||||
return await _dbContext.Queryable<BasicTypeEntity>().Where(x => x.Type == "mealshift").Select(x => x.Code).ToListAsync();
|
||||
}
|
||||
|
||||
private async Task CheckExistsMealShiftAsync(BusinessPlaceShiftSaveMealShiftRequest request)
|
||||
{
|
||||
var exists = await _dbContext.Queryable<BusinessShiftMealRelationshipEntity>()
|
||||
.Where(x => x.ShiftCode == request.ShiftCode)
|
||||
.Where(x => x.ShiftType == request.ShiftType)
|
||||
.WhereIF(request.Id.HasValue, x => x.Id != request.Id)
|
||||
.AnyAsync();
|
||||
|
||||
exists.ThrowIfTrue("重复设置!");
|
||||
}
|
||||
}
|
||||
|
||||
73
Src/Dlhis.Basic/BusinessShift/TimePeriodExtensions.cs
Normal file
73
Src/Dlhis.Basic/BusinessShift/TimePeriodExtensions.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using Kurisu.Core.CustomClass;
|
||||
|
||||
namespace Dlhis.Basic.BusinessShift;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 临时的扩展类 todo: 嵌入框架
|
||||
/// </summary>
|
||||
public static class TimePeriodExtensions
|
||||
{
|
||||
public static bool IsDuplicate1(this TimePeriod current, TimePeriod period)
|
||||
{
|
||||
return !Check();
|
||||
|
||||
bool Check()
|
||||
{
|
||||
if (current.IsCrossDay())
|
||||
{
|
||||
if (period.IsCrossDay())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return period.Start > current.End && period.End < current.Start;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (period.IsCrossDay())
|
||||
{
|
||||
return period.Start > current.End && period.End < current.Start;
|
||||
}
|
||||
else
|
||||
{
|
||||
return period.Start > current.End || period.End < current.Start;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static bool IsPresent1(this TimePeriod period, DateTime dateTime)
|
||||
{
|
||||
DateTime start;
|
||||
DateTime end;
|
||||
|
||||
if (period.IsCrossDay())
|
||||
{
|
||||
var currentStart = DateTime.Today.Add(period.Start.Value.ToTimeSpan());
|
||||
var endOfDay = DateTime.Today.AddHours(23).AddMinutes(59).AddSeconds(59);
|
||||
|
||||
if (dateTime >= currentStart && dateTime <= endOfDay)
|
||||
{
|
||||
start = DateTime.Today.Add(period.Start.Value.ToTimeSpan());
|
||||
end = DateTime.Today.AddDays(1).Add(period.End.Value.ToTimeSpan());
|
||||
}
|
||||
else
|
||||
{
|
||||
//第二天
|
||||
start = DateTime.Today.AddDays(-1).Add(period.Start.Value.ToTimeSpan());
|
||||
end = DateTime.Today.Add(period.End.Value.ToTimeSpan());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
start = DateTime.Today.Add(period.Start.Value.ToTimeSpan());
|
||||
end = DateTime.Today.Add(period.End.Value.ToTimeSpan());
|
||||
}
|
||||
|
||||
return dateTime >= start && dateTime <= end;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using Dlhis.Basic.Device.Request;
|
||||
using Dlhis.Basic.Device.Response;
|
||||
using Dlhis.Basic.Device.Services;
|
||||
using Dlhis.Entity.Device.Enums;
|
||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -22,26 +24,17 @@ public class DeviceGroupsController : ControllerBase
|
||||
_deviceGroupService = deviceGroupService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设备组分页
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("page")]
|
||||
public async Task<Pagination<DeviceGroupPageResponse>> GetPageAsync([FromQuery] DeviceGroupPageRequest request)
|
||||
{
|
||||
return await _deviceGroupService.GetPageAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取设备组树
|
||||
/// </summary>
|
||||
/// <param name="showDevices">是否显示设备</param>
|
||||
/// <param name="type">分组类型</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("tree")]
|
||||
public async Task<List<DeviceGroupTreeResponse>> GetTreeAsync(bool showDevices)
|
||||
[IgnoreTenant]
|
||||
public async Task<List<DeviceGroupTreeResponse>> GetTreeAsync(bool showDevices, DeviceTypeEnumType? type)
|
||||
{
|
||||
return await _deviceGroupService.GetTreeAsync(showDevices);
|
||||
return await _deviceGroupService.GetTreeAsync(showDevices, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -50,6 +43,7 @@ public class DeviceGroupsController : ControllerBase
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("save")]
|
||||
[IgnoreTenant]
|
||||
public async Task SaveAsync(DeviceGroupSaveRequest request)
|
||||
{
|
||||
await _deviceGroupService.SaveAsync(request);
|
||||
@@ -72,6 +66,8 @@ public class DeviceGroupsController : ControllerBase
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("assign")]
|
||||
[IgnoreTenant]
|
||||
[Transactional]
|
||||
public async Task AssignDevicesAsync(DeviceAssignRequest request)
|
||||
{
|
||||
await _deviceGroupService.AssignDevicesAsync(request);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Dlhis.Basic.Device.Request;
|
||||
using Dlhis.Basic.Device.Response;
|
||||
using Dlhis.Basic.Device.Services;
|
||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -25,6 +26,8 @@ public class DevicePermissionsController : ControllerBase
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("assign")]
|
||||
[Transactional]
|
||||
[IgnoreTenant]
|
||||
public async Task AssignAsync(DevicePermissionSaveReuqest request)
|
||||
{
|
||||
await _devicePermissionService.AssignAsync(request);
|
||||
@@ -51,4 +54,17 @@ public class DevicePermissionsController : ControllerBase
|
||||
{
|
||||
return await _devicePermissionService.GetAssigmentByCodeAsync(request);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 就餐设备唯一号权限
|
||||
/// </summary>
|
||||
/// <param name="userNo"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("canteen/uniqueNos")]
|
||||
[IgnoreTenant]
|
||||
public async Task<List<string>> GetCanteenDeviceUniqueNosByUserNoAsync(string userNo)
|
||||
{
|
||||
return await _devicePermissionService.GetCanteenDeviceUniqueNosByUserNoAsync(userNo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Dlhis.Basic.Device.Request;
|
||||
using Dlhis.Basic.Device.Response;
|
||||
using Dlhis.Basic.Device.Services;
|
||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -70,6 +71,7 @@ public class DevicesController : ControllerBase
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("save")]
|
||||
[Transactional]
|
||||
public async Task SaveAsync(DeviceSaveRequest request)
|
||||
{
|
||||
await _deviceService.SaveAsync(request);
|
||||
@@ -81,6 +83,7 @@ public class DevicesController : ControllerBase
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("resigter")]
|
||||
[IgnoreTenant]
|
||||
public async Task<string> ResigterAsync(DeviceResigterRequest request)
|
||||
{
|
||||
return await _deviceConnectService.ResigterAsync(request);
|
||||
@@ -128,6 +131,7 @@ public class DevicesController : ControllerBase
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("heartbeat")]
|
||||
[IgnoreTenant]
|
||||
public async Task HeartbeatAsync(DeviceHeartbeatRequest request)
|
||||
{
|
||||
await _deviceConnectService.HeartbeatAsync(request);
|
||||
@@ -142,6 +146,7 @@ public class DevicesController : ControllerBase
|
||||
{
|
||||
return await _deviceService.CheckExistsAsync(deviceUniqueNo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取设备
|
||||
/// </summary>
|
||||
@@ -194,12 +199,34 @@ public class DevicesController : ControllerBase
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取近期30天新增设备数
|
||||
/// 获取门禁在线/离线设备详情列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("dooroffline")]
|
||||
public async Task<Pagination<DevicePageResponse>> GetDoorOfflineAsync([FromQuery] GetDoorOfflineRequest request)
|
||||
{
|
||||
return await _deviceService.GetDoorOfflineAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取近期30天考勤新增设备数
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("recentnumbers")]
|
||||
public async Task<Dictionary<string, int>> GetRecentNumbersAsync()
|
||||
public async Task<List<RecentNumberResponse>> GetRecentNumbersAsync()
|
||||
{
|
||||
return await _deviceService.GetRecentNumbersAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量导入设备信息
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("bulkUploads")]
|
||||
public async Task BulkUploadsAsync([FromForm] BulkUploadsRequest request)
|
||||
{
|
||||
await _deviceService.BulkUploadsAsync(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
14
Src/Dlhis.Basic/Device/Dtos/UserTenantDeviceCodeDto.cs
Normal file
14
Src/Dlhis.Basic/Device/Dtos/UserTenantDeviceCodeDto.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Dlhis.Basic.Device.Dtos;
|
||||
|
||||
public class UserTenantDeviceCodeDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 租户
|
||||
/// </summary>
|
||||
public string Tenant { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备权限
|
||||
/// </summary>
|
||||
public List<Guid> Codes { get; set; }
|
||||
}
|
||||
10
Src/Dlhis.Basic/Device/Request/BulkUploadsRequest.cs
Normal file
10
Src/Dlhis.Basic/Device/Request/BulkUploadsRequest.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Dlhis.Basic.Device.Request
|
||||
{
|
||||
public class BulkUploadsRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备信息文件
|
||||
/// </summary>
|
||||
public IFormFile FormFile { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
|
||||
namespace Dlhis.Basic.Device.Request;
|
||||
|
||||
public class DeviceGroupPageRequest : PageDto
|
||||
{
|
||||
}
|
||||
@@ -10,7 +10,7 @@ public class DeviceGroupSaveRequest
|
||||
/// <summary>
|
||||
/// 上级分组
|
||||
/// </summary>
|
||||
public Guid? PCode { get; set; }
|
||||
public Guid PCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备组名称
|
||||
@@ -21,7 +21,11 @@ public class DeviceGroupSaveRequest
|
||||
/// <summary>
|
||||
/// 分类类型 DeviceTypeEnumType
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "分类不能为空")]
|
||||
[EnumDataType(typeof(DeviceTypeEnumType))]
|
||||
public DeviceTypeEnumType Type { get; set; }
|
||||
public DeviceTypeEnumType? Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Remark { get; set; }
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Dlhis.Basic.Device.Request
|
||||
{
|
||||
public class DeviceOnlineAndofflineRequest :PageDto
|
||||
public class DeviceOnlineAndofflineRequest : PageDto
|
||||
{
|
||||
public bool IsOnAndOff { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Dlhis.Entity.Sys.Enums;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
|
||||
namespace Dlhis.Basic.Device.Request;
|
||||
|
||||
public class DevicePermissionSaveReuqest
|
||||
public class DevicePermissionSaveReuqest : IValidatableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 分配类型 AssignTypeEnumType
|
||||
@@ -12,9 +13,12 @@ public class DevicePermissionSaveReuqest
|
||||
public AssignTypeEnumType AssignType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 人员档案号
|
||||
/// 分配值
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "人员档案号不能为空")]
|
||||
/// <remarks>
|
||||
/// 如果<see cref="AssignTypeEnumType"/>为用户,那么AssignValue=UserNo
|
||||
/// </remarks>
|
||||
[Required(ErrorMessage = "分配值不能为空")]
|
||||
public string AssignValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -24,7 +28,23 @@ public class DevicePermissionSaveReuqest
|
||||
public DeviceAssignmentTypeEnumType UniqueType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分配权限值不能为空
|
||||
/// 分配权限值
|
||||
/// </summary>
|
||||
public List<Guid> Codes { get; set; } = new List<Guid>();
|
||||
public List<Guid> Codes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// AssignType == AssignTypeEnumType.Department 需要传入
|
||||
/// </summary>
|
||||
public string TenantId { get; set; }
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (AssignType == AssignTypeEnumType.Department)
|
||||
{
|
||||
if (TenantId.IsEmpty())
|
||||
{
|
||||
yield return new ValidationResult("请明确具体的厂区", new[] { nameof(TenantId) });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Dlhis.Entity.Device.Enums;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
|
||||
namespace Dlhis.Basic.Device.Request;
|
||||
|
||||
public class DeviceSaveRequest
|
||||
public class DeviceSaveRequest : IValidatableObject
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
|
||||
@@ -42,7 +43,6 @@ public class DeviceSaveRequest
|
||||
/// <summary>
|
||||
/// 心跳间隔
|
||||
/// </summary>
|
||||
[Range(0, int.MaxValue)]
|
||||
public int HeartbeatInterval { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -70,4 +70,22 @@ public class DeviceSaveRequest
|
||||
/// 是否启用
|
||||
/// </summary>
|
||||
public bool Enable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否作为考勤设备
|
||||
/// </summary>
|
||||
public bool AsAttendance { get; set; }
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (Type != DeviceTypeEnumType.Door && AsAttendance)
|
||||
{
|
||||
yield return new ValidationResult($"{DeviceTypeEnumType.Door.GetDescription()}才可设置作为考勤设备", new[] { nameof(AsAttendance) });
|
||||
}
|
||||
|
||||
if (HeartbeatInterval != 0 && HeartbeatInterval < 30)
|
||||
{
|
||||
yield return new ValidationResult($"心跳间隔需要设置>=30秒", new[] { nameof(HeartbeatInterval) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
/// <summary>
|
||||
/// 营业点
|
||||
/// </summary>
|
||||
public Guid BusinessPlaceCode { get; set; }
|
||||
public Guid? BusinessPlaceCode { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
76
Src/Dlhis.Basic/Device/Request/ImportDeviceSaveRequest.cs
Normal file
76
Src/Dlhis.Basic/Device/Request/ImportDeviceSaveRequest.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using Dlhis.Entity.Device.Enums;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dlhis.Basic.Device.Request
|
||||
{
|
||||
public class ImportDeviceSaveRequest
|
||||
{
|
||||
|
||||
public long? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备唯一号
|
||||
/// </summary>
|
||||
public string UniqueNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模板code
|
||||
/// </summary>
|
||||
public Guid TemplateCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 供应商信息
|
||||
/// </summary>
|
||||
public string Supplier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备功能
|
||||
/// </summary>
|
||||
public List<DeviceFuncEnumType> Funcs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备类型 DeviceTypeEnumType
|
||||
/// </summary>
|
||||
public DeviceTypeEnumType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 心跳间隔
|
||||
/// </summary>
|
||||
public int HeartbeatInterval { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 部署点
|
||||
/// </summary>
|
||||
public string DeployPlace { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 部署坐标
|
||||
/// </summary>
|
||||
public string DeployPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 部署方向
|
||||
/// </summary>
|
||||
public string DeployDirection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 连接信息
|
||||
/// </summary>
|
||||
public string ConnectionInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用
|
||||
/// </summary>
|
||||
public bool Enable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否作为考勤设备
|
||||
/// </summary>
|
||||
public bool AsAttendance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 营业点code
|
||||
/// </summary>
|
||||
public Guid? PlaceeCode { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
namespace Dlhis.Basic.Device.Response;
|
||||
using Dlhis.Entity.Device.Enums;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
|
||||
namespace Dlhis.Basic.Device.Response;
|
||||
|
||||
public class DeviceGroupPageResponse
|
||||
{
|
||||
@@ -11,4 +14,30 @@ public class DeviceGroupPageResponse
|
||||
/// 设备组名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分组类型
|
||||
/// </summary>
|
||||
public DeviceTypeEnumType? Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否可编辑
|
||||
/// </summary>
|
||||
public bool Editable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分组类型描述
|
||||
/// </summary>
|
||||
public string TypeDesc
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!Type.HasValue)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return Type.Value.GetDescription();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
namespace Dlhis.Basic.Device.Response;
|
||||
using Dlhis.Entity.Device.Enums;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dlhis.Basic.Device.Response;
|
||||
|
||||
public class DeviceGroupTreeResponse
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 上级分组code
|
||||
/// </summary>
|
||||
@@ -17,6 +24,42 @@ public class DeviceGroupTreeResponse
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备组类型
|
||||
/// </summary>
|
||||
public DeviceTypeEnumType? Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分组类型描述
|
||||
/// </summary>
|
||||
public string TypeDesc
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!Type.HasValue)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return Type.Value.GetDescription();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Editable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否允许设置下级
|
||||
/// </summary>
|
||||
public bool AbleSetNext { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public string TenantId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 下级
|
||||
/// </summary>
|
||||
|
||||
@@ -84,4 +84,51 @@ public class DevicePageResponse
|
||||
/// 是否启用
|
||||
/// </summary>
|
||||
public bool Enable { get; set; }
|
||||
|
||||
|
||||
//*********************************************************附加信息**************************************************************/
|
||||
|
||||
/// <summary>
|
||||
/// 最后心跳时间
|
||||
/// </summary>
|
||||
public DateTime? LastHeartbeatTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否在线
|
||||
/// </summary>
|
||||
public bool IsOnline
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!LastHeartbeatTime.HasValue)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
if (HeartbeatInterval <= 0)
|
||||
return true;
|
||||
else
|
||||
return LastHeartbeatTime.Value.AddSeconds(HeartbeatInterval * 3) >= DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消费总额
|
||||
/// </summary>
|
||||
public decimal Amount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 消费人次
|
||||
/// </summary>
|
||||
public int UserCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 营业点code
|
||||
/// </summary>
|
||||
public Guid? BusinessPlaceCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 营业点名称
|
||||
/// </summary>
|
||||
public string BusinessPlaceName { get; set; }
|
||||
}
|
||||
|
||||
@@ -88,6 +88,9 @@ public class DeviceResponse
|
||||
}
|
||||
}
|
||||
|
||||
public DeviceTypeEnumType Type { get; set; }
|
||||
public string TypeDesc => Type.GetDescription();
|
||||
|
||||
/// <summary>
|
||||
/// 连接信息
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Dlhis.Basic.Device.Response;
|
||||
using Dlhis.Entity.Device.Enums;
|
||||
|
||||
namespace Dlhis.Basic.Device.Response;
|
||||
|
||||
public class DeviceUnderGroupResponse
|
||||
{
|
||||
@@ -14,6 +16,12 @@ public class DeviceUnderGroupResponse
|
||||
/// </summary>
|
||||
public string Brand { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备类型
|
||||
/// </summary>
|
||||
public DeviceTypeEnumType Type { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用
|
||||
/// </summary>
|
||||
|
||||
9
Src/Dlhis.Basic/Device/Response/GetDoorOfflineRequest.cs
Normal file
9
Src/Dlhis.Basic/Device/Response/GetDoorOfflineRequest.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
|
||||
namespace Dlhis.Basic.Device.Response
|
||||
{
|
||||
public class GetDoorOfflineRequest : PageDto
|
||||
{
|
||||
public bool IsOnAndOff { get; set; }
|
||||
}
|
||||
}
|
||||
9
Src/Dlhis.Basic/Device/Response/RecentNumberResponse.cs
Normal file
9
Src/Dlhis.Basic/Device/Response/RecentNumberResponse.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Dlhis.Basic.Device.Response
|
||||
{
|
||||
public class RecentNumberResponse
|
||||
{
|
||||
public string Date { get; set; }
|
||||
|
||||
public int Num { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
using Dlhis.Basic.Device.Request;
|
||||
using Dlhis.Basic.Device.Response;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Dlhis.Entity.Device.Enums;
|
||||
|
||||
namespace Dlhis.Basic.Device.Services;
|
||||
|
||||
public interface IDeviceGroupService : IScopeDependency
|
||||
{
|
||||
Task<Pagination<DeviceGroupPageResponse>> GetPageAsync(DeviceGroupPageRequest request);
|
||||
|
||||
Task<List<DeviceGroupTreeResponse>> GetTreeAsync(bool showDevices);
|
||||
Task<List<DeviceGroupTreeResponse>> GetTreeAsync(bool showDevices, DeviceTypeEnumType? type);
|
||||
|
||||
Task SaveAsync(DeviceGroupSaveRequest request);
|
||||
|
||||
|
||||
@@ -50,6 +50,14 @@ public interface IDevicePermissionService : IScopeDependency
|
||||
/// <returns></returns>
|
||||
Task<List<Guid>> GetAssignDeviceCodesAsync(string userNo);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取就餐权限唯一号
|
||||
/// </summary>
|
||||
/// <param name="userNo"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<string>> GetCanteenDeviceUniqueNosByUserNoAsync(string userNo);
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户权限设备
|
||||
/// </summary>
|
||||
|
||||
@@ -23,5 +23,11 @@ public interface IDeviceService : IScopeDependency
|
||||
|
||||
Task<Pagination<DevicePageResponse>> GetAttendanceOfflineAsync(DeviceOnlineAndofflineRequest request);
|
||||
|
||||
Task<Dictionary<string, int>> GetRecentNumbersAsync();
|
||||
Task<Pagination<DevicePageResponse>> GetDoorOfflineAsync(GetDoorOfflineRequest request);
|
||||
|
||||
Task<List<RecentNumberResponse>> GetRecentNumbersAsync();
|
||||
|
||||
Task BulkUploadsAsync(BulkUploadsRequest request);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@ using Dlhis.Basic.Device.Response;
|
||||
using Dlhis.Entity.Basic.Entity;
|
||||
using Dlhis.Entity.Device.Entities;
|
||||
using Dlhis.Entity.Device.Enums;
|
||||
using Kurisu.AspNetCore.UnifyResultAndValidation;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
using Kurisu.SqlSugar.Attributes;
|
||||
using Kurisu.SqlSugar.Services;
|
||||
using Mapster;
|
||||
|
||||
@@ -20,10 +18,10 @@ public class DeviceConnectService : IDeviceConnectService
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
[IgnoreTenant]
|
||||
|
||||
public async Task<string> ResigterAsync(DeviceResigterRequest request)
|
||||
{
|
||||
var businessPlace = await _dbContext.Queryable<CanteenBusinessPlaceEntity>().Where(x => x.CustomCode == request.BusinessCustomCode).FirstAsync();
|
||||
var businessPlace = await _dbContext.Queryable<BusinessPlaceEntity>().Where(x => x.CustomCode == request.BusinessCustomCode).FirstAsync();
|
||||
businessPlace.ThrowIfNull("营业点不存在");
|
||||
|
||||
var device = await GetEnableDeviceAsync(request.UniqueNo, false, request.DeployPlace, businessPlace.TenantId);
|
||||
@@ -55,7 +53,7 @@ public class DeviceConnectService : IDeviceConnectService
|
||||
public async Task<List<DeviceNotSetBusinessPlaceResponse>> GetNotSetBusinessPlaceDevicesAsync()
|
||||
{
|
||||
var devices = await _dbContext.Queryable<DeviceEntity>().Where(x => x.Enable).ToListAsync();
|
||||
devices = devices.Where(x => x.Funcs.Any(item => item == DeviceFuncEnumType.Meal)).ToList();
|
||||
devices = devices.Where(x => x.Type == DeviceTypeEnumType.Meal).ToList();
|
||||
|
||||
return devices.Adapt<List<DeviceNotSetBusinessPlaceResponse>>();
|
||||
}
|
||||
@@ -63,26 +61,31 @@ public class DeviceConnectService : IDeviceConnectService
|
||||
public async Task SetResigterBusinessPlaceAsync(DeviceSetResigterBusinessPlaceRequest request)
|
||||
{
|
||||
var device = await GetEnableDeviceAsync(request.UniqueNo);
|
||||
if (device.Funcs?.Any(x => x == DeviceFuncEnumType.Meal) != true)
|
||||
{
|
||||
throw new UserFriendlyException("当前设备无用餐功能,无法设置");
|
||||
}
|
||||
(device.Type != DeviceTypeEnumType.Meal).ThrowIfTrue("非就餐类型设备,无法设置");
|
||||
|
||||
var registry = await _dbContext.Queryable<DeviceRegistryEntity>().Where(x => x.DeviceUniqueNo == request.UniqueNo).FirstAsync();
|
||||
registry.ThrowIfNull($"{request.UniqueNo}的设备注册信息不存在,无法设置营业点");
|
||||
|
||||
var businessPlace = await _dbContext.Queryable<CanteenBusinessPlaceEntity>().Where(x => x.Code == request.BusinessPlaceCode).FirstAsync();
|
||||
businessPlace.ThrowIfNull("营业点不存在,无法设置到设备注册信息中");
|
||||
if (request.BusinessPlaceCode.HasValue)
|
||||
{
|
||||
var businessPlace = await _dbContext.Queryable<BusinessPlaceEntity>().Where(x => x.Code == request.BusinessPlaceCode).FirstAsync();
|
||||
businessPlace.ThrowIfNull("营业点不存在,无法设置到设备注册信息中");
|
||||
|
||||
//更新营业点信息
|
||||
registry.BusinessPlaceCode = businessPlace.Code;
|
||||
registry.BusinessPlaceCustomCode = businessPlace.CustomCode;
|
||||
//更新营业点信息
|
||||
registry.BusinessPlaceCode = businessPlace.Code;
|
||||
registry.BusinessPlaceCustomCode = businessPlace.CustomCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
//更新营业点信息
|
||||
registry.BusinessPlaceCode = null;
|
||||
registry.BusinessPlaceCustomCode = null;
|
||||
}
|
||||
|
||||
await _dbContext.UpdateAsync(registry);
|
||||
//todo 通知设备重新获取
|
||||
}
|
||||
|
||||
[IgnoreTenant]
|
||||
|
||||
public async Task HeartbeatAsync(DeviceHeartbeatRequest request)
|
||||
{
|
||||
var registry = await _dbContext.Queryable<DeviceRegistryEntity>().Where(x => x.DeviceUniqueNo == request.UniqueNo).FirstAsync();
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
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.DataAccess.Dto;
|
||||
using Kurisu.SqlSugar.Attributes;
|
||||
using Kurisu.SqlSugar.Extensions;
|
||||
using Kurisu.Core.User.Abstractions;
|
||||
using Kurisu.SqlSugar.Services;
|
||||
using Mapster;
|
||||
|
||||
@@ -15,24 +14,20 @@ public class DeviceGroupService : IDeviceGroupService
|
||||
{
|
||||
private readonly IDbContext _dbContext;
|
||||
private readonly IDevicePermissionService _devicePermissionService;
|
||||
private readonly ICurrentUser _currentUser;
|
||||
|
||||
public DeviceGroupService(IDbContext dbContext, IDevicePermissionService devicePermissionService)
|
||||
public DeviceGroupService(IDbContext dbContext, IDevicePermissionService devicePermissionService, ICurrentUser currentUser)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
_devicePermissionService = devicePermissionService;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<Pagination<DeviceGroupPageResponse>> GetPageAsync(DeviceGroupPageRequest request)
|
||||
{
|
||||
return await _dbContext.Queryable<DeviceGroupEntity>()
|
||||
.WhereIF(request.Search.IsPresent(), x => x.Name.Contains(request.Search))
|
||||
.Select<DeviceGroupPageResponse>()
|
||||
.ToPageListAsync(request);
|
||||
}
|
||||
|
||||
public async Task<List<DeviceGroupTreeResponse>> GetTreeAsync(bool showDevices)
|
||||
public async Task<List<DeviceGroupTreeResponse>> GetTreeAsync(bool showDevices, DeviceTypeEnumType? type)
|
||||
{
|
||||
var deviceGroups = await _dbContext.Queryable<DeviceGroupEntity>()
|
||||
.WhereIF(type.HasValue, x => x.Type == type)
|
||||
.Select<DeviceGroupTreeResponse>()
|
||||
.ToListAsync();
|
||||
|
||||
@@ -48,19 +43,37 @@ public class DeviceGroupService : IDeviceGroupService
|
||||
public async Task SaveAsync(DeviceGroupSaveRequest request)
|
||||
{
|
||||
//检查父级节点
|
||||
await CheckPCodeExistsDeviceAsync(request.PCode);
|
||||
var pGrp = await CheckPCodeAsync(request);
|
||||
|
||||
if (!request.Id.HasValue)
|
||||
{
|
||||
var entity = request.Adapt<DeviceGroupEntity>();
|
||||
|
||||
entity.Code = Guid.NewGuid();
|
||||
entity.TenantId = _currentUser.GetStringTenantId();
|
||||
|
||||
await _dbContext.InsertAsync(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
var entity = await _dbContext.Queryable<DeviceGroupEntity>().Where(x => x.Id == request.Id).FirstAsync();
|
||||
entity.ThrowIfNull("设备组不存在,无法更新");
|
||||
entity.ThrowIfNull("设备分组不存在,无法更新");
|
||||
entity.Editable.ThrowIfFalse("不可编辑当前分组");
|
||||
|
||||
if (request.Type != entity.Type)
|
||||
{
|
||||
//检查下级分组type不一致
|
||||
var existsDiffNextGroups = await _dbContext.Queryable<DeviceGroupEntity>()
|
||||
.Where(x => x.PCode == entity.Code)
|
||||
.Where(x => x.Type != request.Type)
|
||||
.AnyAsync();
|
||||
|
||||
existsDiffNextGroups.ThrowIfTrue("存在下级分组类型不一致,无法修改");
|
||||
|
||||
var nextDevices = await GetDevicesAsync(entity.Code);
|
||||
nextDevices.Any(x => x.Type != request.Type).ThrowIfTrue("分组设备类型不匹配,无法修改类型");
|
||||
}
|
||||
|
||||
request.Adapt(entity);
|
||||
await _dbContext.UpdateAsync(entity);
|
||||
}
|
||||
}
|
||||
@@ -68,16 +81,16 @@ public class DeviceGroupService : IDeviceGroupService
|
||||
public async Task DeleteAsync(long id)
|
||||
{
|
||||
var deviceGroup = await _dbContext.Queryable<DeviceGroupEntity>().Where(x => x.Id == id).FirstAsync();
|
||||
deviceGroup.ThrowIfNull("设备组不存在,无需删除");
|
||||
deviceGroup.ThrowIfNull("设备分组不存在,无需删除");
|
||||
|
||||
await _dbContext.DeleteAsync(deviceGroup);
|
||||
}
|
||||
|
||||
[Transactional]
|
||||
|
||||
public async Task AssignDevicesAsync(DeviceAssignRequest request)
|
||||
{
|
||||
var group = await _dbContext.Queryable<DeviceGroupEntity>().Where(x => x.Code == request.GroupCode).FirstAsync();
|
||||
group.ThrowIfNull("设备组不存在");
|
||||
group.ThrowIfNull("设备分组不存在,无法进行分配");
|
||||
|
||||
await CheckNoNextGroupAsync(group.Code);
|
||||
await CheckGroupTypeMatchAsync(request, group);
|
||||
@@ -86,13 +99,14 @@ public class DeviceGroupService : IDeviceGroupService
|
||||
await _devicePermissionService.GenerateDeviceTasksAsync(async () =>
|
||||
{
|
||||
var relationships = await _dbContext.Queryable<DeviceGroupRelationshipEntity>().Where(x => x.GroupCode == request.GroupCode).ToListAsync();
|
||||
await _dbContext.DeleteAsync(relationships);
|
||||
|
||||
await _dbContext.DeleteReallyAsync(relationships);
|
||||
|
||||
var entities = request.DeviceCodes.Select(x => new DeviceGroupRelationshipEntity
|
||||
{
|
||||
GroupCode = request.GroupCode,
|
||||
DeviceCode = x
|
||||
DeviceCode = x,
|
||||
|
||||
TenantId = _currentUser.GetStringTenantId(),
|
||||
|
||||
}).ToList();
|
||||
|
||||
@@ -116,28 +130,33 @@ public class DeviceGroupService : IDeviceGroupService
|
||||
/****************************************************** help methods *********************************************************/
|
||||
|
||||
/// <summary>
|
||||
/// 检查父级分组存在设备
|
||||
/// 检查父级分组
|
||||
/// </summary>
|
||||
/// <param name="pCode"></param>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
private async Task CheckPCodeExistsDeviceAsync(Guid? pCode)
|
||||
private async Task<DeviceGroupEntity> CheckPCodeAsync(DeviceGroupSaveRequest request)
|
||||
{
|
||||
if (pCode.HasValue)
|
||||
var pGrp = await _dbContext.Queryable<DeviceGroupEntity>().Where(x => x.Code == request.PCode).FirstAsync();
|
||||
if (pGrp != null)
|
||||
{
|
||||
var exists = await _dbContext.Queryable<DeviceGroupRelationshipEntity>().Where(x => x.GroupCode == pCode).AnyAsync();
|
||||
exists.ThrowIfTrue("父级分组存在设备");
|
||||
(!pGrp.AbleSetNext && !request.Id.HasValue).ThrowIfTrue($"{pGrp.Name}不可添加下级");
|
||||
var exists = await _dbContext.Queryable<DeviceGroupRelationshipEntity>().Where(x => x.GroupCode == request.PCode).AnyAsync();
|
||||
exists.ThrowIfTrue("上级分组存在设备");
|
||||
}
|
||||
|
||||
(pGrp != null && pGrp.Type != request.Type).ThrowIfTrue("分组类型必须与上级类型保持一致");
|
||||
return pGrp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 检查分组是否存在下级
|
||||
/// </summary>
|
||||
/// <param name="currentCode"></param>
|
||||
/// <returns></returns>
|
||||
private async Task CheckNoNextGroupAsync(Guid currentCode)
|
||||
{
|
||||
var exists = await _dbContext.Queryable<DeviceGroupEntity>().Where(x => x.PCode == currentCode).AnyAsync();
|
||||
exists.ThrowIfTrue("存在下级设备分组");
|
||||
exists.ThrowIfTrue("存在下级设备分组,无法分配设备");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -150,10 +169,7 @@ public class DeviceGroupService : IDeviceGroupService
|
||||
{
|
||||
var devices = await _dbContext.Queryable<DeviceEntity>().Where(x => request.DeviceCodes.Contains(x.Code)).ToListAsync();
|
||||
//检查分组的分类控制
|
||||
if (group.Type.HasValue)
|
||||
{
|
||||
devices.Any(x => x.Type != group.Type).ThrowIfTrue("存在设备类型有误,无法分配到当前分组");
|
||||
}
|
||||
devices.Any(x => x.Type != group.Type).ThrowIfTrue($"存在设备类型不一致,无法分配到当前{group.Type.GetDescription()}分组");
|
||||
|
||||
//重新赋值到请求参数中
|
||||
request.DeviceCodes = devices.Select(x => x.Code).ToList();
|
||||
@@ -164,15 +180,32 @@ public class DeviceGroupService : IDeviceGroupService
|
||||
/// 递归获取树
|
||||
/// </summary>
|
||||
/// <param name="current"></param>
|
||||
/// <param name="departments"></param>
|
||||
/// <param name="deviceGroups"></param>
|
||||
/// <param name="showDevices"></param>
|
||||
private void RecursionGetNext(DeviceGroupTreeResponse current, List<DeviceGroupTreeResponse> departments, bool showDevices)
|
||||
private void RecursionGetNext(DeviceGroupTreeResponse current, List<DeviceGroupTreeResponse> deviceGroups, bool showDevices)
|
||||
{
|
||||
var next = departments.Where(x => x.PCode == current.Code).ToList();
|
||||
var currentTenantId = _currentUser.GetStringTenantId();
|
||||
var next = deviceGroups.Where(x =>
|
||||
{
|
||||
if (x.PCode == current.Code)
|
||||
{
|
||||
if (x.TenantId.IsEmpty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return x.TenantId == currentTenantId;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}).ToList();
|
||||
current.Next = next;
|
||||
foreach (var item in next)
|
||||
{
|
||||
RecursionGetNext(item, departments, showDevices);
|
||||
RecursionGetNext(item, deviceGroups, showDevices);
|
||||
}
|
||||
|
||||
//最后层级附加设备信息
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Dlhis.Basic.Device.Request;
|
||||
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;
|
||||
@@ -7,159 +8,156 @@ using Dlhis.Entity.Sys.Entities;
|
||||
using Dlhis.Entity.Sys.Enums;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Kurisu.SqlSugar.Attributes;
|
||||
using Kurisu.Core.DataAccess.Entity;
|
||||
using Kurisu.Core.User.Abstractions;
|
||||
using Kurisu.SqlSugar.Services;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Dlhis.Basic.Device.Services.Implements;
|
||||
|
||||
public class DevicePermissionService : IDevicePermissionService
|
||||
{
|
||||
private readonly IDbContext _dbContext;
|
||||
private readonly ICurrentUser _currentUser;
|
||||
|
||||
public DevicePermissionService(IDbContext dbContext)
|
||||
public DevicePermissionService(IDbContext dbContext, ICurrentUser currentUser)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
[Transactional]
|
||||
public async Task AssignAsync(DevicePermissionSaveReuqest reuqest)
|
||||
{
|
||||
var tenantId = reuqest.AssignType == AssignTypeEnumType.Department ? reuqest.TenantId : _currentUser.GetStringTenantId();
|
||||
|
||||
//删除当前匹配的基地权限
|
||||
var p = await _dbContext.Queryable<DevicePermissionEntity>()
|
||||
.Where(x => x.AssignType == reuqest.AssignType)
|
||||
.Where(x => x.AssignValue == reuqest.AssignValue)
|
||||
.Where(x => x.UniqueType == reuqest.UniqueType)
|
||||
.Where(x => x.TenantId == tenantId)
|
||||
.ToListAsync();
|
||||
|
||||
await _dbContext.DeleteReallyAsync(p);
|
||||
|
||||
await GenerateDeviceTasksAsync(async () =>
|
||||
{
|
||||
|
||||
var p = await _dbContext.Queryable<DevicePermissionEntity>()
|
||||
.Where(x => x.AssignType == reuqest.AssignType)
|
||||
.Where(x => x.AssignValue == reuqest.AssignValue)
|
||||
.Where(x => x.UniqueType == reuqest.UniqueType)
|
||||
.ToListAsync();
|
||||
|
||||
await _dbContext.DeleteReallyAsync(p);
|
||||
|
||||
var devicePermissions = reuqest.Codes.Select(x => new DevicePermissionEntity
|
||||
//保存配置的权限
|
||||
if (reuqest.Codes.IsPresent())
|
||||
{
|
||||
AssignType = reuqest.AssignType,
|
||||
AssignValue = reuqest.AssignValue,
|
||||
UniqueType = reuqest.UniqueType,
|
||||
UniqueValue = x,
|
||||
var devicePermissions = reuqest.Codes.Select(code => new DevicePermissionEntity
|
||||
{
|
||||
AssignType = reuqest.AssignType,
|
||||
AssignValue = reuqest.AssignValue,
|
||||
UniqueType = reuqest.UniqueType,
|
||||
UniqueValue = code,
|
||||
TenantId = tenantId
|
||||
})
|
||||
.ToList();
|
||||
|
||||
}).ToList();
|
||||
|
||||
await _dbContext.InsertAsync(devicePermissions);
|
||||
await _dbContext.InsertAsync(devicePermissions);
|
||||
}
|
||||
|
||||
}, null);
|
||||
}
|
||||
|
||||
public async Task<List<Guid>> GetAssignmentsAsync(DeviceAssignmentTypeEnumType uniqueType, AssignTypeEnumType assignType, string assignValue)
|
||||
{
|
||||
var devicePermissions = await _dbContext.Queryable<DevicePermissionEntity>()
|
||||
.Where(x => x.UniqueType == uniqueType)
|
||||
.Where(x => x.AssignType == assignType)
|
||||
.Where(x => x.AssignValue == assignValue)
|
||||
.Select(x => x.UniqueValue)
|
||||
.ToListAsync();
|
||||
var devicePermissions = await _dbContext.Queryable<DevicePermissionEntity>().ToListAsync();
|
||||
var deviceGroups = await _dbContext.Queryable<DeviceGroupEntity>().ToListAsync();
|
||||
|
||||
if (uniqueType == DeviceAssignmentTypeEnumType.Group)
|
||||
{
|
||||
var deviceGroups = await _dbContext.Queryable<DeviceGroupEntity>().ToListAsync();
|
||||
var tops = deviceGroups.Where(x => !x.PCode.HasValue).ToList();
|
||||
tops.ForEach(x =>
|
||||
{
|
||||
RecursionGetNext(x, deviceGroups, devicePermissions, devicePermissions.Contains(x.Code));
|
||||
});
|
||||
}
|
||||
|
||||
return devicePermissions.Distinct().ToList();
|
||||
|
||||
void RecursionGetNext(DeviceGroupEntity current, List<DeviceGroupEntity> deviceGroups, List<Guid> result, bool add)
|
||||
{
|
||||
var next = deviceGroups.Where(x => x.PCode == current.Code).ToList();
|
||||
foreach (var item in next)
|
||||
{
|
||||
if (add) result.Add(item.Code);
|
||||
RecursionGetNext(item, deviceGroups, result, result.Contains(item.Code));
|
||||
}
|
||||
}
|
||||
var result = GetAssignCodesInternal(devicePermissions, deviceGroups, uniqueType, assignType, assignValue);
|
||||
return result.FirstOrDefault(x => x.Tenant == _currentUser.GetStringTenantId())?.Codes;
|
||||
}
|
||||
|
||||
|
||||
public async Task GenerateDeviceTasksAsync(Func<Task> func, List<string> userNos)
|
||||
{
|
||||
if (userNos.IsEmpty())
|
||||
_dbContext.Client.QueryFilter.ClearAndBackup<ITenantId>();
|
||||
try
|
||||
{
|
||||
userNos = await GetPermissionUserNosAsync();
|
||||
}
|
||||
//获取所有人的权限
|
||||
if (userNos.IsEmpty())
|
||||
userNos = await GetPermissionUserNosAsync();
|
||||
|
||||
var beforeDic = await GetAssignDeviceCodesAsync(userNos);
|
||||
var before = await GetAssignDeviceCodesInternalAsync(userNos);
|
||||
|
||||
//获取处理
|
||||
await func();
|
||||
_dbContext.Client.QueryFilter.Restore();
|
||||
//业务处理
|
||||
await func();
|
||||
_dbContext.Client.QueryFilter.ClearAndBackup<ITenantId>();
|
||||
|
||||
//获取当前的权限code
|
||||
//获取业务处理后所有人的权限
|
||||
var nextUserNos = await GetPermissionUserNosAsync();
|
||||
if (nextUserNos.Any())
|
||||
userNos = userNos.Concat(nextUserNos).Distinct().ToList();
|
||||
|
||||
var nextUserNos = await GetPermissionUserNosAsync();
|
||||
if (nextUserNos.Any())
|
||||
{
|
||||
userNos = nextUserNos;
|
||||
}
|
||||
var current = await GetAssignDeviceCodesInternalAsync(userNos);
|
||||
|
||||
var currentDic = await GetAssignDeviceCodesAsync(userNos);
|
||||
var deivces = await _dbContext.Queryable<DeviceEntity>().ToListAsync();
|
||||
var waitTasks = new List<DeviceTaskEntity>();
|
||||
|
||||
var deivces = await _dbContext.Queryable<DeviceEntity>().ToListAsync();
|
||||
foreach (var userNo in userNos)
|
||||
{
|
||||
beforeDic.TryGetValue(userNo, out var beforeCodes);
|
||||
beforeCodes ??= new List<Guid>();
|
||||
|
||||
currentDic.TryGetValue(userNo, out var currentCodes);
|
||||
currentCodes ??= new List<Guid>();
|
||||
|
||||
//被删除
|
||||
var deletedItems = beforeCodes.Where(x => !currentCodes.Contains(x)).ToList();
|
||||
//新增
|
||||
var addItems = currentCodes.Where(x => !beforeCodes.Contains(x)).ToList();
|
||||
|
||||
if (!deletedItems.Any() && !addItems.Any())
|
||||
foreach (var userNo in userNos)
|
||||
{
|
||||
continue;
|
||||
before.TryGetValue(userNo, out var beforeTenantDeviceCodes);
|
||||
beforeTenantDeviceCodes ??= new();
|
||||
|
||||
current.TryGetValue(userNo, out var currentTenantDeviceCodes);
|
||||
currentTenantDeviceCodes ??= new();
|
||||
|
||||
var tenants = beforeTenantDeviceCodes.Select(x => x.Tenant).Concat(currentTenantDeviceCodes.Select(x => x.Tenant)).Distinct().ToList();
|
||||
|
||||
foreach (var tenant in tenants)
|
||||
{
|
||||
var currentCodes = currentTenantDeviceCodes.FirstOrDefault(x => x.Tenant == tenant)?.Codes ?? new();
|
||||
var beforeCodes = beforeTenantDeviceCodes.FirstOrDefault(x => x.Tenant == tenant)?.Codes ?? new();
|
||||
|
||||
//被删除
|
||||
var deletedItems = beforeCodes.Where(x => !currentCodes.Contains(x)).ToList();
|
||||
//新增
|
||||
var addItems = currentCodes.Where(x => !beforeCodes.Contains(x)).ToList();
|
||||
|
||||
if (!deletedItems.Any() && !addItems.Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var deviceCodes = deivces.Where(x => deletedItems.Contains(x.Code) || addItems.Contains(x.Code)).Select(x => x.Code).ToList();
|
||||
deletedItems = deletedItems.Where(x => deviceCodes.Contains(x)).ToList();
|
||||
addItems = addItems.Where(x => deviceCodes.Contains(x)).ToList();
|
||||
|
||||
//下发任务创建
|
||||
var toDeleted = deletedItems.Select(x => new DeviceTaskEntity
|
||||
{
|
||||
DeviceUniqueNo = deivces.First(item => item.Code == x).UniqueNo,
|
||||
Status = DeviceTaskStatusEnumType.Wait,
|
||||
Type = DeviceTaskEnumType.Delete,
|
||||
UserNo = userNo,
|
||||
Version = 0,
|
||||
TenantId = tenant,
|
||||
}).ToList();
|
||||
|
||||
var toAdd = addItems.Select(x => new DeviceTaskEntity
|
||||
{
|
||||
DeviceUniqueNo = deivces.First(item => item.Code == x).UniqueNo,
|
||||
Status = DeviceTaskStatusEnumType.Wait,
|
||||
Type = DeviceTaskEnumType.Add,
|
||||
UserNo = userNo,
|
||||
Version = 0,
|
||||
TenantId = tenant,
|
||||
}).ToList();
|
||||
|
||||
waitTasks.AddRange(toDeleted.Concat(toAdd).ToList());
|
||||
}
|
||||
}
|
||||
|
||||
var deviceCodes = deivces.Where(x => deletedItems.Contains(x.Code) || addItems.Contains(x.Code)).Select(x => x.Code).ToList();
|
||||
deletedItems = deletedItems.Where(x => deviceCodes.Contains(x)).ToList();
|
||||
addItems = addItems.Where(x => deviceCodes.Contains(x)).ToList();
|
||||
|
||||
var userInfo = await _dbContext.Queryable<GainfoEntity>()
|
||||
.LeftJoin<DepartmentEntity>((ga, department) => department.No == ga.DepartmentNo)
|
||||
.Where(ga => ga.No == userNo)
|
||||
.Select(ga => new
|
||||
{
|
||||
ga.Code
|
||||
})
|
||||
.SingleAsync();
|
||||
|
||||
//下发任务创建
|
||||
var toDeleted = deletedItems.Select(x => new DeviceTaskEntity
|
||||
if (waitTasks.Any())
|
||||
{
|
||||
DeviceUniqueNo = deivces.First(item => item.Code == x).UniqueNo,
|
||||
Status = DeviceTaskStatusEnumType.Wait,
|
||||
Type = DeviceTaskEnumType.Delete,
|
||||
UserNo = userNo,
|
||||
Version = 0,
|
||||
UserCode = userInfo.Code,
|
||||
}).ToList();
|
||||
|
||||
var toAdd = addItems.Select(x => new DeviceTaskEntity
|
||||
{
|
||||
DeviceUniqueNo = deivces.First(item => item.Code == x).UniqueNo,
|
||||
Status = DeviceTaskStatusEnumType.Wait,
|
||||
Type = DeviceTaskEnumType.Add,
|
||||
UserNo = userNo,
|
||||
Version = 0,
|
||||
UserCode = userInfo.Code,
|
||||
}).ToList();
|
||||
|
||||
var tasks = toDeleted.Concat(toAdd).ToList();
|
||||
await _dbContext.InsertAsync(tasks);
|
||||
await _dbContext.InsertAsync(waitTasks);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_dbContext.Client.QueryFilter.Restore();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +181,6 @@ public class DevicePermissionService : IDevicePermissionService
|
||||
})
|
||||
.SingleAsync();
|
||||
|
||||
|
||||
var tasks = deviceCodes.Select(x => new DeviceTaskEntity
|
||||
{
|
||||
DeviceUniqueNo = deivces.First(item => item.Code == x).UniqueNo,
|
||||
@@ -191,13 +188,23 @@ public class DevicePermissionService : IDevicePermissionService
|
||||
Type = taskType,
|
||||
UserNo = userNo,
|
||||
Version = 0,
|
||||
UserCode = userInfo.Code,
|
||||
}).ToList();
|
||||
|
||||
await _dbContext.InsertAsync(tasks);
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<string>> GetCanteenDeviceUniqueNosByUserNoAsync(string userNo)
|
||||
{
|
||||
var all = await GetAssignDeviceCodesAsync(userNo);
|
||||
|
||||
return await _dbContext.Queryable<DeviceEntity>().Where(x => x.Type == DeviceTypeEnumType.Meal)
|
||||
.Where(x => all.Contains(x.Code))
|
||||
.Select(x => x.UniqueNo)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户所有设备权限
|
||||
/// </summary>
|
||||
@@ -206,125 +213,17 @@ public class DevicePermissionService : IDevicePermissionService
|
||||
public async Task<List<Guid>> GetAssignDeviceCodesAsync(string userNo)
|
||||
{
|
||||
var gainfo = await _dbContext.Queryable<GainfoEntity>().Where(x => x.No == userNo).SingleAsync();
|
||||
var gainfoGroups = await _dbContext.Queryable<GainfoGroupRelationshipEntity>().Where(x => x.UserNo == userNo).Select(x => x.GroupCode).ToListAsync();
|
||||
var gainfoGroups = await _dbContext.Queryable<GainfoGroupRelationshipEntity>().ToListAsync();
|
||||
|
||||
var deviceCodes = new List<Guid>();
|
||||
var deviceGroupCodes = new List<Guid>();
|
||||
|
||||
var du = await GetAssignmentsAsync(DeviceAssignmentTypeEnumType.Device, AssignTypeEnumType.User, userNo);
|
||||
var gu = await GetAssignmentsAsync(DeviceAssignmentTypeEnumType.Group, AssignTypeEnumType.User, userNo);
|
||||
deviceCodes.AddRange(du);
|
||||
deviceGroupCodes.AddRange(gu);
|
||||
|
||||
foreach (var group in gainfoGroups)
|
||||
{
|
||||
var dg = await GetAssignmentsAsync(DeviceAssignmentTypeEnumType.Device, AssignTypeEnumType.Group, group.ToString());
|
||||
var gg = await GetAssignmentsAsync(DeviceAssignmentTypeEnumType.Group, AssignTypeEnumType.Group, group.ToString());
|
||||
deviceCodes.AddRange(dg);
|
||||
deviceGroupCodes.AddRange(gg);
|
||||
}
|
||||
|
||||
var dd = await GetAssignmentsAsync(DeviceAssignmentTypeEnumType.Device, AssignTypeEnumType.Department, gainfo.DepartmentNo);
|
||||
var gd = await GetAssignmentsAsync(DeviceAssignmentTypeEnumType.Group, AssignTypeEnumType.Department, gainfo.DepartmentNo);
|
||||
deviceCodes.AddRange(dd);
|
||||
deviceGroupCodes.AddRange(gd);
|
||||
|
||||
var dt = await GetAssignmentsAsync(DeviceAssignmentTypeEnumType.Device, AssignTypeEnumType.Tenant, gainfo.Werks);
|
||||
var gt = await GetAssignmentsAsync(DeviceAssignmentTypeEnumType.Group, AssignTypeEnumType.Tenant, gainfo.Werks);
|
||||
deviceCodes.AddRange(du);
|
||||
deviceGroupCodes.AddRange(gu);
|
||||
|
||||
var deveiceCodesByGroup = await _dbContext.Queryable<DeviceGroupRelationshipEntity>().Where(x => deviceGroupCodes.Contains(x.GroupCode)).Select(x => x.DeviceCode).ToListAsync();
|
||||
deviceCodes.AddRange(deveiceCodesByGroup);
|
||||
|
||||
return deviceCodes.Distinct().ToList();
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, List<Guid>>> GetAssignDeviceCodesAsync(List<string> userNos)
|
||||
{
|
||||
var gainfos = await _dbContext.Queryable<GainfoEntity>().Where(x => userNos.Contains(x.No)).ToListAsync();
|
||||
if (!gainfos.Any())
|
||||
{
|
||||
return new Dictionary<string, List<Guid>>();
|
||||
}
|
||||
var gainfoGroupRelationships = await _dbContext.Queryable<GainfoGroupRelationshipEntity>().ToListAsync();
|
||||
var devicePermissions = await _dbContext.Queryable<DevicePermissionEntity>().ToListAsync();
|
||||
var deviceGroups = await _dbContext.Queryable<DeviceGroupEntity>().ToListAsync();
|
||||
var deviceRelationships = await _dbContext.Queryable<DeviceGroupRelationshipEntity>().ToListAsync();
|
||||
|
||||
var result = new Dictionary<string, List<Guid>>();
|
||||
|
||||
foreach (var gainfo in gainfos)
|
||||
{
|
||||
var userNo = gainfo.No;
|
||||
|
||||
var gainfoGroups = gainfoGroupRelationships.Where(x => x.UserNo == userNo).ToList();
|
||||
|
||||
var deviceCodes = new List<Guid>();
|
||||
var deviceGroupCodes = new List<Guid>();
|
||||
|
||||
var du = GetAssignmentsInternal(DeviceAssignmentTypeEnumType.Device, AssignTypeEnumType.User, userNo);
|
||||
var gu = GetAssignmentsInternal(DeviceAssignmentTypeEnumType.Group, AssignTypeEnumType.User, userNo);
|
||||
deviceCodes.AddRange(du);
|
||||
deviceGroupCodes.AddRange(gu);
|
||||
|
||||
foreach (var group in gainfoGroups)
|
||||
{
|
||||
var dg = GetAssignmentsInternal(DeviceAssignmentTypeEnumType.Device, AssignTypeEnumType.Group, group.ToString());
|
||||
var gg = GetAssignmentsInternal(DeviceAssignmentTypeEnumType.Group, AssignTypeEnumType.Group, group.ToString());
|
||||
deviceCodes.AddRange(dg);
|
||||
deviceGroupCodes.AddRange(gg);
|
||||
}
|
||||
|
||||
var dd = GetAssignmentsInternal(DeviceAssignmentTypeEnumType.Device, AssignTypeEnumType.Department, gainfo.DepartmentNo);
|
||||
var gd = GetAssignmentsInternal(DeviceAssignmentTypeEnumType.Group, AssignTypeEnumType.Department, gainfo.DepartmentNo);
|
||||
deviceCodes.AddRange(dd);
|
||||
deviceGroupCodes.AddRange(gd);
|
||||
|
||||
var dt = GetAssignmentsInternal(DeviceAssignmentTypeEnumType.Device, AssignTypeEnumType.Tenant, gainfo.Werks);
|
||||
var gt = GetAssignmentsInternal(DeviceAssignmentTypeEnumType.Group, AssignTypeEnumType.Tenant, gainfo.Werks);
|
||||
deviceCodes.AddRange(du);
|
||||
deviceGroupCodes.AddRange(gu);
|
||||
|
||||
var deveiceCodesByGroup = await _dbContext.Queryable<DeviceGroupRelationshipEntity>().Where(x => deviceGroupCodes.Contains(x.GroupCode)).Select(x => x.DeviceCode).ToListAsync();
|
||||
deviceCodes.AddRange(deveiceCodesByGroup);
|
||||
|
||||
result.Add(userNo, deviceCodes.Distinct().ToList());
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
|
||||
List<Guid> GetAssignmentsInternal(DeviceAssignmentTypeEnumType uniqueTypeInternal, AssignTypeEnumType assignTypeInternal, string assignValueInternal)
|
||||
{
|
||||
var devicePermissionsInternal = devicePermissions.Where(x => x.UniqueType == uniqueTypeInternal)
|
||||
.Where(x => x.AssignType == assignTypeInternal)
|
||||
.Where(x => x.AssignValue == assignValueInternal)
|
||||
.Select(x => x.UniqueValue)
|
||||
.ToList();
|
||||
|
||||
if (uniqueTypeInternal == DeviceAssignmentTypeEnumType.Group)
|
||||
{
|
||||
var tops = deviceGroups.Where(x => !x.PCode.HasValue).ToList();
|
||||
tops.ForEach(x =>
|
||||
{
|
||||
RecursionGetNext(x, deviceGroups, devicePermissionsInternal, devicePermissionsInternal.Contains(x.Code));
|
||||
});
|
||||
}
|
||||
|
||||
return devicePermissionsInternal.Distinct().ToList();
|
||||
|
||||
void RecursionGetNext(DeviceGroupEntity current, List<DeviceGroupEntity> deviceGroups, List<Guid> result, bool add)
|
||||
{
|
||||
var next = deviceGroups.Where(x => x.PCode == current.Code).ToList();
|
||||
foreach (var item in next)
|
||||
{
|
||||
if (add) result.Add(item.Code);
|
||||
RecursionGetNext(item, deviceGroups, result, result.Contains(item.Code));
|
||||
}
|
||||
}
|
||||
}
|
||||
var result = GetAssignDeviceCodesInternal(gainfo, gainfoGroups, devicePermissions, deviceGroups, deviceRelationships);
|
||||
return result.SelectMany(x => x.Codes).ToList();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户权限设备
|
||||
/// </summary>
|
||||
@@ -340,7 +239,7 @@ public class DevicePermissionService : IDevicePermissionService
|
||||
|
||||
var devices = await _dbContext.Queryable<DeviceEntity>().ToListAsync();
|
||||
|
||||
if(ggs != null && ggs.Count > 0)
|
||||
if (ggs != null && ggs.Count > 0)
|
||||
{
|
||||
foreach (var gid in ggs)
|
||||
{
|
||||
@@ -351,7 +250,7 @@ public class DevicePermissionService : IDevicePermissionService
|
||||
gds.AddRange(ds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var dds = gds.Distinct().ToList();
|
||||
var lst = devices.Where(x => dds.Contains(x.Code))
|
||||
.Select(x => new AssigmentByCodeResponse
|
||||
@@ -403,8 +302,169 @@ public class DevicePermissionService : IDevicePermissionService
|
||||
var tenants = permissions.Where(x => x.AssignType == AssignTypeEnumType.Tenant).Select(x => x.AssignValue).ToList();
|
||||
var userNosByWerk = await _dbContext.Queryable<GainfoEntity>().Where(x => tenants.Contains(x.Werks)).Select(x => x.No).ToListAsync();
|
||||
|
||||
|
||||
return userNos.Concat(userNosByGroup).Concat(userNosByDepartment).Concat(userNosByWerk).ToList();
|
||||
return userNos.Concat(userNosByGroup).Concat(userNosByDepartment).Concat(userNosByWerk).Distinct().ToList();
|
||||
}
|
||||
|
||||
|
||||
private static List<Guid> GetAssignmentsInternal(
|
||||
List<DevicePermissionEntity> devicePermissions, List<DeviceGroupEntity> deviceGroups,
|
||||
DeviceAssignmentTypeEnumType uniqueType, AssignTypeEnumType assignType, string assignValue)
|
||||
{
|
||||
var devicePermissionCodes = devicePermissions
|
||||
.Where(x => x.UniqueType == uniqueType)
|
||||
.Where(x => x.AssignType == assignType)
|
||||
.Where(x => x.AssignValue == assignValue)
|
||||
.Select(x => x.UniqueValue).ToList();
|
||||
|
||||
//处理获取设备组的情况,递归到最下级获取设备code
|
||||
if (uniqueType == DeviceAssignmentTypeEnumType.Group)
|
||||
{
|
||||
var tops = deviceGroups.Where(x => !x.PCode.HasValue).ToList();
|
||||
tops.ForEach(x =>
|
||||
{
|
||||
RecursionGetNext(x, deviceGroups, devicePermissionCodes, devicePermissionCodes.Contains(x.Code));
|
||||
});
|
||||
}
|
||||
|
||||
return devicePermissionCodes.Distinct().ToList();
|
||||
|
||||
void RecursionGetNext(DeviceGroupEntity current, List<DeviceGroupEntity> deviceGroups, List<Guid> result, bool add)
|
||||
{
|
||||
var next = deviceGroups.Where(x => x.PCode == current.Code).ToList();
|
||||
foreach (var item in next)
|
||||
{
|
||||
if (add) result.Add(item.Code);
|
||||
RecursionGetNext(item, deviceGroups, result, result.Contains(item.Code));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<UserTenantDeviceCodeDto> GetAssignCodesInternal(
|
||||
List<DevicePermissionEntity> devicePermissions, List<DeviceGroupEntity> deviceGroups,
|
||||
DeviceAssignmentTypeEnumType uniqueType, AssignTypeEnumType assignType, string assignValue)
|
||||
{
|
||||
var tenantDevicePermissions = devicePermissions
|
||||
.Where(x => x.UniqueType == uniqueType)
|
||||
.Where(x => x.AssignType == assignType)
|
||||
.Where(x => x.AssignValue == assignValue)
|
||||
.GroupBy(x => x.TenantId)
|
||||
.Select(x => new UserTenantDeviceCodeDto { Tenant = x.Key, Codes = x.Select(x => x.UniqueValue).ToList() })
|
||||
.ToList();
|
||||
|
||||
//处理获取设备分组的情况
|
||||
if (uniqueType == DeviceAssignmentTypeEnumType.Group)
|
||||
{
|
||||
//开始递归处理
|
||||
var tops = deviceGroups.Where(x => !x.PCode.HasValue).ToList();
|
||||
tops.ForEach(x =>
|
||||
{
|
||||
RecursionGetNext(x, deviceGroups, tenantDevicePermissions, tenantDevicePermissions.SelectMany(x => x.Codes).Contains(x.Code));
|
||||
});
|
||||
}
|
||||
|
||||
return tenantDevicePermissions.GroupBy(x => x.Tenant).Select(x =>
|
||||
{
|
||||
var tenant = x.Key;
|
||||
|
||||
return new UserTenantDeviceCodeDto
|
||||
{
|
||||
Tenant = tenant,
|
||||
Codes = x.SelectMany(item => item.Codes).ToList()
|
||||
};
|
||||
}).ToList();
|
||||
|
||||
void RecursionGetNext(DeviceGroupEntity current, List<DeviceGroupEntity> deviceGroups, List<UserTenantDeviceCodeDto> result, bool add)
|
||||
{
|
||||
var next = deviceGroups.Where(x => x.PCode == current.Code).ToList();
|
||||
foreach (var item in next)
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
result.Add(new UserTenantDeviceCodeDto { Tenant = item.TenantId, Codes = new List<Guid> { item.Code } });
|
||||
}
|
||||
RecursionGetNext(item, deviceGroups, result, result.SelectMany(x => x.Codes).Contains(item.Code));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, List<UserTenantDeviceCodeDto>>> GetAssignDeviceCodesInternalAsync(List<string> userNos)
|
||||
{
|
||||
var gainfos = await _dbContext.Queryable<GainfoEntity>().Where(x => userNos.Contains(x.No)).ToListAsync();
|
||||
if (!gainfos.Any())
|
||||
{
|
||||
return new Dictionary<string, List<UserTenantDeviceCodeDto>>();
|
||||
}
|
||||
|
||||
var gainfoGroupRelationships = await _dbContext.Queryable<GainfoGroupRelationshipEntity>().Where(x => userNos.Contains(x.UserNo)).ToListAsync();
|
||||
var devicePermissions = await _dbContext.Queryable<DevicePermissionEntity>().ToListAsync();
|
||||
var deviceGroups = await _dbContext.Queryable<DeviceGroupEntity>().ToListAsync();
|
||||
var deviceRelationships = await _dbContext.Queryable<DeviceGroupRelationshipEntity>().ToListAsync();
|
||||
|
||||
var result = new Dictionary<string, List<UserTenantDeviceCodeDto>>(gainfos.Count);
|
||||
|
||||
foreach (var gainfo in gainfos)
|
||||
{
|
||||
var codes = GetAssignDeviceCodesInternal(gainfo, gainfoGroupRelationships, devicePermissions, deviceGroups, deviceRelationships);
|
||||
result.Add(gainfo.No, codes);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<UserTenantDeviceCodeDto> GetAssignDeviceCodesInternal(
|
||||
GainfoEntity gainfo,
|
||||
List<GainfoGroupRelationshipEntity> gainfoGroupRelationships,
|
||||
List<DevicePermissionEntity> devicePermissions,
|
||||
List<DeviceGroupEntity> deviceGroups,
|
||||
List<DeviceGroupRelationshipEntity> deviceGroupRelationships)
|
||||
{
|
||||
var userNo = gainfo.No;
|
||||
var deviceCodes = new List<UserTenantDeviceCodeDto>();
|
||||
var deviceGroupCodes = new List<UserTenantDeviceCodeDto>();
|
||||
|
||||
//获取人员的分组,跨基地
|
||||
var gainfoGroups = gainfoGroupRelationships.Where(x => x.UserNo == userNo).Select(x => x.GroupCode).ToList();
|
||||
|
||||
//按User获取权限
|
||||
var du = GetAssignCodesInternal(devicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.Device, AssignTypeEnumType.User, userNo);
|
||||
var gu = GetAssignCodesInternal(devicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.Group, AssignTypeEnumType.User, userNo);
|
||||
deviceCodes.AddRange(du);
|
||||
deviceGroupCodes.AddRange(gu);
|
||||
|
||||
foreach (var groupCode in gainfoGroups)
|
||||
{
|
||||
var dg = GetAssignCodesInternal(devicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.Device, AssignTypeEnumType.Group, groupCode.ToString());
|
||||
var gg = GetAssignCodesInternal(devicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.Group, AssignTypeEnumType.Group, groupCode.ToString());
|
||||
deviceCodes.AddRange(dg);
|
||||
deviceGroupCodes.AddRange(gg);
|
||||
}
|
||||
|
||||
var gainfoFactoryDevicePermissions = devicePermissions.Where(x => x.TenantId == gainfo.Factory).ToList();
|
||||
var dd = GetAssignCodesInternal(gainfoFactoryDevicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.Device, AssignTypeEnumType.Department, gainfo.DepartmentNo);
|
||||
var gd = GetAssignCodesInternal(gainfoFactoryDevicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.Group, AssignTypeEnumType.Department, gainfo.DepartmentNo);
|
||||
deviceCodes.AddRange(dd);
|
||||
deviceGroupCodes.AddRange(gd);
|
||||
|
||||
var dt = GetAssignCodesInternal(devicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.Device, AssignTypeEnumType.Tenant, gainfo.Factory);
|
||||
var gt = GetAssignCodesInternal(devicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.Group, AssignTypeEnumType.Tenant, gainfo.Factory);
|
||||
deviceCodes.AddRange(du);
|
||||
deviceGroupCodes.AddRange(gu);
|
||||
|
||||
var groupCodes = deviceGroupCodes.SelectMany(x => x.Codes).Distinct().ToList();
|
||||
var deveiceCodesByGroup = deviceGroupRelationships.Where(x => groupCodes.Contains(x.GroupCode)).GroupBy(x => x.TenantId)
|
||||
.Select(x => new UserTenantDeviceCodeDto
|
||||
{
|
||||
Tenant = x.Key,
|
||||
Codes = x.Select(item => item.DeviceCode).Distinct().ToList()
|
||||
});
|
||||
|
||||
deviceCodes.AddRange(deveiceCodesByGroup);
|
||||
|
||||
return deviceCodes.GroupBy(x => x.Tenant).Select(x => new UserTenantDeviceCodeDto
|
||||
{
|
||||
Tenant = x.Key,
|
||||
Codes = x.SelectMany(item => item.Codes).Distinct().ToList()
|
||||
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
using Dlhis.Basic.Device.Request;
|
||||
using Dlhis.Basic.Device.Response;
|
||||
using Dlhis.Entity.Basic.Entity;
|
||||
using Dlhis.Entity.Canteen.Entities;
|
||||
using Dlhis.Entity.Canteen.Enums;
|
||||
using Dlhis.Entity.Device.Entities;
|
||||
using Dlhis.Entity.Device.Enums;
|
||||
using Kurisu.AspNetCore.UnifyResultAndValidation;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Kurisu.SqlSugar.Attributes;
|
||||
using Kurisu.SqlSugar.Extensions;
|
||||
using Kurisu.SqlSugar.Services;
|
||||
using Mapster;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MySqlX.XDevAPI.Relational;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NPOI.OpenXmlFormats;
|
||||
using NPOI.SS.UserModel;
|
||||
using NPOI.XSSF.UserModel;
|
||||
using SqlSugar;
|
||||
|
||||
namespace Dlhis.Basic.Device.Services.Implements;
|
||||
|
||||
@@ -29,29 +35,57 @@ public class DeviceService : IDeviceService
|
||||
{
|
||||
var page = await _dbContext.Queryable<DeviceEntity>()
|
||||
.LeftJoin<DeviceTemplateEntity>((d, dt) => d.TemplateCode == dt.Code)
|
||||
.LeftJoin<DeviceRegistryEntity>((d, dt, dr) => d.UniqueNo == dr.DeviceUniqueNo)
|
||||
.LeftJoin<BusinessPlaceEntity>((d, dt, dr, bp) => dr.BusinessPlaceCode == bp.Code)
|
||||
.WhereIF(request.Type.HasValue, (d, dt) => d.Type == request.Type)
|
||||
.Select((d, dt) => new DevicePageResponse
|
||||
.Select((d, dt, dr, bp) => new DevicePageResponse
|
||||
{
|
||||
FuncsStr = d.Funcs.ToString(),
|
||||
Brand = dt.Brand,
|
||||
Type = d.Type,
|
||||
|
||||
BusinessPlaceCode = bp.Code,
|
||||
BusinessPlaceName = bp.Name,
|
||||
LastHeartbeatTime = dr.LastHeartbeatTime
|
||||
}, true)
|
||||
.ToPageListAsync(request);
|
||||
|
||||
var deviceUniqueNos = page.Data.Select(x => x.UniqueNo).ToList();
|
||||
|
||||
var balanceInfos = await _dbContext.Queryable<BalanceRecordEntity>().Where(x => x.Type == BalanceRecordTypeEnumType.Out)
|
||||
.Where(x => deviceUniqueNos.Contains(x.DeviceInfo))
|
||||
.Select(x => new
|
||||
{
|
||||
x.DeviceInfo,
|
||||
Amount = SqlFunc.AggregateSum(x.Amount),
|
||||
UserCount = SqlFunc.AggregateDistinctCount(x.UserCode)
|
||||
})
|
||||
.GroupBy(x => x.DeviceInfo)
|
||||
.ToListAsync();
|
||||
|
||||
page.Data.ForEach(device =>
|
||||
{
|
||||
var info = balanceInfos.FirstOrDefault(x => x.DeviceInfo == device.UniqueNo);
|
||||
if (info != null)
|
||||
{
|
||||
device.Amount = info.Amount;
|
||||
device.UserCount = info.UserCount;
|
||||
}
|
||||
});
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
[Transactional]
|
||||
|
||||
public async Task SaveAsync(DeviceSaveRequest request)
|
||||
{
|
||||
await CheckUniqueNoExistsAsync(request);
|
||||
var template = await CheckTemplateExistsAsync(request.TemplateCode);
|
||||
await CheckTemplateFieldAsync(request.TemplateCode, request.ConnectionInfo);
|
||||
|
||||
DeviceEntity entity = null;
|
||||
if (!request.Id.HasValue)
|
||||
{
|
||||
var entity = request.Adapt<DeviceEntity>();
|
||||
entity = request.Adapt<DeviceEntity>();
|
||||
entity.Code = Guid.NewGuid();
|
||||
await _dbContext.InsertAsync(entity);
|
||||
//同时保存注册信息
|
||||
@@ -72,7 +106,7 @@ public class DeviceService : IDeviceService
|
||||
}
|
||||
else
|
||||
{
|
||||
var entity = await _dbContext.Queryable<DeviceEntity>().Where(x => x.Id == request.Id).FirstAsync();
|
||||
entity = await _dbContext.Queryable<DeviceEntity>().Where(x => x.Id == request.Id).FirstAsync();
|
||||
entity.ThrowIfNull("设备不存在,无法更新");
|
||||
|
||||
//分类发生变化,检查是否存在分组
|
||||
@@ -81,21 +115,94 @@ public class DeviceService : IDeviceService
|
||||
var existsG = await _dbContext.Queryable<DeviceGroupRelationshipEntity>()
|
||||
.LeftJoin<DeviceGroupEntity>((dgr, dg) => dgr.GroupCode == dg.Code)
|
||||
.Where((dgr, dg) => dgr.DeviceCode == entity.Code)
|
||||
.Where((dgr, dg) => dg.Type != null)
|
||||
.AnyAsync();
|
||||
|
||||
existsG.ThrowIfTrue("存在设备分组,不可修改设备分类");
|
||||
}
|
||||
|
||||
var uniqueNo = entity.UniqueNo;
|
||||
request.Adapt(entity).UniqueNo = uniqueNo;
|
||||
|
||||
request.Adapt(entity);
|
||||
await _dbContext.UpdateAsync(entity);
|
||||
}
|
||||
|
||||
await GenerateUploadRecordLogForBeginTimeAsync(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量导入
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public async Task BulkUploadsAsync(BulkUploadsRequest request)
|
||||
{
|
||||
var lst = ImportFromExcel(request.FormFile);
|
||||
var places = await _dbContext.Queryable<BusinessPlaceEntity>().ToListAsync();
|
||||
|
||||
foreach (var form in lst)
|
||||
{
|
||||
if (form.PlaceeCode != null)
|
||||
{
|
||||
var place = places.Where(x => x.Code == form.PlaceeCode).FirstOrDefault();
|
||||
place.ThrowIfNull($"该设备{form.UniqueNo}配置的营业点营业点不存在!");
|
||||
}
|
||||
//插入
|
||||
var exists = await _dbContext.Queryable<DeviceEntity>().Where(x => x.UniqueNo == form.UniqueNo)
|
||||
.AnyAsync();
|
||||
exists.ThrowIfTrue("唯一号已经存在");
|
||||
var template = await CheckTemplateExistsAsync(form.TemplateCode);
|
||||
await CheckTemplateFieldAsync(form.TemplateCode, form.ConnectionInfo);
|
||||
|
||||
var saveEntity = form.Adapt<DeviceEntity>();
|
||||
saveEntity.Code = Guid.NewGuid();
|
||||
await _dbContext.InsertAsync(saveEntity);
|
||||
//保存注册信息
|
||||
var regis = await _dbContext.Queryable<DeviceRegistryEntity>()
|
||||
.Where(x => x.DeviceUniqueNo == form.UniqueNo)
|
||||
.FirstAsync();
|
||||
if(regis == null)
|
||||
{
|
||||
var custCode = places.Where(x => x.Code == form.PlaceeCode).Select(x => x.CustomCode).FirstOrDefault();
|
||||
regis = new DeviceRegistryEntity
|
||||
{
|
||||
DeviceUniqueNo = form.UniqueNo,
|
||||
LastHeartbeatTime = DateTime.Now,
|
||||
RegisterTime = DateTime.Now,
|
||||
BusinessPlaceCode = form.PlaceeCode,
|
||||
BusinessPlaceCustomCode = custCode
|
||||
};
|
||||
await _dbContext.InsertAsync(regis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//******************************************************** help methods **********************************************************
|
||||
|
||||
private async Task GenerateUploadRecordLogForBeginTimeAsync(DeviceEntity entity)
|
||||
{
|
||||
if (entity.Type == DeviceTypeEnumType.Door || entity.Type == DeviceTypeEnumType.Attendance)
|
||||
{
|
||||
var exists = await _dbContext.Queryable<DeviceUploadLogEntity>()
|
||||
.Where(x => x.DeviceUniqueNo == entity.UniqueNo)
|
||||
.Where(x => x.Type == DeviceUploadLogTypeEnumType.Raise)
|
||||
.AnyAsync();
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
await _dbContext.InsertAsync(new DeviceUploadLogEntity
|
||||
{
|
||||
DeviceUniqueNo = entity.UniqueNo,
|
||||
Type = DeviceUploadLogTypeEnumType.Raise,
|
||||
UserUniqueNo = string.Empty,
|
||||
RaiseDateTime = entity.CreateTime,
|
||||
|
||||
CreatedBy = 1,
|
||||
CreateTime = DateTime.Now,
|
||||
ModifiedBy = 1,
|
||||
ModifiedTime = DateTime.Now,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查设备模板是否存在
|
||||
/// </summary>
|
||||
@@ -148,14 +255,15 @@ public class DeviceService : IDeviceService
|
||||
/// <returns></returns>
|
||||
private async Task CheckUniqueNoExistsAsync(DeviceSaveRequest request)
|
||||
{
|
||||
var exists = await _dbContext.Queryable<DeviceEntity>().Where(x => x.UniqueNo == request.UniqueNo)
|
||||
var exists = await _dbContext.Queryable<DeviceEntity>()
|
||||
.Where(x => x.UniqueNo == request.UniqueNo)
|
||||
.WhereIF(request.Id.HasValue, x => x.Id != request.Id)
|
||||
.AnyAsync();
|
||||
|
||||
exists.ThrowIfTrue("唯一号已经存在");
|
||||
}
|
||||
|
||||
[IgnoreTenant]
|
||||
|
||||
public async Task<bool> CheckExistsAsync(string deviceUniqueNo)
|
||||
{
|
||||
return await _dbContext.Queryable<DeviceEntity>()
|
||||
@@ -187,36 +295,81 @@ public class DeviceService : IDeviceService
|
||||
{
|
||||
var devices = await _dbContext.Queryable<DeviceEntity>()
|
||||
.Where(x => x.Enable)
|
||||
.Where(x => x.Type == DeviceTypeEnumType.Attendance || (x.Type == DeviceTypeEnumType.Door && x.AsAttendance))
|
||||
.Select(x => new DeviceResponse
|
||||
{
|
||||
FuncsStr = x.Funcs.ToString()
|
||||
}, true)
|
||||
.ToListAsync();
|
||||
|
||||
return devices.Where(x => x.Funcs.Contains(DeviceFuncEnumType.Attendance)).ToList();
|
||||
return devices.Where(x => x.Type == DeviceTypeEnumType.Attendance).ToList();
|
||||
}
|
||||
|
||||
public async Task<DeviceNumberResponse> GetDeviceNumberAsync()
|
||||
{
|
||||
var devices = await _dbContext.Queryable<DeviceEntity>()
|
||||
.Where(x => x.Type == DeviceTypeEnumType.Attendance)
|
||||
.ToListAsync();
|
||||
var onlineNumber = devices.Where(x => x.Enable).Count();
|
||||
var offlineNumber = devices.Where(x => x.Enable == false).Count();
|
||||
var devices = await _dbContext.Queryable<DeviceEntity>().Where(x => x.Type == DeviceTypeEnumType.Attendance || (x.Type == DeviceTypeEnumType.Door && x.AsAttendance)).ToListAsync();
|
||||
|
||||
var offlineNumber = await GetOfflineDevicesCount(devices);
|
||||
|
||||
var res = new DeviceNumberResponse
|
||||
{
|
||||
OnlineNumber = onlineNumber,
|
||||
OfflineNumber = offlineNumber,
|
||||
TotalNumber = devices.Count()
|
||||
OfflineNumber = offlineNumber.Count,
|
||||
TotalNumber = devices.Count,
|
||||
OnlineNumber = devices.Count - offlineNumber.Count
|
||||
};
|
||||
return res;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取离线设备
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task<List<DeviceEntity>> GetOfflineDevicesCount(List<DeviceEntity> devices)
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
|
||||
var deviceUniqueNos = devices.Select(x => x.UniqueNo).ToList();
|
||||
|
||||
var deviceRegistries = await _dbContext.Queryable<DeviceRegistryEntity>()
|
||||
.LeftJoin<DeviceEntity>((x, d) => x.DeviceUniqueNo == d.UniqueNo)
|
||||
.Where(x => deviceUniqueNos.Contains(x.DeviceUniqueNo))
|
||||
.Select((x, d) => new
|
||||
{
|
||||
UniqueNo = d.UniqueNo,
|
||||
d.HeartbeatInterval,
|
||||
x.LastHeartbeatTime
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
var OnlineDevices = deviceRegistries
|
||||
.Where(x =>
|
||||
{
|
||||
if (x.HeartbeatInterval <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return x.LastHeartbeatTime.AddSeconds(x.HeartbeatInterval * 3) >= now;
|
||||
|
||||
})
|
||||
.Select(x => new
|
||||
{
|
||||
UniqueNo = x.UniqueNo,
|
||||
})
|
||||
.ToList();
|
||||
var onlineUniqueNos = new List<string>();
|
||||
OnlineDevices.ForEach(x => onlineUniqueNos.Add(x.UniqueNo));
|
||||
|
||||
var offUniqueNos = deviceUniqueNos.Except(onlineUniqueNos).ToList();
|
||||
var list = devices.Where(x => offUniqueNos.Contains(x.UniqueNo)).ToList();
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
public async Task<Pagination<DevicePageResponse>> GetAttendanceTotalAsync(AttendanceTotalRequest request)
|
||||
{
|
||||
var page = await _dbContext.Queryable<DeviceEntity>()
|
||||
.LeftJoin<DeviceTemplateEntity>((d, dt) => d.TemplateCode == dt.Code)
|
||||
.Where(d => d.Type == DeviceTypeEnumType.Attendance)
|
||||
.Where(d => d.Type == DeviceTypeEnumType.Attendance || (d.Type == DeviceTypeEnumType.Door && d.AsAttendance))
|
||||
.Select((d, dt) => new DevicePageResponse
|
||||
{
|
||||
FuncsStr = d.Funcs.ToString(),
|
||||
@@ -231,9 +384,37 @@ public class DeviceService : IDeviceService
|
||||
|
||||
public async Task<Pagination<DevicePageResponse>> GetAttendanceOfflineAsync(DeviceOnlineAndofflineRequest request)
|
||||
{
|
||||
var devices = await _dbContext.Queryable<DeviceEntity>().Where(x => x.Type == DeviceTypeEnumType.Attendance || (x.Type == DeviceTypeEnumType.Door && x.AsAttendance)).ToListAsync();
|
||||
|
||||
//离线
|
||||
var offDevices = await GetOfflineDevicesCount(devices);
|
||||
var offids = offDevices.Select(x => x.Id).ToList();
|
||||
|
||||
if (request.IsOnAndOff)
|
||||
{
|
||||
//离线
|
||||
var offpage = await _dbContext.Queryable<DeviceEntity>()
|
||||
.LeftJoin<DeviceTemplateEntity>((d, dt) => d.TemplateCode == dt.Code)
|
||||
.Where(d => d.Type == DeviceTypeEnumType.Attendance)
|
||||
.Where(d => offids.Contains(d.Id))
|
||||
.Select((d, dt) => new DevicePageResponse
|
||||
{
|
||||
FuncsStr = d.Funcs.ToString(),
|
||||
Brand = dt.Brand,
|
||||
Type = d.Type,
|
||||
|
||||
}, true)
|
||||
.ToPageListAsync(request);
|
||||
return offpage;
|
||||
}
|
||||
//在线
|
||||
var ids = devices.Select(x => x.Id).ToList();
|
||||
List<long> onids = ids.Except(offids).ToList();
|
||||
|
||||
var page = await _dbContext.Queryable<DeviceEntity>()
|
||||
.LeftJoin<DeviceTemplateEntity>((d, dt) => d.TemplateCode == dt.Code)
|
||||
.Where(d => d.Type == DeviceTypeEnumType.Attendance && d.Enable == request.IsOnAndOff)
|
||||
.Where(d => d.Type == DeviceTypeEnumType.Attendance)
|
||||
.Where(d => onids.Contains(d.Id))
|
||||
.Select((d, dt) => new DevicePageResponse
|
||||
{
|
||||
FuncsStr = d.Funcs.ToString(),
|
||||
@@ -246,7 +427,52 @@ public class DeviceService : IDeviceService
|
||||
return page;
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, int>> GetRecentNumbersAsync()
|
||||
public async Task<Pagination<DevicePageResponse>> GetDoorOfflineAsync(GetDoorOfflineRequest request)
|
||||
{
|
||||
var devices = await _dbContext.Queryable<DeviceEntity>().Where(x => x.Type == DeviceTypeEnumType.Door).ToListAsync();
|
||||
|
||||
var offDevices = await GetOfflineDevicesCount(devices);
|
||||
var offids = offDevices.Select(x => x.Id).ToList();
|
||||
|
||||
if (request.IsOnAndOff)
|
||||
{
|
||||
//离线
|
||||
var offpage = await _dbContext.Queryable<DeviceEntity>()
|
||||
.LeftJoin<DeviceTemplateEntity>((d, dt) => d.TemplateCode == dt.Code)
|
||||
.Where(d => d.Type == DeviceTypeEnumType.Door)
|
||||
.Where(d => offids.Contains(d.Id))
|
||||
.Select((d, dt) => new DevicePageResponse
|
||||
{
|
||||
FuncsStr = d.Funcs.ToString(),
|
||||
Brand = dt.Brand,
|
||||
Type = d.Type,
|
||||
|
||||
}, true)
|
||||
.ToPageListAsync(request);
|
||||
return offpage;
|
||||
}
|
||||
//在线
|
||||
var ids = devices.Select(x => x.Id).ToList();
|
||||
List<long> onids = ids.Except(offids).ToList();
|
||||
|
||||
var page = await _dbContext.Queryable<DeviceEntity>()
|
||||
.LeftJoin<DeviceTemplateEntity>((d, dt) => d.TemplateCode == dt.Code)
|
||||
.Where(d => d.Type == DeviceTypeEnumType.Door)
|
||||
.Where(d => onids.Contains(d.Id))
|
||||
.Select((d, dt) => new DevicePageResponse
|
||||
{
|
||||
FuncsStr = d.Funcs.ToString(),
|
||||
Brand = dt.Brand,
|
||||
Type = d.Type,
|
||||
|
||||
}, true)
|
||||
.ToPageListAsync(request);
|
||||
|
||||
return page;
|
||||
|
||||
}
|
||||
|
||||
public async Task<List<RecentNumberResponse>> GetRecentNumbersAsync()
|
||||
{
|
||||
//获取近30天并转化为"yyyy-MM-dd"集合
|
||||
DateTime currentDate = DateTime.Now;
|
||||
@@ -258,15 +484,84 @@ public class DeviceService : IDeviceService
|
||||
times.Add(dateString);
|
||||
}
|
||||
|
||||
var devices = await _dbContext.Queryable<DeviceEntity>().ToListAsync();
|
||||
var devices = await _dbContext.Queryable<DeviceEntity>().Where(x => x.Type == DeviceTypeEnumType.Attendance || (x.Type == DeviceTypeEnumType.Door && x.AsAttendance)).ToListAsync();
|
||||
|
||||
var dic = new Dictionary<string, int>();
|
||||
var list = new List<RecentNumberResponse>();
|
||||
times.ForEach(time =>
|
||||
{
|
||||
var count = devices.Where(x => x.CreateTime.ToString("yyyy-MM-dd") == time).Count();
|
||||
dic[time] = count;
|
||||
var res = new RecentNumberResponse
|
||||
{
|
||||
Date = time,
|
||||
Num = count,
|
||||
};
|
||||
list.Add(res);
|
||||
});
|
||||
return dic;
|
||||
|
||||
return list;
|
||||
}
|
||||
private List<ImportDeviceSaveRequest> ImportFromExcel(IFormFile formFile)
|
||||
{
|
||||
var requests = new List<ImportDeviceSaveRequest>();
|
||||
|
||||
using (var stream = formFile.OpenReadStream())
|
||||
{
|
||||
XSSFWorkbook workbook = new XSSFWorkbook(stream);
|
||||
ISheet sheet = workbook.GetSheetAt(0);
|
||||
|
||||
for (int rowIdx = 1; rowIdx <= sheet.LastRowNum; rowIdx++)
|
||||
{
|
||||
IRow row = sheet.GetRow(rowIdx);
|
||||
if (row == null) continue;
|
||||
|
||||
var request = new ImportDeviceSaveRequest();
|
||||
|
||||
request.UniqueNo = row.GetCell(0).ToString();
|
||||
request.TemplateCode = Guid.Parse(row.GetCell(1).ToString());
|
||||
request.Supplier = row.GetCell(2).ToString();
|
||||
|
||||
var funs = new List<DeviceFuncEnumType>();
|
||||
var fs = row.GetCell(3).ToString().Split(',');
|
||||
foreach (string str in fs)
|
||||
{
|
||||
switch (str)
|
||||
{
|
||||
case "1":
|
||||
funs.Add(DeviceFuncEnumType.Face);
|
||||
break;
|
||||
case "2":
|
||||
funs.Add(DeviceFuncEnumType.Card);
|
||||
break;
|
||||
case "3":
|
||||
funs.Add(DeviceFuncEnumType.QrCode);
|
||||
break;
|
||||
case "4":
|
||||
funs.Add(DeviceFuncEnumType.Control);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
request.Funcs = funs;
|
||||
request.Type = (DeviceTypeEnumType)Enum.Parse(typeof(DeviceTypeEnumType), row.GetCell(4).ToString());
|
||||
request.HeartbeatInterval = int.Parse(row.GetCell(5).ToString());
|
||||
request.DeployPlace = row.GetCell(6).ToString();
|
||||
request.DeployPosition = row.GetCell(7).ToString();
|
||||
request.DeployDirection = row.GetCell(8).ToString();
|
||||
request.ConnectionInfo = row.GetCell(9).ToString();
|
||||
request.Enable = Convert.ToBoolean(Convert.ToInt32(row.GetCell(10).ToString()));
|
||||
request.AsAttendance = Convert.ToBoolean(Convert.ToInt32(row.GetCell(11).ToString()));
|
||||
if (row.GetCell(12) != null)
|
||||
{
|
||||
request.PlaceeCode = Guid.Parse(row.GetCell(12)?.ToString());
|
||||
}
|
||||
requests.Add(request);
|
||||
}
|
||||
}
|
||||
|
||||
return requests;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ public class DeviceTemplateService : IDeviceTemplateService
|
||||
{
|
||||
var entity = await _dbContext.Queryable<DeviceTemplateEntity>().Where(x => x.Id == request.Id).FirstAsync();
|
||||
await ExistsDeviceUsingTemplateAsync(entity.Code);
|
||||
request.Adapt(entity);
|
||||
await _dbContext.UpdateAsync(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Kurisu.AspNetCore" Version="0.5.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="6.0.26" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.4" />
|
||||
<PackageReference Include="Kurisu.AspNetCore" Version="0.6.1" />
|
||||
<PackageReference Include="NPOI" Version="2.6.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -28,4 +27,8 @@
|
||||
<ProjectReference Include="..\Dlhis.Sys.Api\Dlhis.Sys.Api.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Summary\Request\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using Dlhis.Basic.Organization.Request;
|
||||
using Dlhis.Basic.Organization.Response;
|
||||
using Dlhis.Basic.Organization.Response;
|
||||
using Dlhis.Basic.Organization.Services;
|
||||
using Kurisu.AspNetCore.MVC;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
@@ -33,14 +31,4 @@ public class DepartmentsController : ControllerBase
|
||||
{
|
||||
return await _departmentService.GetTreeAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取部门树分页
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("treepage")]
|
||||
public async Task<Pagination<DepartmentTreeResponse>> GetTreePageAsync([FromQuery]DepartmentPageRequest request)
|
||||
{
|
||||
return await _departmentService.GetTreePageAsync(request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
using Dlhis.Basic.Organization.Request;
|
||||
using Dlhis.Basic.Organization.Response;
|
||||
using Dlhis.Basic.Organization.Services;
|
||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// 档案卡记录
|
||||
/// </summary>
|
||||
[Authorize]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class GainfoCardsController : ControllerBase
|
||||
{
|
||||
private readonly IGainfoCardService _gainfoCardService;
|
||||
|
||||
public GainfoCardsController(IGainfoCardService gainfoCardService)
|
||||
{
|
||||
_gainfoCardService = gainfoCardService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 换卡
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("change")]
|
||||
[Transactional]
|
||||
public async Task ChangeCardAsync(ChangeCardRequest request)
|
||||
{
|
||||
await _gainfoCardService.ChangeCardAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 换卡记录
|
||||
/// </summary>
|
||||
/// <param name="userNo"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("records")]
|
||||
public async Task<List<ChangeCardResponse>> GetChangeRecordsAsync(string userNo)
|
||||
{
|
||||
return await _gainfoCardService.GetChangeRecordsAsync(userNo);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using Dlhis.Basic.Organization.Request;
|
||||
using Dlhis.Basic.Organization.Response;
|
||||
using Dlhis.Basic.Organization.Services;
|
||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop;
|
||||
using Kurisu.AspNetCore.MVC;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
@@ -25,24 +25,14 @@ public class GainfoGroupsController : ControllerBase
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取档案组分页
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("page")]
|
||||
public async Task<Pagination<GainfoGroupResponse>> GetPageAsync([FromQuery] GainfoGroupPageRequest request)
|
||||
{
|
||||
return await _gainfoGroupService.GetPageAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有档案组
|
||||
/// 获取档案分组树
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("list")]
|
||||
public async Task<List<GainfoGroupResponse>> GetListAsync()
|
||||
[HttpGet("tree")]
|
||||
[IgnoreTenant]
|
||||
public async Task<List<GainfoGroupTreeResponse>> GetTreeAsync()
|
||||
{
|
||||
return await _gainfoGroupService.GetListAsync();
|
||||
return await _gainfoGroupService.GetTreeAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -50,7 +40,7 @@ public class GainfoGroupsController : ControllerBase
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[HttpPost("save")]
|
||||
public async Task SaveAsync(GainfoGroupSaveRequest request)
|
||||
{
|
||||
await _gainfoGroupService.SaveAsync(request);
|
||||
@@ -73,6 +63,8 @@ public class GainfoGroupsController : ControllerBase
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("assign")]
|
||||
[IgnoreTenant]
|
||||
[Transactional]
|
||||
public async Task AssignGainfosAsync(GainfoAssignRequest request)
|
||||
{
|
||||
await _gainfoGroupService.AssignGainfosAsync(request);
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
using Dlhis.Basic.Organization.Request;
|
||||
using Dlhis.Basic.Organization.Response;
|
||||
using Dlhis.Basic.Organization.Services;
|
||||
using Dlhis.Entity.Basic.Entity;
|
||||
using Kurisu.AspNetCore.MVC;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Org.BouncyCastle.Asn1.Ocsp;
|
||||
|
||||
namespace Dlhis.Basic.MealUser.Controllers;
|
||||
|
||||
@@ -43,8 +41,8 @@ public class GainfosController : ControllerBase
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("page")]
|
||||
public async Task<Pagination<GainfoPageResponse>> GetPageAsync([FromQuery] GainfoPageRequest request)
|
||||
[HttpPost("page")]
|
||||
public async Task<Pagination<GainfoPageResponse>> GetPageAsync(GainfoPageRequest request)
|
||||
{
|
||||
return await _gainfoService.GetPageAsync(request);
|
||||
}
|
||||
@@ -102,6 +100,17 @@ public class GainfosController : ControllerBase
|
||||
await _gainfoService.UploadFaceAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量上传人脸照片
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("batchface")]
|
||||
public async Task UploadFaceAsync(List<GainfoUploadFaceRequest> request)
|
||||
{
|
||||
await _gainfoService.UploadFacesAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过token获取人脸照片,失效或者找不到返回HttpStatus404状态码
|
||||
/// </summary>
|
||||
@@ -142,72 +151,21 @@ public class GainfosController : ControllerBase
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("gainfolist")]
|
||||
public async Task<Pagination<GainfoListResponse>> GetGainfoListTaskAsync([FromQuery]GainfoListRequest request)
|
||||
[HttpGet("list")]
|
||||
public async Task<Pagination<GainfoListResponse>> GetGainfoListTaskAsync([FromQuery] GainfoListRequest request)
|
||||
{
|
||||
return await _gainfoService.GetGainfoListTaskAsync(request);
|
||||
return await _gainfoService.GetGainfoListAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 档案详情
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("gainfodetail")]
|
||||
public async Task<GainfoDetailResponse> GetGainfoDetailTaskAsync([FromQuery] GainfoDetailRequest request)
|
||||
[HttpGet("detail")]
|
||||
public async Task<GainfoDetailResponse> GetGainfoDetailAsync([FromQuery] GainfoDetailRequest request)
|
||||
{
|
||||
return await _gainfoService.GetGainfoDetailTaskAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取近七天入职人数及列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("weeknumber")]
|
||||
public async Task<Dictionary<string, Pagination<GainfoDetailResponse>>> GetWeekNumberAsync([FromQuery] WeekNumberRequest request)
|
||||
{
|
||||
// 从请求头中获取 Token
|
||||
string token = HttpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
|
||||
|
||||
return await _gainfoService.GetWeekNumberAsync(request,token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取近七天离职人数及列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("weeknumberdimission")]
|
||||
public async Task<Dictionary<string, Pagination<GainfoDetailResponse>>> GetDimissionWeekNumberAsync([FromQuery] WeekNumberRequest request)
|
||||
{
|
||||
// 从请求头中获取 Token
|
||||
string token = HttpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
|
||||
|
||||
return await _gainfoService.GetDimissionWeekNumberAsync(request,token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取基地在职、离职、考勤数
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("gainfonumbers")]
|
||||
public async Task<GainfoGainfoNumbersResponse> GetGainfoNumbersAsync()
|
||||
{
|
||||
// 从请求头中获取 Token
|
||||
string token = HttpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
|
||||
|
||||
return await _gainfoService.GetGainfoNumbersAsync(token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取本基地管理员列表
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("administrator")]
|
||||
public async Task<Pagination<GainfoDetailResponse>> GetAdministratorAsync([FromQuery] WeekNumberRequest request)
|
||||
{
|
||||
// 从请求头中获取 Token
|
||||
string token = HttpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
|
||||
return await _gainfoService.GetAdministratorAsync(request,token);
|
||||
return await _gainfoService.GetGainfoDetailAsync(request);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Dlhis.Basic.Organization.Response;
|
||||
using Dlhis.Basic.Organization.Services;
|
||||
using Dlhis.User.Api.Response;
|
||||
using Dlhis.Basic.Organization.Services;
|
||||
using Dlhis.Sys.Api.Response;
|
||||
using Kurisu.AspNetCore.MVC;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
17
Src/Dlhis.Basic/Organization/Request/ChangeCardRequest.cs
Normal file
17
Src/Dlhis.Basic/Organization/Request/ChangeCardRequest.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Request;
|
||||
|
||||
public class ChangeCardRequest
|
||||
{
|
||||
[Required]
|
||||
public string UserNo { get; set; }
|
||||
|
||||
[Required]
|
||||
public string CardNo { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Reason { get; set; }
|
||||
|
||||
public string Remark { get; set; }
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Request
|
||||
{
|
||||
public class DepartmentPageRequest : PageDto
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,25 @@
|
||||
using Dlhis.Entity.Basic.Enums;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using SqlSugar;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Request
|
||||
{
|
||||
public class GainfoDetailRequest : PageDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 档案类型
|
||||
/// </summary>
|
||||
[Required]
|
||||
[EnumDataType(typeof(GainfoStatusEnumType))]
|
||||
public GainfoStatusEnumType Status { get; set; }
|
||||
namespace Dlhis.Basic.Organization.Request;
|
||||
|
||||
/// <summary>
|
||||
/// 档案号
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string No { get; set; }
|
||||
}
|
||||
public class GainfoDetailRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 档案类型
|
||||
/// </summary>
|
||||
[Required]
|
||||
[EnumDataType(typeof(GainfoStatusEnumType))]
|
||||
public GainfoStatusEnumType Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 档案号
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string No { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否需要人脸信息
|
||||
/// </summary>
|
||||
public bool WithFace { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Request;
|
||||
|
||||
public class GainfoGroupPageRequest: PageDto
|
||||
{
|
||||
}
|
||||
@@ -4,6 +4,11 @@ public class GainfoGroupSaveRequest
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上级
|
||||
/// </summary>
|
||||
public Guid? PCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
|
||||
@@ -10,10 +10,10 @@ public class GainfoPageRequest : PageDto
|
||||
/// 档案类型
|
||||
/// </summary>
|
||||
[EnumDataType(typeof(GainfoStatusEnumType))]
|
||||
public GainfoStatusEnumType Status { get; set; } = GainfoStatusEnumType.Working;
|
||||
public GainfoStatusEnumType? Status { get; set; } = GainfoStatusEnumType.Working;
|
||||
|
||||
/// <summary>
|
||||
/// 部门号(部门树传入)
|
||||
/// 部门选择
|
||||
/// </summary>
|
||||
public List<string> DepartmentNos { get; set; }
|
||||
public List<TenantDepartmentRequest> DepartmentSelections { get; set; } = new List<TenantDepartmentRequest>();
|
||||
}
|
||||
|
||||
@@ -110,11 +110,6 @@ public class GainfoSaveRequest : IValidatableObject
|
||||
/// </summary>
|
||||
public string Werks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 在职状态
|
||||
/// </summary>
|
||||
public string Employed { get; set; }
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (GainfoStatus.HasValue && GainfoStatus == GainfoStatusEnumType.Leave)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Request;
|
||||
|
||||
public class TenantDepartmentRequest
|
||||
{
|
||||
[Required]
|
||||
public string Tenant { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 部门号(部门树传入)
|
||||
/// </summary>
|
||||
public List<string> DepartmentNos { get; set; }
|
||||
}
|
||||
15
Src/Dlhis.Basic/Organization/Response/ChangeCardResponse.cs
Normal file
15
Src/Dlhis.Basic/Organization/Response/ChangeCardResponse.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Dlhis.Basic.Organization.Response;
|
||||
|
||||
public class ChangeCardResponse
|
||||
{
|
||||
public string UserNo { get; set; }
|
||||
public string UserCode { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string CardNo { get; set; }
|
||||
|
||||
public string Reason { get; set; }
|
||||
|
||||
public string Remark { get; set; }
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
}
|
||||
@@ -1,7 +1,14 @@
|
||||
namespace Dlhis.Basic.Organization.Response;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Response;
|
||||
|
||||
public class DepartmentTreeResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// 上级
|
||||
/// </summary>
|
||||
public string PNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 部门号
|
||||
/// </summary>
|
||||
@@ -12,8 +19,24 @@ public class DepartmentTreeResponse
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
public string Tenant { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 下级部门
|
||||
/// </summary>
|
||||
public List<DepartmentTreeResponse> Next { get; set; } = new List<DepartmentTreeResponse>();
|
||||
[JsonIgnore]
|
||||
public List<DepartmentTreeResponse> _Next { get; set; } = new List<DepartmentTreeResponse>();
|
||||
|
||||
/// <summary>
|
||||
/// 下级部门
|
||||
/// </summary>
|
||||
public List<DepartmentTreeResponse> Next
|
||||
{
|
||||
get
|
||||
{
|
||||
_Next.ForEach(x => x.Tenant = Tenant);
|
||||
return _Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,114 +1,125 @@
|
||||
using Dlhis.Entity.Basic.Enums;
|
||||
using SqlSugar;
|
||||
using SqlSugar.DbConvert;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Response
|
||||
namespace Dlhis.Basic.Organization.Response;
|
||||
|
||||
public class GainfoDetailResponse
|
||||
{
|
||||
public class GainfoDetailResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// 档案号
|
||||
/// </summary>
|
||||
public string No { get; set; }
|
||||
/// <summary>
|
||||
/// 档案号
|
||||
/// </summary>
|
||||
public string No { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// SAP内部编号
|
||||
/// </summary>
|
||||
public string SapNo { get; set; }
|
||||
/// <summary>
|
||||
/// SAP内部编号
|
||||
/// </summary>
|
||||
public string SapNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 姓名
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// 姓名
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 学工号
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
/// <summary>
|
||||
/// 学工号
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 部门名称
|
||||
/// </summary>
|
||||
public string DepartmentName { get; set; }
|
||||
/// <summary>
|
||||
/// 部门名称
|
||||
/// </summary>
|
||||
public string DepartmentName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 证件类型代码
|
||||
/// </summary>
|
||||
public string IdClass { get; set; }
|
||||
/// <summary>
|
||||
/// 证件类型代码
|
||||
/// </summary>
|
||||
public string IdClass { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 身份证号
|
||||
/// </summary>
|
||||
public string IdNo { get; set; }
|
||||
/// <summary>
|
||||
/// 证件类型名称
|
||||
/// </summary>
|
||||
public string ClassName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 性别
|
||||
/// </summary>
|
||||
public GenderEnumType Gender { get; set; }
|
||||
/// <summary>
|
||||
/// 身份证号
|
||||
/// </summary>
|
||||
public string IdNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 身份证籍贯
|
||||
/// </summary>
|
||||
public string NativeName { get; set; }
|
||||
/// <summary>
|
||||
/// 性别
|
||||
/// </summary>
|
||||
public GenderEnumType Gender { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 身份证地址
|
||||
/// </summary>
|
||||
public string Address { get; set; }
|
||||
/// <summary>
|
||||
/// 性别描述
|
||||
/// </summary>
|
||||
public string GenderCN => Gender.GetDescription();
|
||||
|
||||
/// <summary>
|
||||
/// 生日
|
||||
/// </summary>
|
||||
public DateTime Birthday { get; set; }
|
||||
/// <summary>
|
||||
/// 身份证籍贯
|
||||
/// </summary>
|
||||
public string NativeName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 手机号码
|
||||
/// </summary>
|
||||
public string Phone { get; set; }
|
||||
/// <summary>
|
||||
/// 身份证地址
|
||||
/// </summary>
|
||||
public string Address { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 岗位
|
||||
/// </summary>
|
||||
public string Position { get; set; }
|
||||
/// <summary>
|
||||
/// 生日
|
||||
/// </summary>
|
||||
public DateTime Birthday { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 职等
|
||||
/// </summary>
|
||||
public string Grade { get; set; }
|
||||
/// <summary>
|
||||
/// 手机号码
|
||||
/// </summary>
|
||||
public string Phone { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 学历
|
||||
/// </summary>
|
||||
public string Degree { get; set; }
|
||||
/// <summary>
|
||||
/// 岗位
|
||||
/// </summary>
|
||||
public string Position { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 人事范围
|
||||
/// </summary>
|
||||
public string Werks { get; set; }
|
||||
/// <summary>
|
||||
/// 职等
|
||||
/// </summary>
|
||||
public string Grade { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 成本中心
|
||||
/// </summary>
|
||||
public string CostId { get; set; }
|
||||
/// <summary>
|
||||
/// 学历
|
||||
/// </summary>
|
||||
public string Degree { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 已婚/未婚
|
||||
/// </summary>
|
||||
public string Marital { get; set; }
|
||||
/// <summary>
|
||||
/// 人事范围
|
||||
/// </summary>
|
||||
public string Werks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 国家
|
||||
/// </summary>
|
||||
public string CountryName { get; set; }
|
||||
/// <summary>
|
||||
/// 成本中心
|
||||
/// </summary>
|
||||
public string CostId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 已婚/未婚
|
||||
/// </summary>
|
||||
public string Marital { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 国家
|
||||
/// </summary>
|
||||
public string CountryName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 民族代码
|
||||
/// </summary>
|
||||
public string NationName { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 人脸base64
|
||||
/// </summary>
|
||||
public string Face { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 民族代码
|
||||
/// </summary>
|
||||
public string NationName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否在职
|
||||
/// </summary>
|
||||
public bool IsActive { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
namespace Dlhis.Basic.Organization.Response;
|
||||
|
||||
public class GainfoGroupResponse
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分组code
|
||||
/// </summary>
|
||||
public Guid Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Remark { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Response;
|
||||
|
||||
public class GainfoGroupTreeResponse
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public Guid? PCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分组code
|
||||
/// </summary>
|
||||
public Guid Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否可编辑
|
||||
/// </summary>
|
||||
public bool Editable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否为业务默认分组
|
||||
/// </summary>
|
||||
public bool IsDefault { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否允许设置下级
|
||||
/// </summary>
|
||||
public bool AbleSetNext => IsDefault;
|
||||
|
||||
|
||||
[JsonIgnore]
|
||||
public string TenantId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 下级数据
|
||||
/// </summary>
|
||||
public List<GainfoGroupTreeResponse> Next { get; set; }
|
||||
}
|
||||
@@ -1,60 +1,51 @@
|
||||
using Dlhis.Entity.Basic.Enums;
|
||||
using SqlSugar;
|
||||
using SqlSugar.DbConvert;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Response
|
||||
namespace Dlhis.Basic.Organization.Response;
|
||||
|
||||
public class GainfoListResponse
|
||||
{
|
||||
public class GainfoListResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// 档案号
|
||||
/// </summary>
|
||||
public string No { get; set; }
|
||||
/// <summary>
|
||||
/// 档案号
|
||||
/// </summary>
|
||||
public string No { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 姓名
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// 姓名
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 学工号
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
/// <summary>
|
||||
/// 学工号
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 身份证号
|
||||
/// </summary>
|
||||
public string IdNo { get; set; }
|
||||
/// <summary>
|
||||
/// 身份证号
|
||||
/// </summary>
|
||||
public string IdNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 性别
|
||||
/// </summary>
|
||||
public GenderEnumType Gender { get; set; }
|
||||
/// <summary>
|
||||
/// 性别
|
||||
/// </summary>
|
||||
public GenderEnumType Gender { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 手机号码
|
||||
/// </summary>
|
||||
public string Phone { get; set; }
|
||||
/// <summary>
|
||||
/// 手机号码
|
||||
/// </summary>
|
||||
public string Phone { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 部门编码
|
||||
/// </summary>
|
||||
public string DepartmentNo { get; set; }
|
||||
/// <summary>
|
||||
/// 部门编码
|
||||
/// </summary>
|
||||
public string DepartmentNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 部门名称
|
||||
/// </summary>
|
||||
public string DepartmentName { get; set; }
|
||||
/// <summary>
|
||||
/// 部门名称
|
||||
/// </summary>
|
||||
public string DepartmentName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 身份证地址
|
||||
/// </summary>
|
||||
public string Address { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 在职状态
|
||||
/// </summary>
|
||||
public string Employed { get; set; }
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 身份证地址
|
||||
/// </summary>
|
||||
public string Address { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
namespace Dlhis.Basic.Organization.Response;
|
||||
using Dlhis.Entity.Basic.Enums;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Response;
|
||||
|
||||
public class GainfoPageResponse
|
||||
{
|
||||
@@ -52,7 +55,8 @@ public class GainfoPageResponse
|
||||
/// <summary>
|
||||
/// 性别
|
||||
/// </summary>
|
||||
public string Gender { get; set; }
|
||||
public GenderEnumType Gender { get; set; }
|
||||
public string GenderDesc => Gender.GetDescription();
|
||||
|
||||
/// <summary>
|
||||
/// 生日
|
||||
@@ -108,9 +112,4 @@ public class GainfoPageResponse
|
||||
/// 人事范围
|
||||
/// </summary>
|
||||
public string Werks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 在职状态
|
||||
/// </summary>
|
||||
public string Employed { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
using Dlhis.Basic.Organization.Request;
|
||||
using Dlhis.Basic.Organization.Response;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Dlhis.Basic.Organization.Response;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Services;
|
||||
|
||||
public interface IDepartmentService : IScopeDependency
|
||||
{
|
||||
Task<List<DepartmentTreeResponse>> GetTreeAsync();
|
||||
|
||||
Task<Pagination<DepartmentTreeResponse>> GetTreePageAsync(DepartmentPageRequest request);
|
||||
}
|
||||
|
||||
11
Src/Dlhis.Basic/Organization/Services/IGainfoCardService.cs
Normal file
11
Src/Dlhis.Basic/Organization/Services/IGainfoCardService.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Dlhis.Basic.Organization.Request;
|
||||
using Dlhis.Basic.Organization.Response;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Services;
|
||||
|
||||
public interface IGainfoCardService
|
||||
{
|
||||
Task ChangeCardAsync(ChangeCardRequest request);
|
||||
|
||||
Task<List<ChangeCardResponse>> GetChangeRecordsAsync(string userNo);
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
using Dlhis.Basic.Organization.Request;
|
||||
using Dlhis.Basic.Organization.Response;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Services;
|
||||
|
||||
public interface IGainfoGroupService : IScopeDependency
|
||||
{
|
||||
Task<Pagination<GainfoGroupResponse>> GetPageAsync(GainfoGroupPageRequest request);
|
||||
|
||||
Task<List<GainfoGroupResponse>> GetListAsync();
|
||||
Task<List<GainfoGroupTreeResponse>> GetTreeAsync();
|
||||
|
||||
Task SaveAsync(GainfoGroupSaveRequest request);
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Dlhis.Basic.Organization.Request;
|
||||
using Dlhis.Basic.Organization.Response;
|
||||
using Dlhis.Entity.Basic.Entity;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
@@ -22,21 +21,15 @@ public interface IGainfoService : IScopeDependency
|
||||
|
||||
Task UploadFaceAsync(GainfoUploadFaceRequest request);
|
||||
|
||||
Task UploadFacesAsync(List<GainfoUploadFaceRequest> request);
|
||||
|
||||
Task<IActionResult> GetFaceAsync(string token);
|
||||
|
||||
Task<string> GetFaceByUserCodeAsync(string userCode);
|
||||
|
||||
Task<Dictionary<string, string>> GetFaceByUserCodesAsync(GetFaceByUserCodesRequest request);
|
||||
|
||||
Task<Pagination<GainfoListResponse>> GetGainfoListTaskAsync(GainfoListRequest request);
|
||||
Task<Pagination<GainfoListResponse>> GetGainfoListAsync(GainfoListRequest request);
|
||||
|
||||
Task<GainfoDetailResponse> GetGainfoDetailTaskAsync(GainfoDetailRequest request);
|
||||
|
||||
Task<Dictionary<string, Pagination<GainfoDetailResponse>>> GetWeekNumberAsync(WeekNumberRequest request, string token);
|
||||
|
||||
Task<Dictionary<string, Pagination<GainfoDetailResponse>>> GetDimissionWeekNumberAsync([FromQuery] WeekNumberRequest request, string token);
|
||||
|
||||
Task<GainfoGainfoNumbersResponse> GetGainfoNumbersAsync(string token);
|
||||
|
||||
Task<Pagination<GainfoDetailResponse>> GetAdministratorAsync(WeekNumberRequest request,string token);
|
||||
Task<GainfoDetailResponse> GetGainfoDetailAsync(GainfoDetailRequest request);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Dlhis.Basic.Organization.Services;
|
||||
/// </summary>
|
||||
public interface IGainfoStore : IScopeDependency
|
||||
{
|
||||
ISugarQueryable<GainfoEntity> Queryable(GainfoStatusEnumType? gainfoStatus);
|
||||
ISugarQueryable<GainfoEntity> Queryable(GainfoStatusEnumType? gainfoStatus = null);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Dlhis.User.Api.Response;
|
||||
using Dlhis.Sys.Api.Response;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Services;
|
||||
|
||||
|
||||
@@ -1,73 +1,60 @@
|
||||
using Dlhis.Basic.Organization.Request;
|
||||
using Dlhis.Basic.Organization.Response;
|
||||
using Dlhis.Basic.Organization.Response;
|
||||
using Dlhis.Entity.Basic.Entity;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Dlhis.Sys.Api;
|
||||
using Kurisu.SqlSugar.Services;
|
||||
using Mapster;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Services.Implements;
|
||||
|
||||
public class DepartmentService : IDepartmentService
|
||||
{
|
||||
private readonly IDbContext _dbContext;
|
||||
private readonly ITenantApi _tenantApi;
|
||||
|
||||
public DepartmentService(IDbContext dbContext)
|
||||
public DepartmentService(IDbContext dbContext, ITenantApi tenantApi)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
_tenantApi = tenantApi;
|
||||
}
|
||||
|
||||
public async Task<List<DepartmentTreeResponse>> GetTreeAsync()
|
||||
{
|
||||
var departments = await _dbContext.Queryable<DepartmentEntity>().ToListAsync();
|
||||
var departments = await _dbContext.Queryable<DepartmentEntity>().Select<DepartmentTreeResponse>().ToListAsync();
|
||||
//00001000 一定是这个开头的
|
||||
var tops = departments.Where(x => x.PNo == "00001000").Adapt<List<DepartmentTreeResponse>>();
|
||||
var tops = departments.Where(x => x.PNo == "00001000").ToList();
|
||||
|
||||
tops.ForEach(x =>
|
||||
{
|
||||
RecursionGetNext(x, departments);
|
||||
});
|
||||
|
||||
return tops;
|
||||
var myTenantResult = await _tenantApi.GetMyTenantsAsync();
|
||||
var tenants = myTenantResult.Data;
|
||||
|
||||
return tenants.Select(x => new DepartmentTreeResponse
|
||||
{
|
||||
Name = x.Name,
|
||||
No = x.Code,
|
||||
PNo = x.PCode,
|
||||
Tenant = x.Code,
|
||||
_Next = tops.Select(item =>
|
||||
{
|
||||
var i = item.Adapt<DepartmentTreeResponse>();
|
||||
i.PNo = x.Code;
|
||||
return i;
|
||||
|
||||
}).ToList()
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public async Task<Pagination<DepartmentTreeResponse>> GetTreePageAsync(DepartmentPageRequest request)
|
||||
private void RecursionGetNext(DepartmentTreeResponse current, List<DepartmentTreeResponse> data)
|
||||
{
|
||||
var departments = await _dbContext
|
||||
.Queryable<DepartmentEntity>()
|
||||
.WhereIF(!request.Search.IsEmpty(), x => x.Name.Contains(request.Search) || x.No.Contains(request.Search)).ToListAsync();
|
||||
|
||||
var tops = departments.Where(x => x.PNo.IsEmpty()).Adapt<List<DepartmentTreeResponse>>();
|
||||
|
||||
tops.ForEach(x =>
|
||||
{
|
||||
RecursionGetNext(x, departments);
|
||||
});
|
||||
|
||||
// 分页操作
|
||||
var startIndex = (request.PageIndex - 1) * request.PageSize;
|
||||
var pagedData = tops.Skip(startIndex).Take(request.PageSize).ToList();
|
||||
|
||||
var pagination = new Pagination<DepartmentTreeResponse>
|
||||
{
|
||||
PageIndex = request.PageIndex,
|
||||
PageSize = request.PageSize,
|
||||
Total = tops.Count, // 使用原始列表的总数进行分页
|
||||
Data = pagedData
|
||||
};
|
||||
|
||||
return pagination;
|
||||
|
||||
}
|
||||
|
||||
private void RecursionGetNext(DepartmentTreeResponse current, List<DepartmentEntity> departments)
|
||||
{
|
||||
var next = departments.Where(x => x.PNo == current.No).ToList();
|
||||
current.Next = next.Adapt<List<DepartmentTreeResponse>>();
|
||||
var next = data.Where(x => x.PNo == current.No).ToList();
|
||||
current._Next = next;
|
||||
foreach (var item in next)
|
||||
{
|
||||
RecursionGetNext(item.Adapt<DepartmentTreeResponse>(), departments);
|
||||
RecursionGetNext(item, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using Dlhis.Basic.Organization.Request;
|
||||
using Dlhis.Basic.Organization.Response;
|
||||
using Dlhis.Entity.Basic.Entity;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
using Kurisu.SqlSugar.Services;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Services.Implements;
|
||||
|
||||
public class GainfoCardService : IGainfoCardService
|
||||
{
|
||||
private readonly IDbContext _dbContext;
|
||||
private readonly IGainfoStore _gainfoStore;
|
||||
|
||||
public GainfoCardService(IDbContext dbContext, IGainfoStore gainfoStore)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
_gainfoStore = gainfoStore;
|
||||
}
|
||||
|
||||
public async Task ChangeCardAsync(ChangeCardRequest request)
|
||||
{
|
||||
var gainfo = await _gainfoStore.Queryable().Where(x => x.No == request.UserNo).FirstAsync();
|
||||
gainfo.ThrowIfNull("档案不存在");
|
||||
|
||||
gainfo.CardNo = request.CardNo;
|
||||
|
||||
await _gainfoStore.UpdateAsync(gainfo);
|
||||
await _dbContext.InsertAsync(new GainfoCardRecordEntity
|
||||
{
|
||||
UserNo = request.UserNo,
|
||||
CardNo = request.CardNo,
|
||||
Reason = request.Reason,
|
||||
Remark = request.Remark,
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<List<ChangeCardResponse>> GetChangeRecordsAsync(string userNo)
|
||||
{
|
||||
return await _dbContext.Queryable<GainfoCardRecordEntity>()
|
||||
.LeftJoin<GainfoEntity>((x, ga) => x.UserNo == ga.No)
|
||||
.Where(x => x.UserNo == userNo)
|
||||
.Select((x, ga) => new ChangeCardResponse
|
||||
{
|
||||
UserNo = x.UserNo,
|
||||
UserCode = ga.Code,
|
||||
UserName = ga.Name,
|
||||
CardNo = x.CardNo,
|
||||
Reason = x.Reason,
|
||||
Remark = x.Remark,
|
||||
CreateTime = x.CreateTime,
|
||||
})
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
using Dlhis.Basic.Organization.Request;
|
||||
using Dlhis.Basic.Device.Services;
|
||||
using Dlhis.Basic.Organization.Request;
|
||||
using Dlhis.Basic.Organization.Response;
|
||||
using Dlhis.Entity.Basic.Entity;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Kurisu.SqlSugar.Extensions;
|
||||
using Kurisu.Core.DataAccess.Entity;
|
||||
using Kurisu.Core.User.Abstractions;
|
||||
using Kurisu.SqlSugar.Services;
|
||||
using Mapster;
|
||||
|
||||
@@ -12,30 +13,50 @@ namespace Dlhis.Basic.Organization.Services.Implements;
|
||||
public class GainfoGroupService : IGainfoGroupService
|
||||
{
|
||||
private readonly IDbContext _dbContext;
|
||||
private readonly ICurrentUser _currentUser;
|
||||
private readonly IDevicePermissionService _devicePermissionService;
|
||||
|
||||
public GainfoGroupService(IDbContext dbContext)
|
||||
public GainfoGroupService(IDbContext dbContext, ICurrentUser currentUser, IDevicePermissionService devicePermissionService)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
_currentUser = currentUser;
|
||||
_devicePermissionService = devicePermissionService;
|
||||
}
|
||||
|
||||
public async Task<Pagination<GainfoGroupResponse>> GetPageAsync(GainfoGroupPageRequest request)
|
||||
public async Task<List<GainfoGroupTreeResponse>> GetTreeAsync()
|
||||
{
|
||||
return await _dbContext.Queryable<GainfoGroupEntity>()
|
||||
.Select<GainfoGroupResponse>()
|
||||
.ToPageListAsync(request);
|
||||
}
|
||||
var gainfoGroups = await _dbContext.Queryable<GainfoGroupEntity>()
|
||||
.Select<GainfoGroupTreeResponse>()
|
||||
.ToListAsync();
|
||||
|
||||
var tops = gainfoGroups.Where(x => !x.PCode.HasValue).ToList();
|
||||
tops.ForEach(x =>
|
||||
{
|
||||
RecursionGetNext(x, gainfoGroups);
|
||||
});
|
||||
|
||||
public async Task<List<GainfoGroupResponse>> GetListAsync()
|
||||
{
|
||||
return await _dbContext.Queryable<GainfoGroupEntity>()
|
||||
.Select<GainfoGroupResponse>()
|
||||
.ToListAsync();
|
||||
return tops;
|
||||
}
|
||||
|
||||
public async Task SaveAsync(GainfoGroupSaveRequest request)
|
||||
{
|
||||
await CheckDuplicateNameAsync(request);
|
||||
try
|
||||
{
|
||||
//todo
|
||||
_dbContext.Client.QueryFilter.ClearAndBackup<ITenantId>();
|
||||
var defaultGroup = await _dbContext.Queryable<GainfoGroupEntity>().Where(x => x.IsDefault).FirstAsync();
|
||||
|
||||
if (!request.PCode.HasValue)
|
||||
{
|
||||
request.PCode = defaultGroup.Code;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_dbContext.Client.QueryFilter.Restore();
|
||||
}
|
||||
|
||||
|
||||
if (!request.Id.HasValue)
|
||||
{
|
||||
@@ -47,7 +68,6 @@ public class GainfoGroupService : IGainfoGroupService
|
||||
{
|
||||
var entity = await _dbContext.Queryable<GainfoGroupEntity>().Where(x => x.Id == request.Id).SingleAsync();
|
||||
request.Adapt(entity);
|
||||
|
||||
await _dbContext.UpdateAsync(entity);
|
||||
}
|
||||
}
|
||||
@@ -69,18 +89,32 @@ public class GainfoGroupService : IGainfoGroupService
|
||||
|
||||
public async Task AssignGainfosAsync(GainfoAssignRequest request)
|
||||
{
|
||||
var relations = await _dbContext.Queryable<GainfoGroupRelationshipEntity>().Where(x => x.GroupCode == request.GroupCode).ToListAsync();
|
||||
await _dbContext.DeleteReallyAsync(relations);
|
||||
|
||||
request.UserNos = await _dbContext.Queryable<GainfoEntity>().Where(x => request.UserNos.Contains(x.No)).Select(x => x.No).ToListAsync();
|
||||
var entities = request.UserNos.Select(x => new GainfoGroupRelationshipEntity
|
||||
if (request.UserNos.IsPresent())
|
||||
{
|
||||
GroupCode = request.GroupCode,
|
||||
UserNo = x
|
||||
var pGrp = await _dbContext.Queryable<GainfoGroupEntity>().Where(x => x.Code == request.GroupCode).FirstAsync();
|
||||
(pGrp?.Editable == false && pGrp?.IsDefault == true).ThrowIfTrue("不可分配人员到当前分组");
|
||||
}
|
||||
|
||||
}).ToList();
|
||||
var existsNextGroup = await _dbContext.Queryable<GainfoGroupEntity>().Where(x => x.PCode == request.GroupCode).AnyAsync();
|
||||
existsNextGroup.ThrowIfTrue("存在下级分组,无法分配人员");
|
||||
|
||||
await _dbContext.InsertAsync(entities);
|
||||
await _devicePermissionService.GenerateDeviceTasksAsync(async () =>
|
||||
{
|
||||
var relations = await _dbContext.Queryable<GainfoGroupRelationshipEntity>().Where(x => x.GroupCode == request.GroupCode).ToListAsync();
|
||||
await _dbContext.DeleteReallyAsync(relations);
|
||||
|
||||
request.UserNos = await _dbContext.Queryable<GainfoEntity>().Where(x => request.UserNos.Contains(x.No)).Select(x => x.No).ToListAsync();
|
||||
var entities = request.UserNos.Select(x => new GainfoGroupRelationshipEntity
|
||||
{
|
||||
GroupCode = request.GroupCode,
|
||||
UserNo = x,
|
||||
|
||||
|
||||
}).ToList();
|
||||
|
||||
await _dbContext.InsertAsync(entities);
|
||||
|
||||
}, null);
|
||||
}
|
||||
|
||||
//******************************************************* help methods ***********************************************************
|
||||
@@ -99,4 +133,32 @@ public class GainfoGroupService : IGainfoGroupService
|
||||
|
||||
exists.ThrowIfTrue($"重复组名{request.Name}");
|
||||
}
|
||||
|
||||
|
||||
private void RecursionGetNext(GainfoGroupTreeResponse current, List<GainfoGroupTreeResponse> gainfoGroups)
|
||||
{
|
||||
var currentTenantId = _currentUser.GetStringTenantId();
|
||||
var next = gainfoGroups.Where(x =>
|
||||
{
|
||||
if (x.PCode == current.Code)
|
||||
{
|
||||
if (x.TenantId.IsEmpty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return x.TenantId == currentTenantId;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}).ToList();
|
||||
current.Next = next;
|
||||
foreach (var item in next)
|
||||
{
|
||||
RecursionGetNext(item, gainfoGroups);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,19 +4,17 @@ using Dlhis.Basic.Organization.Response;
|
||||
using Dlhis.Entity.Basic.Entity;
|
||||
using Dlhis.Entity.Basic.Enums;
|
||||
using Dlhis.Entity.Device.Enums;
|
||||
using Kurisu.AspNetCore.Scope;
|
||||
using Kurisu.AspNetCore.UnifyResultAndValidation;
|
||||
using Kurisu.AspNetCore.Utils;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Kurisu.Core.User.Abstractions;
|
||||
using Kurisu.SqlSugar.Attributes;
|
||||
using Kurisu.SqlSugar.Extensions;
|
||||
using Kurisu.SqlSugar.Options;
|
||||
using Kurisu.SqlSugar.Services;
|
||||
using Mapster;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace Dlhis.Basic.Organization.Services.Implements;
|
||||
|
||||
@@ -26,18 +24,27 @@ public class GainfoService : IGainfoService
|
||||
private readonly IDbContext _dbContext;
|
||||
private readonly ICurrentUser _currentUser;
|
||||
private readonly IDevicePermissionService _devicePermissionService;
|
||||
private readonly RedisCache _redisCache;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly ILogger<GainfoService> _logger;
|
||||
|
||||
public GainfoService(IGainfoStore gainfoStore,
|
||||
IDbContext dbContext,
|
||||
ICurrentUser currentUser,
|
||||
IDevicePermissionService devicePermissionService,
|
||||
RedisCache redisCache,
|
||||
IServiceProvider serviceProvider,
|
||||
IConfiguration configuration,
|
||||
ILogger<GainfoService> logger)
|
||||
{
|
||||
_gainfoStore = gainfoStore;
|
||||
_dbContext = dbContext;
|
||||
_currentUser = currentUser;
|
||||
_devicePermissionService = devicePermissionService;
|
||||
_redisCache = redisCache;
|
||||
_serviceProvider = serviceProvider;
|
||||
_configuration = configuration;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -48,16 +55,28 @@ public class GainfoService : IGainfoService
|
||||
/// <returns></returns>
|
||||
public async Task<Pagination<GainfoPageResponse>> GetPageAsync(GainfoPageRequest request)
|
||||
{
|
||||
request.DepartmentNos = await GetRecursionDepartmentNosAsync(request.DepartmentNos);
|
||||
var currentTenantId = _currentUser.GetStringTenantId();
|
||||
|
||||
var tenant = _currentUser.GetStringTenantId();
|
||||
//根据组织架构搜索档案
|
||||
Expression<Func<GainfoEntity, bool>> where = LinqExpressionExtension.False<GainfoEntity>();
|
||||
foreach (var item in request.DepartmentSelections)
|
||||
{
|
||||
var depts = await GetRecursionDepartmentNosAsync(item.DepartmentNos);
|
||||
if (depts.Any())
|
||||
where = where.Or(gainfo => gainfo.Factory == item.Tenant && depts.Contains(gainfo.DepartmentNo));
|
||||
else
|
||||
where = where.Or(gainfo => gainfo.Factory == item.Tenant);
|
||||
}
|
||||
|
||||
var page = await _gainfoStore.Queryable(request.Status)
|
||||
.WhereIF(request.DepartmentNos?.Any() == true, gainfo => request.DepartmentNos.Contains(gainfo.DepartmentNo))
|
||||
.WhereIF(request.DepartmentSelections.IsPresent(), where)
|
||||
.WhereIF(request.DepartmentSelections.IsEmpty(), gainfo => gainfo.Factory == currentTenantId)
|
||||
.WhereIF(request.Search.IsPresent(), gainfo =>
|
||||
gainfo.Name.Contains(request.Search)
|
||||
|| gainfo.Code.Contains(request.Search))
|
||||
.Where(gainfo => gainfo.Werks == tenant)
|
||||
gainfo.Name.Contains(request.Search)
|
||||
|| gainfo.Code.Contains(request.Search)
|
||||
|| gainfo.IdNo.Contains(request.Search)
|
||||
|| gainfo.Werks.Contains(request.Search)
|
||||
)
|
||||
.Select<GainfoPageResponse>()
|
||||
.ToPageListAsync(request);
|
||||
|
||||
@@ -104,7 +123,6 @@ public class GainfoService : IGainfoService
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[Transactional]
|
||||
public async Task DimissionAsync(GainfoDimissionRequest request)
|
||||
{
|
||||
var gainfo = await _gainfoStore.Queryable(GainfoStatusEnumType.Working)
|
||||
@@ -140,11 +158,19 @@ public class GainfoService : IGainfoService
|
||||
public async Task<GainfoCurrentResponse> CurrentUserInfoAsync()
|
||||
{
|
||||
var identityId = _currentUser.GetIntSubjectId();
|
||||
var code = _currentUser.GetUserClaim("jinko-code");
|
||||
var gainfo = await _gainfoStore.Queryable().Where(x => x.Code == code).FirstAsync()
|
||||
?? await _gainfoStore.Queryable().Where(x => x.IdentityUserId == identityId).FirstAsync();
|
||||
|
||||
var gainfo = await _gainfoStore.Queryable(GainfoStatusEnumType.Working)
|
||||
if (gainfo == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var info = await _gainfoStore.Queryable(GainfoStatusEnumType.Working)
|
||||
.LeftJoin<DepartmentEntity>((ga, department) => ga.DepartmentNo == department.No)
|
||||
.LeftJoin<CanteenUserEntity>((ga, department, mealUser) => ga.No == mealUser.UserNo)
|
||||
.Where((ga, department) => ga.IdentityUserId == identityId)
|
||||
.Where((ga, department) => ga.Id == gainfo.Id)
|
||||
.Select((ga, department, mealUser) => new GainfoCurrentResponse
|
||||
{
|
||||
UserNo = ga.No,
|
||||
@@ -161,49 +187,43 @@ public class GainfoService : IGainfoService
|
||||
})
|
||||
.FirstAsync();
|
||||
|
||||
return gainfo;
|
||||
return info;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> GetFaceAsync(string token)
|
||||
{
|
||||
return await Scoped.Request.Value.CreateAsync<IActionResult>(async (sp) =>
|
||||
var timeLimitedDataProtector = _serviceProvider.GetService<IDataProtectionProvider>()
|
||||
.CreateProtector("down:face")
|
||||
.ToTimeLimitedDataProtector();
|
||||
|
||||
try
|
||||
{
|
||||
var timeLimitedDataProtector = sp.GetService<IDataProtectionProvider>()
|
||||
.CreateProtector("down:face")
|
||||
.ToTimeLimitedDataProtector();
|
||||
var password = timeLimitedDataProtector.Unprotect(token);
|
||||
var userCode = password.Split(':')[1];
|
||||
|
||||
try
|
||||
var faceCache = await _redisCache.HashGetAsync("faces", userCode);
|
||||
if (faceCache.HasValue)
|
||||
{
|
||||
var password = timeLimitedDataProtector.Unprotect(token);
|
||||
var userCode = password.Split(':')[1];
|
||||
|
||||
var configuration = sp.GetService<IConfiguration>();
|
||||
var faceConnectionString = configuration.GetSection("SqlSugarOptions:FaceConnectionString").Value;
|
||||
if (faceConnectionString.IsEmpty())
|
||||
{
|
||||
_logger.LogWarning("暂不支持获取人脸");
|
||||
return new NotFoundResult();
|
||||
}
|
||||
|
||||
//todo 切换连接字符串
|
||||
var dbContext = sp.GetService<IDbContext>();
|
||||
dbContext.Client.CurrentConnectionConfig.ConnectionString = faceConnectionString;
|
||||
var face = await dbContext.Queryable<GainfoFaceEntity>().Where(x => x.UserCode == userCode).SingleAsync();
|
||||
|
||||
if (face == null)
|
||||
{
|
||||
_logger.LogWarning("学工号:{userCode}不存在人脸照片", userCode);
|
||||
return new NotFoundResult();
|
||||
}
|
||||
|
||||
return new FileContentResult(Convert.FromBase64String(face.Face), "image/png");
|
||||
return new FileContentResult(Convert.FromBase64String(faceCache), "image/png");
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
var dbContext = _dbContext.ChangeDb("face");
|
||||
var face = await dbContext.Queryable<GainfoFaceEntity>().Where(x => x.UserCode == userCode).SingleAsync();
|
||||
|
||||
if (face == null)
|
||||
{
|
||||
_logger.LogError(ex, "获取人脸失败:" + ex.Message);
|
||||
_logger.LogWarning("学工号:{userCode}不存在人脸照片", userCode);
|
||||
return new NotFoundResult();
|
||||
}
|
||||
});
|
||||
|
||||
await _redisCache.HashSetAsync("faces", userCode, face.Face);
|
||||
return new FileContentResult(Convert.FromBase64String(face.Face), "image/png");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "获取人脸失败:{message}", ex.Message);
|
||||
return new NotFoundResult();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UploadFaceAsync(GainfoUploadFaceRequest request)
|
||||
@@ -213,21 +233,53 @@ public class GainfoService : IGainfoService
|
||||
|
||||
gainfo.ThrowIfNull("人员档案信息不存在");
|
||||
|
||||
await Scoped.Request.Value.CreateAsync(async (sp) =>
|
||||
var dbContext = _dbContext.ChangeDb("face");
|
||||
var face = await dbContext.Queryable<GainfoFaceEntity>().Where(x => x.UserCode == gainfo.Code).SingleAsync();
|
||||
|
||||
var taskType = face == null ? DeviceTaskEnumType.Add : DeviceTaskEnumType.Update;
|
||||
|
||||
await _redisCache.HashSetAsync("faces", gainfo.Code, request.Face);
|
||||
if (face == null)
|
||||
{
|
||||
var configuration = sp.GetService<IConfiguration>();
|
||||
var faceConnectionString = configuration.GetSection("SqlSugarOptions:FaceConnectionString").Value;
|
||||
if (faceConnectionString.IsEmpty())
|
||||
face = new GainfoFaceEntity
|
||||
{
|
||||
throw new UserFriendlyException("暂不支持人脸上传");
|
||||
UserCode = gainfo.Code,
|
||||
Face = request.Face
|
||||
};
|
||||
|
||||
await dbContext.InsertAsync(face);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (face.Face == request.Face)
|
||||
{
|
||||
_logger.LogWarning("相同的人脸照片更新忽略");
|
||||
return;
|
||||
}
|
||||
|
||||
var dbContext = sp.GetService<IDbContext>();
|
||||
//todo 切换连接字符串
|
||||
dbContext.Client.CurrentConnectionConfig.ConnectionString = faceConnectionString;
|
||||
face.Face = request.Face;
|
||||
await dbContext.UpdateAsync(face);
|
||||
}
|
||||
|
||||
//生成任务
|
||||
await _devicePermissionService.GenerateDeviceTasksAsync(gainfo.No, taskType);
|
||||
}
|
||||
|
||||
public async Task UploadFacesAsync(List<GainfoUploadFaceRequest> requests)
|
||||
{
|
||||
foreach (var request in requests)
|
||||
{
|
||||
var gainfo = await _gainfoStore.Queryable(GainfoStatusEnumType.Working).Where(x => x.No == request.UserNo).FirstAsync();
|
||||
gainfo ??= await _gainfoStore.Queryable(GainfoStatusEnumType.External).Where(x => x.No == request.UserNo).FirstAsync();
|
||||
|
||||
gainfo.ThrowIfNull("人员档案信息不存在");
|
||||
|
||||
var dbContext = _dbContext.ChangeDb("face");
|
||||
var face = await dbContext.Queryable<GainfoFaceEntity>().Where(x => x.UserCode == gainfo.Code).SingleAsync();
|
||||
|
||||
var taskType = face == null ? DeviceTaskEnumType.Add : DeviceTaskEnumType.Update;
|
||||
|
||||
await _redisCache.HashSetAsync("faces", gainfo.Code, request.Face);
|
||||
if (face == null)
|
||||
{
|
||||
face = new GainfoFaceEntity
|
||||
@@ -252,49 +304,33 @@ public class GainfoService : IGainfoService
|
||||
|
||||
//生成任务
|
||||
await _devicePermissionService.GenerateDeviceTasksAsync(gainfo.No, taskType);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<string> GetFaceByUserCodeAsync(string userCode)
|
||||
{
|
||||
var gainfo = await _dbContext.Queryable<GainfoEntity>().Where(x => x.Code == userCode).SingleAsync();
|
||||
gainfo.ThrowIfNull($"{userCode}人员信息不存在");
|
||||
|
||||
return await Scoped.Request.Value.CreateAsync<string>(async (sp) =>
|
||||
{
|
||||
var configuration = sp.GetService<IConfiguration>();
|
||||
var dbContext = _dbContext.ChangeDb("face");
|
||||
|
||||
var faceConnectionString = configuration.GetSection($"{nameof(SqlSugarOptions)}:FaceConnectionString").Value;
|
||||
if (faceConnectionString.IsEmpty())
|
||||
{
|
||||
throw new UserFriendlyException("暂不支持获取人脸");
|
||||
}
|
||||
var face = await dbContext.Queryable<GainfoFaceEntity>()
|
||||
.Where(x => x.UserCode == userCode)
|
||||
.SingleAsync();
|
||||
|
||||
var dbContext = sp.GetService<IDbContext>();
|
||||
//todo 切换连接字符串
|
||||
dbContext.Client.CurrentConnectionConfig.ConnectionString = faceConnectionString;
|
||||
face.ThrowIfNull("人脸照片尚未录入");
|
||||
|
||||
var face = await dbContext.Queryable<GainfoFaceEntity>()
|
||||
.Where(x => x.UserCode == userCode)
|
||||
.SingleAsync();
|
||||
var timeLimitedDataProtector = _serviceProvider.GetService<IDataProtectionProvider>()
|
||||
.CreateProtector("down:face")
|
||||
.ToTimeLimitedDataProtector();
|
||||
|
||||
face.ThrowIfNull("人脸照片尚未录入");
|
||||
var faceUrl = _configuration.GetSection("FaceUrlOptions:Url").Value;
|
||||
var limit = _configuration.GetSection("FaceUrlOptions:Limit").Get<int>();
|
||||
|
||||
var timeLimitedDataProtector = sp.GetService<IDataProtectionProvider>()
|
||||
.CreateProtector("down:face")
|
||||
.ToTimeLimitedDataProtector();
|
||||
var key = $"face:{userCode}";
|
||||
var token = timeLimitedDataProtector.Protect(key, TimeSpan.FromSeconds(limit));
|
||||
|
||||
var faceUrl = configuration.GetSection("FaceUrlOptions:Url").Value;
|
||||
var limit = configuration.GetSection("FaceUrlOptions:Limit").Get<int>();
|
||||
var dataProtectionProvider = sp.GetService<IDataProtectionProvider>();
|
||||
|
||||
var key = $"face:{userCode}";
|
||||
var token = timeLimitedDataProtector.Protect(key, TimeSpan.FromSeconds(limit));
|
||||
|
||||
return faceUrl + token;
|
||||
});
|
||||
return faceUrl + token;
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, string>> GetFaceByUserCodesAsync(GetFaceByUserCodesRequest request)
|
||||
@@ -314,7 +350,7 @@ public class GainfoService : IGainfoService
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Pagination<GainfoListResponse>> GetGainfoListTaskAsync(GainfoListRequest request)
|
||||
public async Task<Pagination<GainfoListResponse>> GetGainfoListAsync(GainfoListRequest request)
|
||||
{
|
||||
var page = await _gainfoStore.Queryable(request.Status)
|
||||
.LeftJoin<DepartmentEntity>((ga, de) => ga.DepartmentNo == de.No)
|
||||
@@ -333,25 +369,26 @@ public class GainfoService : IGainfoService
|
||||
DepartmentNo = de.No,
|
||||
DepartmentName = de.Name,
|
||||
Address = ga.Address,
|
||||
Employed = ga.Employed
|
||||
}).ToPageListAsync(request);
|
||||
return page;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 档案详情
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<GainfoDetailResponse> GetGainfoDetailTaskAsync(GainfoDetailRequest request)
|
||||
public async Task<GainfoDetailResponse> GetGainfoDetailAsync(GainfoDetailRequest request)
|
||||
{
|
||||
var info = await _gainfoStore.Queryable(request.Status)
|
||||
.LeftJoin<DepartmentEntity>((ga, de) => ga.DepartmentNo == de.No)
|
||||
.LeftJoin<BasicTypeEntity>((ga, de, type) => ga.Native == type.Code && type.Type == "native")
|
||||
.LeftJoin<PositionEntity>((ga, de, type, posi) => ga.Position == posi.Name)
|
||||
.LeftJoin<BasicTypeEntity>((ga, de, type, posi, type2) => ga.CountryNo == type2.Code && type2.Type == "country")
|
||||
.LeftJoin<BasicTypeEntity>((ga, de, type, posi, type2, type3) => ga.Nation == type3.Code && type3.Type == "nation")
|
||||
.LeftJoin<BasicTypeEntity>((ga, de, type, posi, type2, type3) => ga.Nation == type3.Code && type3.Type == "nation")
|
||||
.LeftJoin<BasicTypeEntity>((ga, de, type, posi, type2, type3, type4) => ga.IdClass == type4.Code && type4.Type == "cls")
|
||||
.Where(ga => ga.No == request.No)
|
||||
.Select((ga, de, type, posi, type2, type3) => new GainfoDetailResponse
|
||||
.Select((ga, de, type, posi, type2, type3, type4) => new GainfoDetailResponse
|
||||
{
|
||||
No = ga.No,
|
||||
SapNo = ga.SapNo,
|
||||
@@ -370,11 +407,21 @@ public class GainfoService : IGainfoService
|
||||
Degree = ga.Degree,
|
||||
Werks = ga.Werks,
|
||||
CostId = ga.CostId,
|
||||
Marital = ga.Marital,
|
||||
Marital = ga.Marital == "Single" ? "未婚" : "已婚",
|
||||
CountryName = type2.Display,
|
||||
NationName = type3.Display,
|
||||
IsActive = ga.Employed == "Active" ? true : false,
|
||||
}).FirstAsync();
|
||||
ClassName = type4.Display,
|
||||
})
|
||||
.FirstAsync();
|
||||
|
||||
if (info != null)
|
||||
{
|
||||
if (request.WithFace)
|
||||
{
|
||||
info.Face = await _dbContext.ChangeDb("face").Queryable<GainfoFaceEntity>().Where(x => x.UserCode == info.Code).Select(x => x.Face).SingleAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -425,11 +472,8 @@ public class GainfoService : IGainfoService
|
||||
Marital = ga.Marital,
|
||||
CountryName = type2.Display,
|
||||
NationName = type3.Display,
|
||||
IsActive = ga.Employed == "Active" ? true : false,
|
||||
}).ToPageListAsync(request);
|
||||
//var infos = await _gainfoStore.Queryable(GainfoStatusEnumType.Working)
|
||||
// .Where(ga => ga.CreateTime.ToString("yyyy-MM-dd") == time)
|
||||
// .ToPageListAsync(request);
|
||||
|
||||
dic[time] = infos;
|
||||
}
|
||||
return dic;
|
||||
@@ -481,7 +525,6 @@ public class GainfoService : IGainfoService
|
||||
Marital = ga.Marital,
|
||||
CountryName = type2.Display,
|
||||
NationName = type3.Display,
|
||||
IsActive = ga.Employed == "Active" ? true : false,
|
||||
}).ToPageListAsync(request);
|
||||
dic[time] = infos;
|
||||
}
|
||||
@@ -514,44 +557,6 @@ public class GainfoService : IGainfoService
|
||||
return res;
|
||||
}
|
||||
|
||||
public async Task<Pagination<GainfoDetailResponse>> GetAdministratorAsync( WeekNumberRequest request, string token)
|
||||
{
|
||||
var werks = GetClaimValueFromToken(token, "tenant");
|
||||
var info = await _gainfoStore.Queryable(GainfoStatusEnumType.Working)
|
||||
.LeftJoin<DepartmentEntity>((ga, de) => ga.DepartmentNo == de.No)
|
||||
.LeftJoin<BasicTypeEntity>((ga, de, type) => ga.Native == type.Code && type.Type == "native")
|
||||
.LeftJoin<PositionEntity>((ga, de, type, posi) => ga.Position == posi.Name)
|
||||
.LeftJoin<BasicTypeEntity>((ga, de, type, posi, type2) => ga.CountryNo == type2.Code && type2.Type == "country")
|
||||
.LeftJoin<BasicTypeEntity>((ga, de, type, posi, type2, type3) => ga.Nation == type3.Code && type3.Type == "nation")
|
||||
.Where(ga => ga.Werks == werks && ga.IdentityUserId != 0)
|
||||
.Select((ga, de, type, posi, type2, type3) => new GainfoDetailResponse
|
||||
{
|
||||
No = ga.No,
|
||||
SapNo = ga.SapNo,
|
||||
Name = ga.Name,
|
||||
Code = ga.Code,
|
||||
DepartmentName = de.Name,
|
||||
IdClass = ga.IdClass,
|
||||
IdNo = ga.IdNo,
|
||||
Gender = ga.Gender,
|
||||
NativeName = type.Display,
|
||||
Address = ga.Address,
|
||||
Birthday = ga.Birthday,
|
||||
Phone = ga.Phone,
|
||||
Position = ga.Position,
|
||||
Grade = posi.Grade,
|
||||
Degree = ga.Degree,
|
||||
Werks = ga.Werks,
|
||||
CostId = ga.CostId,
|
||||
Marital = ga.Marital,
|
||||
CountryName = type2.Display,
|
||||
NationName = type3.Display,
|
||||
IsActive = ga.Employed == "Active" ? true : false,
|
||||
}).ToPageListAsync(request);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
//-------------------------------------------help methods ------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
@@ -561,7 +566,7 @@ public class GainfoService : IGainfoService
|
||||
/// <returns></returns>
|
||||
private async Task<List<string>> GetRecursionDepartmentNosAsync(List<string> departmentNos)
|
||||
{
|
||||
if (departmentNos == null || departmentNos.Count == 0)
|
||||
if (departmentNos.IsEmpty())
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
@@ -579,13 +584,10 @@ public class GainfoService : IGainfoService
|
||||
void RecursionGetNext(string currentCode, List<DepartmentEntity> departments, List<string> result)
|
||||
{
|
||||
var next = departments.Where(x => x.PNo == currentCode).ToList();
|
||||
foreach (var item in next)
|
||||
{
|
||||
result.Add(item.No);
|
||||
}
|
||||
|
||||
foreach (var item in next)
|
||||
{
|
||||
result.Add(item.No);
|
||||
RecursionGetNext(item.No, departments, result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Dlhis.Sys.Api;
|
||||
using Dlhis.User.Api.Response;
|
||||
using Dlhis.Sys.Api.Response;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
using Kurisu.Core.Result;
|
||||
using Kurisu.Core.User.Abstractions;
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using Dlhis.Entity.Basic.Entity;
|
||||
using Kurisu.AspNetCore;
|
||||
using Kurisu.AspNetCore.Startup;
|
||||
using Kurisu.Core.DataAccess.Entity;
|
||||
using Kurisu.SqlSugar.Extensions;
|
||||
using Kurisu.SqlSugar.Services;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using SqlSugar;
|
||||
|
||||
namespace Dlhis.Basic.Packs;
|
||||
@@ -12,25 +15,57 @@ public class SqlSugarPack : BaseAppPack
|
||||
|
||||
public override void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSqlSugar();
|
||||
services.AddSqlSugar(sp =>
|
||||
{
|
||||
var configuration = sp.GetService<IConfiguration>();
|
||||
|
||||
return new List<ConnectionConfig>
|
||||
{
|
||||
new ConnectionConfig
|
||||
{
|
||||
ConfigId = "face",
|
||||
|
||||
ConnectionString = configuration.GetSection("SqlSugarOptions:FaceConnectionString").Value,
|
||||
DbType = DbType.MySql,
|
||||
InitKeyType = InitKeyType.Attribute,
|
||||
IsAutoCloseConnection = true,
|
||||
|
||||
MoreSettings = new ConnMoreSettings
|
||||
{
|
||||
DisableNvarchar = true,
|
||||
}
|
||||
},
|
||||
new ConnectionConfig
|
||||
{
|
||||
ConfigId = "log",
|
||||
|
||||
ConnectionString = configuration.GetSection("SqlSugarOptions:LogConnectionString").Value,
|
||||
DbType = DbType.MySql,
|
||||
InitKeyType = InitKeyType.Attribute,
|
||||
IsAutoCloseConnection = true,
|
||||
|
||||
MoreSettings = new ConnMoreSettings
|
||||
{
|
||||
DisableNvarchar = true,
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public override void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
//using var scope = app.ApplicationServices.CreateScope();
|
||||
//var db = scope.ServiceProvider.GetService<ISqlSugarClient>();
|
||||
//var tables = App.ActiveTyps.Where(x => x.IsDefined(typeof(SugarTable), false))
|
||||
// .Where(x => !x.IsDefined(typeof(SkipScanAttribute), false))
|
||||
// .ToArray();
|
||||
using var scope = app.ApplicationServices.CreateScope();
|
||||
var db = scope.ServiceProvider.GetService<IDbContext>();
|
||||
var tables = App.ActiveTyps.Where(x => x.IsDefined(typeof(SugarTable), false))
|
||||
.Where(x => !x.IsDefined(typeof(SkipScanAttribute), false))
|
||||
.ToArray();
|
||||
|
||||
//db.DbMaintenance.CreateDatabase();
|
||||
//db.CodeFirst.InitTables(tables);
|
||||
db.Client.DbMaintenance.CreateDatabase();
|
||||
db.Client.CodeFirst.InitTables(tables);
|
||||
|
||||
//using var scopeFace = app.ApplicationServices.CreateScope();
|
||||
//var dbFace = scopeFace.ServiceProvider.GetService<ISqlSugarClient>();
|
||||
//var faceConnectionString = Configuration.GetSection("SqlSugarOptions:FaceConnectionString").Value;
|
||||
//dbFace.CurrentConnectionConfig.ConnectionString = faceConnectionString;
|
||||
//dbFace.DbMaintenance.CreateDatabase();
|
||||
//dbFace.CodeFirst.InitTables<GainfoFaceEntity>();
|
||||
var faceDb = db.ChangeDb("face");
|
||||
faceDb.Client.DbMaintenance.CreateDatabase();
|
||||
faceDb.Client.CodeFirst.InitTables<GainfoFaceEntity>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
using Kurisu.AspNetCore.Startup;
|
||||
using Kurisu.AspNetCore.Utils.Extensions;
|
||||
using Kurisu.Startup;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.IdentityModel.Logging;
|
||||
using StackExchange.Redis;
|
||||
|
||||
class Program
|
||||
{
|
||||
@@ -22,11 +21,6 @@ public class Startup : DefaultStartup
|
||||
public override void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
base.ConfigureServices(services);
|
||||
|
||||
//todo
|
||||
var redis = ConnectionMultiplexer.Connect($"10.27.21.15:30050,defaultDatabase:1,password=dlhis123");
|
||||
services.AddDataProtection()
|
||||
.SetApplicationName("basic")
|
||||
.PersistKeysToStackExchangeRedis(redis, "DataProtection-Keys");
|
||||
services.AddRedis();
|
||||
}
|
||||
}
|
||||
40
Src/Dlhis.Basic/Summary/Controllers/SummariesController.cs
Normal file
40
Src/Dlhis.Basic/Summary/Controllers/SummariesController.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Dlhis.Basic.Device.Response;
|
||||
using Dlhis.Basic.Summary.Response;
|
||||
using Dlhis.Basic.Summary.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Dlhis.Basic.Summary.Controllers;
|
||||
|
||||
[Authorize]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class SummariesController : ControllerBase
|
||||
{
|
||||
private readonly ISummaryService _summaryService;
|
||||
|
||||
public SummariesController(ISummaryService summaryService)
|
||||
{
|
||||
_summaryService = summaryService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 考勤首页
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("attendance-summary")]
|
||||
public async Task<AttendanceSummaryResponse> GetKaoQingSummary()
|
||||
{
|
||||
return await _summaryService.GetAttendanceSummaryAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 门禁首页数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("door-summary")]
|
||||
public async Task<DoorHomeDataResponse> GetDoorHomeDataAsync()
|
||||
{
|
||||
return await _summaryService.GetDoorHomeDataAsync();
|
||||
}
|
||||
}
|
||||
8
Src/Dlhis.Basic/Summary/Dto/TrendDto.cs
Normal file
8
Src/Dlhis.Basic/Summary/Dto/TrendDto.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Dlhis.Basic.Summary.Dto;
|
||||
|
||||
public class TrendDto
|
||||
{
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
public int Count { get; set; }
|
||||
}
|
||||
24
Src/Dlhis.Basic/Summary/Response/AttendanceDetailSummary.cs
Normal file
24
Src/Dlhis.Basic/Summary/Response/AttendanceDetailSummary.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace Dlhis.Basic.Summary.Response;
|
||||
|
||||
public class AttendanceDetailSummary
|
||||
{
|
||||
/// <summary>
|
||||
/// 考勤总人数
|
||||
/// </summary>
|
||||
public int Total => Employed + Unemployed;
|
||||
|
||||
/// <summary>
|
||||
/// 在职人数
|
||||
/// </summary>
|
||||
public int Employed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 非在职人数
|
||||
/// </summary>
|
||||
public int Unemployed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 人员趋势 7天
|
||||
/// </summary>
|
||||
public GainfoTrendResponse GainfoTrend { get; set; }
|
||||
}
|
||||
31
Src/Dlhis.Basic/Summary/Response/AttendanceDeviceSummary.cs
Normal file
31
Src/Dlhis.Basic/Summary/Response/AttendanceDeviceSummary.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Dlhis.Basic.Summary.Dto;
|
||||
|
||||
namespace Dlhis.Basic.Summary.Response;
|
||||
|
||||
public class AttendanceDeviceSummary
|
||||
{
|
||||
/// <summary>
|
||||
/// 总数
|
||||
/// </summary>
|
||||
public int Total { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 在线数
|
||||
/// </summary>
|
||||
public int OnlineCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 启用数
|
||||
/// </summary>
|
||||
public int EnableCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 离线数
|
||||
/// </summary>
|
||||
public int OfflineCount => Total - OnlineCount;
|
||||
|
||||
/// <summary>
|
||||
/// 新增设备趋势 30天内
|
||||
/// </summary>
|
||||
public List<TrendDto> Trend { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Dlhis.Basic.Summary.Response
|
||||
{
|
||||
public class AttendanceSummaryResponse
|
||||
{
|
||||
public AttendanceDeviceSummary DeviceSummary { get; set; }
|
||||
|
||||
public AttendanceDetailSummary AttendanceDetailSummary { get; set; }
|
||||
}
|
||||
}
|
||||
11
Src/Dlhis.Basic/Summary/Response/DoorHomeDataResponse.cs
Normal file
11
Src/Dlhis.Basic/Summary/Response/DoorHomeDataResponse.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Dlhis.Basic.Summary.Dto;
|
||||
|
||||
namespace Dlhis.Basic.Summary.Response
|
||||
{
|
||||
public class DoorHomeDataResponse
|
||||
{
|
||||
public int OffNum { get; set; }
|
||||
public int TotalNum { get; set; }
|
||||
public List<TrendDto> Trend { get; set; }
|
||||
}
|
||||
}
|
||||
10
Src/Dlhis.Basic/Summary/Response/GainfoTrendResponse.cs
Normal file
10
Src/Dlhis.Basic/Summary/Response/GainfoTrendResponse.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Dlhis.Basic.Summary.Dto;
|
||||
|
||||
namespace Dlhis.Basic.Summary.Response
|
||||
{
|
||||
public class GainfoTrendResponse
|
||||
{
|
||||
public List<TrendDto> EmployedTrend { get; set; }
|
||||
public List<TrendDto> UnemployedTrend { get; set; }
|
||||
}
|
||||
}
|
||||
11
Src/Dlhis.Basic/Summary/Services/ISummaryService.cs
Normal file
11
Src/Dlhis.Basic/Summary/Services/ISummaryService.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Dlhis.Basic.Device.Response;
|
||||
using Dlhis.Basic.Summary.Response;
|
||||
|
||||
namespace Dlhis.Basic.Summary.Services;
|
||||
|
||||
public interface ISummaryService : IScopeDependency
|
||||
{
|
||||
Task<AttendanceSummaryResponse> GetAttendanceSummaryAsync();
|
||||
|
||||
Task<DoorHomeDataResponse> GetDoorHomeDataAsync();
|
||||
}
|
||||
189
Src/Dlhis.Basic/Summary/Services/Implements/SummaryService.cs
Normal file
189
Src/Dlhis.Basic/Summary/Services/Implements/SummaryService.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
using Dlhis.Basic.Device.Response;
|
||||
using Dlhis.Basic.Organization.Services;
|
||||
using Dlhis.Basic.Summary.Dto;
|
||||
using Dlhis.Basic.Summary.Response;
|
||||
using Dlhis.Entity.Basic.Entity;
|
||||
using Dlhis.Entity.Basic.Enums;
|
||||
using Dlhis.Entity.Device.Entities;
|
||||
using Dlhis.Entity.Device.Enums;
|
||||
using Kurisu.SqlSugar.Services;
|
||||
|
||||
namespace Dlhis.Basic.Summary.Services.Implements;
|
||||
|
||||
public class SummaryService : ISummaryService
|
||||
{
|
||||
private readonly IDbContext _dbContext;
|
||||
private readonly IGainfoStore _gainfoStore;
|
||||
|
||||
public SummaryService(IDbContext dbContext, IGainfoStore gainfoStore)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
_gainfoStore = gainfoStore;
|
||||
}
|
||||
|
||||
public async Task<AttendanceSummaryResponse> GetAttendanceSummaryAsync()
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
|
||||
var currentDay = DateTime.Today.AddDays(1).AddSeconds(-1);
|
||||
var before30Day = DateTime.Today.AddDays(-29);
|
||||
var before7Day = DateTime.Today.AddDays(-6);
|
||||
|
||||
var devices = await _dbContext.Queryable<DeviceEntity>().Where(x => x.Type == DeviceTypeEnumType.Attendance || (x.Type == DeviceTypeEnumType.Door && x.AsAttendance)).ToListAsync();
|
||||
var deviceUniqueNos = devices.Select(x => x.UniqueNo).ToList();
|
||||
|
||||
var deviceRegistries = await _dbContext.Queryable<DeviceRegistryEntity>()
|
||||
.LeftJoin<DeviceEntity>((x, d) => x.DeviceUniqueNo == d.UniqueNo)
|
||||
.Where(x => deviceUniqueNos.Contains(x.DeviceUniqueNo))
|
||||
.Select((x, d) => new
|
||||
{
|
||||
d.HeartbeatInterval,
|
||||
x.LastHeartbeatTime
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
var workingGainfos = await _gainfoStore.Queryable(GainfoStatusEnumType.Working).ToListAsync();
|
||||
var leaveGainfos = await _gainfoStore.Queryable(GainfoStatusEnumType.Leave).ToListAsync();
|
||||
|
||||
return new AttendanceSummaryResponse
|
||||
{
|
||||
DeviceSummary = new AttendanceDeviceSummary
|
||||
{
|
||||
Total = devices.Count,
|
||||
EnableCount = devices.Where(x => x.Enable).Count(),
|
||||
OnlineCount = deviceRegistries.Where(x =>
|
||||
{
|
||||
if (x.HeartbeatInterval <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return x.LastHeartbeatTime.AddSeconds(x.HeartbeatInterval * 3) >= now;
|
||||
|
||||
}).Count(),
|
||||
Trend = FixTrend(devices.Where(x => x.CreateTime >= before30Day && x.CreateTime <= currentDay)
|
||||
.GroupBy(x => x.CreateTime.Date)
|
||||
.Select(x => new TrendDto { Date = x.Key, Count = x.Count() }), before30Day, currentDay)
|
||||
},
|
||||
AttendanceDetailSummary = new AttendanceDetailSummary
|
||||
{
|
||||
Employed = workingGainfos.Count,
|
||||
Unemployed = leaveGainfos.Count,
|
||||
GainfoTrend = new GainfoTrendResponse
|
||||
{
|
||||
EmployedTrend = FixTrend(workingGainfos.Where(x => x.CreateTime >= before7Day && x.CreateTime <= currentDay)
|
||||
.GroupBy(x => x.CreateTime.Date)
|
||||
.Select(x => new TrendDto { Date = x.Key, Count = x.Count() }), before7Day, currentDay),
|
||||
UnemployedTrend = FixTrend(leaveGainfos.Where(x => x.CreateTime >= before7Day && x.CreateTime <= currentDay)
|
||||
.GroupBy(x => x.CreateTime.Date)
|
||||
.Select(x => new TrendDto { Date = x.Key, Count = x.Count() }), before7Day, currentDay),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<DoorHomeDataResponse> GetDoorHomeDataAsync()
|
||||
{
|
||||
var devices = await _dbContext.Queryable<DeviceEntity>().Where(x => x.Type == DeviceTypeEnumType.Door).ToListAsync();
|
||||
|
||||
var offDevices = await GetOfflineDevicesCount(devices);
|
||||
|
||||
//获取近30天并转化为"yyyy-MM-dd"集合
|
||||
DateTime currentDate = DateTime.Now;
|
||||
List<string> times = new List<string>();
|
||||
for (int i = 0; i < 30; i++)
|
||||
{
|
||||
DateTime date = currentDate.AddDays(-i);
|
||||
string dateString = date.ToString("yyyy-MM-dd");
|
||||
times.Add(dateString);
|
||||
}
|
||||
|
||||
var list = new List<TrendDto>();
|
||||
times.ForEach(time =>
|
||||
{
|
||||
var count = devices.Where(x => x.CreateTime.ToString("yyyy-MM-dd") == time).Count();
|
||||
var trend = new TrendDto
|
||||
{
|
||||
Date = DateTime.ParseExact(time, "yyyy-MM-dd", null),
|
||||
Count = count,
|
||||
};
|
||||
list.Add(trend);
|
||||
});
|
||||
var res = new DoorHomeDataResponse
|
||||
{
|
||||
OffNum = offDevices.Count,
|
||||
TotalNum = devices.Count,
|
||||
Trend = list
|
||||
};
|
||||
return res;
|
||||
}
|
||||
|
||||
private static List<TrendDto> FixTrend(IEnumerable<TrendDto> dtos, DateTime start, DateTime end)
|
||||
{
|
||||
var result = dtos.ToList();
|
||||
|
||||
start = start.Date;
|
||||
end = end.Date;
|
||||
|
||||
var currentDate = start;
|
||||
while (currentDate <= end)
|
||||
{
|
||||
if (result.Any(x => x.Date == currentDate))
|
||||
{
|
||||
currentDate = currentDate.AddDays(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
result.Add(new TrendDto { Date = currentDate, Count = 0 });
|
||||
|
||||
currentDate = currentDate.AddDays(1);
|
||||
}
|
||||
|
||||
return result.OrderBy(x => x.Date).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取离线设备
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task<List<DeviceEntity>> GetOfflineDevicesCount(List<DeviceEntity> devices)
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
|
||||
var deviceUniqueNos = devices.Select(x => x.UniqueNo).ToList();
|
||||
|
||||
var deviceRegistries = await _dbContext.Queryable<DeviceRegistryEntity>()
|
||||
.LeftJoin<DeviceEntity>((x, d) => x.DeviceUniqueNo == d.UniqueNo)
|
||||
.Where(x => deviceUniqueNos.Contains(x.DeviceUniqueNo))
|
||||
.Select((x, d) => new
|
||||
{
|
||||
UniqueNo = d.UniqueNo,
|
||||
d.HeartbeatInterval,
|
||||
x.LastHeartbeatTime
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
var OnlineDevices = deviceRegistries
|
||||
.Where(x =>
|
||||
{
|
||||
if (x.HeartbeatInterval <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return x.LastHeartbeatTime.AddSeconds(x.HeartbeatInterval * 3) >= now;
|
||||
|
||||
})
|
||||
.Select(x => new
|
||||
{
|
||||
UniqueNo = x.UniqueNo,
|
||||
})
|
||||
.ToList();
|
||||
var onlineUniqueNos = new List<string>();
|
||||
OnlineDevices.ForEach(x => onlineUniqueNos.Add(x.UniqueNo));
|
||||
|
||||
var offUniqueNos = deviceUniqueNos.Except(onlineUniqueNos).ToList();
|
||||
var list = devices.Where(x => offUniqueNos.Contains(x.UniqueNo)).ToList();
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,10 @@
|
||||
"CommonRequestUrl": "http://localhost:5001",
|
||||
"SysRequestUrl": "http://localhost:5003"
|
||||
},
|
||||
"FaceUrlOptions": {
|
||||
"Url": "http://localhost:5002/api/gainfos/face?token=",
|
||||
"Limit": 7200
|
||||
},
|
||||
"SwaggerOptions": {
|
||||
"Enable": true,
|
||||
"Authority": "https://yikatong.isawesome.cn/oauth2",
|
||||
|
||||
@@ -11,13 +11,18 @@
|
||||
"SysRequestUrl": "http://sys"
|
||||
},
|
||||
"FaceUrlOptions": {
|
||||
"Url": "https://face.jinkosolar.com/api/basic/gainfos/face?token=",
|
||||
"Url": "https://yikatong.isawesome.cn/api/basic/gainfos/face?token=",
|
||||
"Limit": 7200
|
||||
},
|
||||
"DataProtectionOptions": {
|
||||
"Enable": true,
|
||||
"AppName": "yiliantong"
|
||||
},
|
||||
"SqlSugarOptions": {
|
||||
"DefaultConnectionString": "server=10.27.21.22;port=3306;userid=root;password=dlhis123;database=yikatong;charset=utf8mb4;",
|
||||
"SlaveConnectionString": [],
|
||||
"FaceConnectionString": "server=10.27.21.20;port=3306;userid=root;password=dlhis123;database=face;charset=utf8mb4;",
|
||||
"FaceConnectionString": "server=192.168.199.124;port=3306;userid=root;password=dlhis123;database=face;charset=utf8mb4;",
|
||||
"LogConnectionString": "server=192.168.199.124;port=3306;userid=root;password=dlhis123;database=log;charset=utf8mb4;",
|
||||
"Timeout": 30,
|
||||
"SlowSqlTime": 1,
|
||||
"EnableSqlLog": false
|
||||
@@ -33,6 +38,9 @@
|
||||
"yikatong": "yikatong"
|
||||
}
|
||||
},
|
||||
"RedisOptions": {
|
||||
"ConnectionString": "192.168.199.30:30115,defaultDatabase:1,password=dlhis123"
|
||||
},
|
||||
"IdentityServerOptions": {
|
||||
"Authority": "http://identity.oauth.svc.cluster.local",
|
||||
"RequireHttpsMetadata": false,
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Dlhis.Common.Api\Dlhis.Common.Api.csproj" />
|
||||
<ProjectReference Include="..\Dlhis.Basic.Api\Dlhis.Basic.Api.csproj" />
|
||||
<ProjectReference Include="..\Dlhis.Entity\Dlhis.Entity.csproj" />
|
||||
<ProjectReference Include="..\Dlhis.Sys.Api\Dlhis.Sys.Api.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -35,7 +36,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Kurisu.AspNetCore" Version="0.5.2" />
|
||||
<PackageReference Include="Kurisu.AspNetCore" Version="0.7.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.4" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -7,8 +7,9 @@ EXPOSE 80
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["Src/Dlhis.Canteen/Dlhis.Canteen.csproj", "Src/Dlhis.Canteen/"]
|
||||
COPY ["Src/Dlhis.Common.Api/Dlhis.Common.Api.csproj", "Src/Dlhis.Common.Api/"]
|
||||
COPY ["Src/Dlhis.Basic.Api/Dlhis.Basic.Api.csproj", "Src/Dlhis.Basic.Api/"]
|
||||
COPY ["Src/Dlhis.Entity/Dlhis.Entity.csproj", "Src/Dlhis.Entity/"]
|
||||
COPY ["Src/Dlhis.Sys.Api/Dlhis.Sys.Api.csproj", "Src/Dlhis.Sys.Api/"]
|
||||
RUN dotnet restore "Src/Dlhis.Canteen/Dlhis.Canteen.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/Src/Dlhis.Canteen"
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using Dlhis.Canteen.Order.Request;
|
||||
using Dlhis.Canteen.Order.Response;
|
||||
using Dlhis.Canteen.Order.Services;
|
||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop;
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Org.BouncyCastle.Asn1.Ocsp;
|
||||
|
||||
namespace Dlhis.Canteen.Order.Controllers;
|
||||
|
||||
@@ -27,6 +29,7 @@ public class BalancesController : ControllerBase
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[DataPermission]
|
||||
[HttpGet]
|
||||
public async Task<Pagination<BalanceRecordResponse>> GetPageAsync([FromQuery] BalanceRecordPageRequest request)
|
||||
{
|
||||
@@ -39,6 +42,7 @@ public class BalancesController : ControllerBase
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("device/page")]
|
||||
[IgnoreTenant]
|
||||
public async Task<Pagination<BalanceRecordResponse>> GetPageByDeviceUniqueNoGetAsync([FromQuery] BalanceRecordPageByDeviceUniqueNoRequest request)
|
||||
{
|
||||
return await _balanceService.GetPageByDeviceUniqueNoAsync(request);
|
||||
@@ -50,6 +54,7 @@ public class BalancesController : ControllerBase
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("device/page")]
|
||||
[IgnoreTenant]
|
||||
public async Task<Pagination<BalanceRecordResponse>> GetPageByDeviceUniqueNoPostAsync(BalanceRecordPageByDeviceUniqueNoRequest request)
|
||||
{
|
||||
return await _balanceService.GetPageByDeviceUniqueNoAsync(request);
|
||||
@@ -72,6 +77,7 @@ public class BalancesController : ControllerBase
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("obsoluteOutRecord")]
|
||||
[Transactional]
|
||||
public async Task ObsoluteAsync(BalanceRecordObsoluteRequest request)
|
||||
{
|
||||
await _balanceService.ObsoluteAsync(request);
|
||||
@@ -85,7 +91,7 @@ public class BalancesController : ControllerBase
|
||||
[HttpGet("recordByCostId")]
|
||||
public async Task<Pagination<BalanceRecordCostIdResponse>> RecordByCostIdAsync([FromQuery] BalanceRecordPageByCostIdRequest request)
|
||||
{
|
||||
return await _balanceService.RecordByCostIdAsync(request);
|
||||
return await _balanceService.RecordByCostIdAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -132,4 +138,81 @@ public class BalancesController : ControllerBase
|
||||
{
|
||||
return await _balanceService.BalanceRecordAnalysisAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取消费机总数、离线设备数量、营业点数量、可消费人数、人均日消费额
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("consumenumbers")]
|
||||
public async Task<ConsumeNumberResponse> GetConsumeNumberAsync()
|
||||
{
|
||||
return await _balanceService.GetConsumeNumberAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消费人数详情
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("spendingDetails")]
|
||||
public async Task<Pagination<SpendingDetailResponse>> GetSpendingDetailsAsync([FromQuery]SpendingDetailRequest request)
|
||||
{
|
||||
return await _balanceService.GetSpendingDetailsAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 日消费均额
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("averageDaily")]
|
||||
public async Task<Pagination<AverageDailyResponse>> AverageDailyAsync([FromQuery] AverageDailyRequest request)
|
||||
{
|
||||
return await _balanceService.AverageDailyAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取消费机详情
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("consumeDevices")]
|
||||
public async Task<Pagination<DevicePageResponse>> GetConsumeDeviceAsync([FromQuery] GetConsumeDeviceRequest request)
|
||||
{
|
||||
return await _balanceService.GetConsumeDeviceAsync(request);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 营业点增加配置设备接口
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("disposition")]
|
||||
public async Task DispositionDeviceAsync([FromQuery] DispositionDeviceRequest request)
|
||||
{
|
||||
await _balanceService.DispositionDeviceAsync(request);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 电子餐券申请记录查询
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("oaemealvoucher")]
|
||||
public async Task<Pagination<OaEMealVoucherResponse>> GetOaEMealVoucherAsync([FromQuery] OaEMealVoucherRequest request)
|
||||
{
|
||||
return await _balanceService.GetOaEMealVoucherAsync(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 电子餐券使用记录查询
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("oaemealvoucherdetail")]
|
||||
public async Task<Pagination<OaEMealVoucherDetailResponse>> GetOaEMealVoucherDetailAsync([FromQuery] OaEMealVoucherDetailRequest request)
|
||||
{
|
||||
return await _balanceService.GetOaEMealVoucherDetailAsync(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@ public class OrdersController : ControllerBase
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[IgnoreTenant]
|
||||
public async Task<OrderResultResponse> AddAsync(OrderAddRequest request)
|
||||
{
|
||||
return await _orderService.AddAsync(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
8
Src/Dlhis.Canteen/Order/Request/AverageDailyRequest.cs
Normal file
8
Src/Dlhis.Canteen/Order/Request/AverageDailyRequest.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Kurisu.Core.DataAccess.Dto;
|
||||
|
||||
namespace Dlhis.Canteen.Order.Request
|
||||
{
|
||||
public class AverageDailyRequest : PageDto
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,17 @@ namespace Dlhis.Canteen.Order.Request;
|
||||
|
||||
public class BalanceRecordPageRequest : PageDto, IValidatableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 营业点codes
|
||||
/// </summary>
|
||||
public List<Guid?> BusinessplaceCodes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 餐次
|
||||
/// </summary>
|
||||
public List<string> ShiftTypes { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 查询日期范围类型 DateTimeSearchEnumType
|
||||
/// </summary>
|
||||
|
||||
12
Src/Dlhis.Canteen/Order/Request/ConsumptionTrendRequest.cs
Normal file
12
Src/Dlhis.Canteen/Order/Request/ConsumptionTrendRequest.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Dlhis.Entity.Canteen.Enums;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dlhis.Canteen.Order.Request
|
||||
{
|
||||
public class ConsumptionTrendRequest
|
||||
{
|
||||
[Required]
|
||||
[EnumDataType(typeof(ConsumptionTrendEnumType))]
|
||||
public ConsumptionTrendEnumType Type { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Dlhis.Canteen.Order.Request
|
||||
{
|
||||
public class DispositionDeviceRequest
|
||||
{
|
||||
public string PlaceCode { get; set; }
|
||||
|
||||
public List<string> UniqueNos { get; set; }
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user