refactor 优化命名和结构,注释
This commit is contained in:
@@ -52,18 +52,6 @@ public class HolidaysController : ControllerBase
|
|||||||
[HttpGet("remote-ip")]
|
[HttpGet("remote-ip")]
|
||||||
public string GetRemoteIp()
|
public string GetRemoteIp()
|
||||||
{
|
{
|
||||||
// 检查是否在Kubernetes环境中
|
|
||||||
var isKubernetes = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("KUBERNETES_SERVICE_HOST"));
|
|
||||||
|
|
||||||
if (isKubernetes)
|
|
||||||
{
|
|
||||||
var forwardedFor = HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
|
|
||||||
if (!string.IsNullOrEmpty(forwardedFor))
|
|
||||||
{
|
|
||||||
return forwardedFor.Split(',').First().Trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return HttpContext.Connection.RemoteIpAddress?.ToString();
|
return HttpContext.Connection.RemoteIpAddress?.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Dlhis.Basic.Common.Message.Requests;
|
||||||
|
using Dlhis.Basic.Common.Message.Services;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Dlhis.Basic.Common.Message;
|
namespace Dlhis.Basic.Common.Message.Controller;
|
||||||
|
|
||||||
|
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
@@ -16,7 +18,7 @@ public class MessagesController : ControllerBase
|
|||||||
|
|
||||||
|
|
||||||
[HttpPost("dingtalk/workmessage")]
|
[HttpPost("dingtalk/workmessage")]
|
||||||
public async Task SendWorkMessageAsync(JinkoSendWorkMessageRequest request)
|
public async Task SendWorkMessageAsync(DingTalkWorkMessageRequest request)
|
||||||
{
|
{
|
||||||
await _jinkoApiService.SendWorkMessageAsync(request);
|
await _jinkoApiService.SendWorkMessageAsync(request);
|
||||||
}
|
}
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Dlhis.Basic.Common.Message;
|
|
||||||
|
|
||||||
public interface IJinkoApiService : ISingletonDependency
|
|
||||||
{
|
|
||||||
Task SendWorkMessageAsync(JinkoSendWorkMessageRequest request);
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
namespace Dlhis.Basic.Common.Message;
|
|
||||||
|
|
||||||
public class JinkoSendWorkMessageRequest
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 发送内容
|
|
||||||
/// </summary>
|
|
||||||
public string Content { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 工号
|
|
||||||
/// </summary>
|
|
||||||
public List<string> WorkCodes { get; set; }
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Dlhis.Basic.Common.Message.Requests;
|
||||||
|
|
||||||
|
public class DingTalkWorkMessageRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 工号
|
||||||
|
/// </summary>
|
||||||
|
[MinLength(1, ErrorMessage = "{0}不能为空")]
|
||||||
|
public List<string> WorkCodes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发送内容
|
||||||
|
/// </summary>
|
||||||
|
[Required(ErrorMessage = "{0}不能为空")]
|
||||||
|
public string Content { get; set; }
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Dlhis.Basic.Common.Message
|
namespace Dlhis.Basic.Common.Message.Responses
|
||||||
{
|
{
|
||||||
public class JinkoOaResponse<T>
|
public class JinkoOaResponse<T>
|
||||||
{
|
{
|
||||||
@@ -12,11 +12,10 @@ namespace Dlhis.Basic.Common.Message
|
|||||||
public T Data { get; set; }
|
public T Data { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class JinkoOaInfo
|
public class JinkoOaInfo
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
public string Lastname { get; set; }
|
public string Lastname { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using Dlhis.Basic.Common.Message.Requests;
|
||||||
|
|
||||||
|
namespace Dlhis.Basic.Common.Message.Services;
|
||||||
|
|
||||||
|
public interface IJinkoApiService : ISingletonDependency
|
||||||
|
{
|
||||||
|
Task SendWorkMessageAsync(DingTalkWorkMessageRequest request);
|
||||||
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using Dlhis.Basic.Common.ApiLog.Services;
|
using Dlhis.Basic.Common.ApiLog.Services;
|
||||||
|
using Dlhis.Basic.Common.Message.Requests;
|
||||||
|
using Dlhis.Basic.Common.Message.Responses;
|
||||||
using Dlhis.Entity.Common.Enums;
|
using Dlhis.Entity.Common.Enums;
|
||||||
using Kurisu.AspNetCore.Utils.Extensions;
|
using Kurisu.AspNetCore.Utils.Extensions;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace Dlhis.Basic.Common.Message;
|
namespace Dlhis.Basic.Common.Message.Services.Implements;
|
||||||
|
|
||||||
public class JinkoApiService : IJinkoApiService
|
public class JinkoApiService : IJinkoApiService
|
||||||
{
|
{
|
||||||
@@ -24,49 +26,51 @@ public class JinkoApiService : IJinkoApiService
|
|||||||
private async Task<string> GetTokenAsync()
|
private async Task<string> GetTokenAsync()
|
||||||
{
|
{
|
||||||
var token = string.Empty;
|
var token = string.Empty;
|
||||||
if (string.IsNullOrEmpty(token))
|
if (!token.IsEmpty())
|
||||||
{
|
{
|
||||||
var httpClient = _httpClientFactory.CreateClient("jinko.httpclient");
|
return token;
|
||||||
|
|
||||||
var form = new FormUrlEncodedContent(new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "appkey", _appKey },
|
|
||||||
{ "appsecret", _appSecret }
|
|
||||||
});
|
|
||||||
|
|
||||||
//appkey=dingumelppews6rah7x9&appsecret=nsWfJTVjYesHVzrLiP-t1TQqMQvC1L_kZNfXfnIyzcXK4pCTfKprkjZcxAbsDR_l
|
|
||||||
var response = await httpClient.GetStringAsync($"/gettoken?{await form.ReadAsStringAsync()}");
|
|
||||||
var jObj = JObject.Parse(response);
|
|
||||||
(jObj.Value<string>("errcode") == "0").ThrowIfFalse(jObj.Value<string>("errmsg"));
|
|
||||||
|
|
||||||
token = jObj.Value<string>("access_token");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var httpClient = _httpClientFactory.CreateClient("jinko.httpclient");
|
||||||
|
|
||||||
|
var form = new FormUrlEncodedContent(new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "appkey", _appKey },
|
||||||
|
{ "appsecret", _appSecret }
|
||||||
|
});
|
||||||
|
|
||||||
|
//eg: appkey=dingumelppews6rah7x9&appsecret=nsWfJTVjYesHVzrLiP-t1TQqMQvC1L_kZNfXfnIyzcXK4pCTfKprkjZcxAbsDR_l
|
||||||
|
var response = await httpClient.GetStringAsync($"/gettoken?{await form.ReadAsStringAsync()}");
|
||||||
|
var jObj = JObject.Parse(response);
|
||||||
|
(jObj.Value<string>("errcode") == "0").ThrowIfFalse(jObj.Value<string>("errmsg"));
|
||||||
|
|
||||||
|
token = jObj.Value<string>("access_token");
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task SendWorkMessageAsync(JinkoSendWorkMessageRequest request)
|
public async Task SendWorkMessageAsync(DingTalkWorkMessageRequest request)
|
||||||
{
|
{
|
||||||
request.Content.IsEmpty().ThrowIfTrue("发送内容不能为空");
|
request.Content.IsEmpty().ThrowIfTrue("发送内容不能为空");
|
||||||
var token = await GetTokenAsync();
|
var token = await GetTokenAsync();
|
||||||
|
|
||||||
var users = await GetJinkoOaInfoByWorkCodes(request.WorkCodes);
|
var users = await GetJinkoOaInfoByWorkCodes(request.WorkCodes);
|
||||||
var userStringIds = string.Join(",", users.Select(x => x.Id));
|
var userIds = users.Select(x => x.Id).Join(",");
|
||||||
(userStringIds.Length > 100).ThrowIfTrue("超出消息接受人数,length > 100");
|
(userIds.Length > 100).ThrowIfTrue("超出消息接受人数,length > 100");
|
||||||
|
|
||||||
var body = new
|
var body = new
|
||||||
{
|
{
|
||||||
agent_id = _agentId,
|
agent_id = _agentId,
|
||||||
userid_list = userStringIds,
|
userid_list = userIds,
|
||||||
msg = new
|
msg = new
|
||||||
{
|
{
|
||||||
msgtype = "text",
|
msgtype = "text",
|
||||||
text = new
|
text = new
|
||||||
{
|
{
|
||||||
content = request.Content
|
content = request.Content
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
}.ToJson();
|
}.ToJson();
|
||||||
|
|
||||||
var httpClient = _httpClientFactory.CreateClient("jinko.httpclient");
|
var httpClient = _httpClientFactory.CreateClient("jinko.httpclient");
|
||||||
@@ -76,11 +80,8 @@ public class JinkoApiService : IJinkoApiService
|
|||||||
var response = await httpClient.PostAsync(url, content);
|
var response = await httpClient.PostAsync(url, content);
|
||||||
var jsonResponse = await response.Content.ReadAsStringAsync();
|
var jsonResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
//_logger.LogInformation("请求参数:{Request} \r\n 钉钉请求参数:{DingTalkRequest} \r\n 钉钉响应:{DingTalkResponse}", JsonConvert.SerializeObject(request), body, jsonResponse);
|
var jObject = JObject.Parse(jsonResponse);
|
||||||
|
(jObject.Value<string>("errcode") == "0").ThrowIfFalse(jObject.Value<string>("errmsg"));
|
||||||
var jObj = JObject.Parse(jsonResponse);
|
|
||||||
(jObj.Value<string>("errcode") == "0").ThrowIfFalse(jObj.Value<string>("errmsg"));
|
|
||||||
|
|
||||||
|
|
||||||
using var scope = _serviceProvider.CreateScope();
|
using var scope = _serviceProvider.CreateScope();
|
||||||
var ol = scope.ServiceProvider.GetService<IOperateLog>();
|
var ol = scope.ServiceProvider.GetService<IOperateLog>();
|
||||||
@@ -196,7 +196,7 @@ public class DevicePermissionAnalyzeService : IDevicePermissionAnalyzeService
|
|||||||
AssignTypeEnumType.Group => analyzePack.UserGainfoGroupCodes.Select(x => x.ToString()),
|
AssignTypeEnumType.Group => analyzePack.UserGainfoGroupCodes.Select(x => x.ToString()),
|
||||||
AssignTypeEnumType.Department => RecursionHelper.HandlerDepartmentPreviousCodes(analyzePack.UserDepartment, departments).Select(x => analyzePack.UserFactory + ":" + x).ToList(),
|
AssignTypeEnumType.Department => RecursionHelper.HandlerDepartmentPreviousCodes(analyzePack.UserDepartment, departments).Select(x => analyzePack.UserFactory + ":" + x).ToList(),
|
||||||
AssignTypeEnumType.Tenant => new List<string> { analyzePack.UserFactory },
|
AssignTypeEnumType.Tenant => new List<string> { analyzePack.UserFactory },
|
||||||
AssignTypeEnumType.Role => throw new ArgumentOutOfRangeException(),
|
AssignTypeEnumType.Role => throw new NotSupportedException("不支持角色分配"),
|
||||||
_ => throw new ArgumentOutOfRangeException()
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -517,6 +517,7 @@ public class DevicePermissionService : IDevicePermissionService
|
|||||||
{
|
{
|
||||||
var now = DateTime.Now;
|
var now = DateTime.Now;
|
||||||
|
|
||||||
|
// 获取与指定设备关联的分组编码
|
||||||
var groupCodes = await _dbContext.Queryable<DeviceGroupEntity>()
|
var groupCodes = await _dbContext.Queryable<DeviceGroupEntity>()
|
||||||
.Where(x => SqlFunc.Subqueryable<DeviceGroupRelationshipEntity>()
|
.Where(x => SqlFunc.Subqueryable<DeviceGroupRelationshipEntity>()
|
||||||
.Where(p => p.GroupCode == x.Code)
|
.Where(p => p.GroupCode == x.Code)
|
||||||
@@ -525,25 +526,30 @@ public class DevicePermissionService : IDevicePermissionService
|
|||||||
.Select(x => x.Code)
|
.Select(x => x.Code)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
|
// 获取与分组相关联的区域编码及类型
|
||||||
var areaCodes = await _dbContext.Queryable<AppointmentAreaAssignmentEntity>()
|
var areaCodes = await _dbContext.Queryable<AppointmentAreaAssignmentEntity>()
|
||||||
.LeftJoin<AppointmentAreaEntity>((x, y) => x.CustomCode == y.CustomCode)
|
.LeftJoin<AppointmentAreaEntity>((x, y) => x.CustomCode == y.CustomCode)
|
||||||
.Where(x => groupCodes.Contains(x.DeviceGroupCode))
|
.Where(x => groupCodes.Contains(x.DeviceGroupCode))
|
||||||
.Select((x, y) => new { x.CustomCode, y.Type })
|
.Select((x, y) => new { x.CustomCode, y.Type })
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
|
// 根据区域类型筛选出门区和厂区的区域编码
|
||||||
var doorAreaCodes = areaCodes.Where(p => p.Type == AppointmentAreaEnumType.Door).Select(p => p.CustomCode).ToList();
|
var doorAreaCodes = areaCodes.Where(p => p.Type == AppointmentAreaEnumType.Door).Select(p => p.CustomCode).ToList();
|
||||||
var workplaceAreaCodes = areaCodes.Where(p => p.Type == AppointmentAreaEnumType.Workplace).Select(p => p.CustomCode).ToList();
|
var workplaceAreaCodes = areaCodes.Where(p => p.Type == AppointmentAreaEnumType.Workplace).Select(p => p.CustomCode).ToList();
|
||||||
|
|
||||||
|
// 查询当前时间段内已到访的访客预约明细
|
||||||
var details = await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
|
var details = await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
|
||||||
.Where(x => (x.IsEnterDoorArea && now >= x.DoorStart && now <= x.DoorEnd && x.DoorStatus == VisitorAppointmentDetailStatusEnumType.Arrived)
|
.Where(x => (x.IsEnterDoorArea && now >= x.DoorStart && now <= x.DoorEnd && x.DoorStatus == VisitorAppointmentDetailStatusEnumType.Arrived)
|
||||||
|| x.IsEnterWorkplace && now >= x.WorkplaceStart && now <= x.WorkplaceEnd && x.WorkplaceStatus == VisitorAppointmentDetailStatusEnumType.Arrived)
|
|| x.IsEnterWorkplace && now >= x.WorkplaceStart && now <= x.WorkplaceEnd && x.WorkplaceStatus == VisitorAppointmentDetailStatusEnumType.Arrived)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
|
//到访门区或厂区的访客编号列表
|
||||||
return details.Where(x =>
|
return details.Where(x =>
|
||||||
(x.IsEnterDoorArea && doorAreaCodes.Contains(x.ApplyDoorArea))
|
(x.IsEnterDoorArea && doorAreaCodes.Contains(x.ApplyDoorArea))
|
||||||
|| (x.IsEnterWorkplace && workplaceAreaCodes.Any(p => x.ApplyWorkplaceAreas.Contains(p)))
|
|| (x.IsEnterWorkplace && workplaceAreaCodes.Any(p => x.ApplyWorkplaceAreas.Contains(p)))
|
||||||
)
|
)
|
||||||
.Select(x => x.UserNo)
|
.Select(x => x.UserNo)
|
||||||
|
.Distinct()
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Dlhis.Basic.Common.Message;
|
using Dlhis.Basic.Common.Message.Requests;
|
||||||
|
using Dlhis.Basic.Common.Message.Services;
|
||||||
using Dlhis.Basic.Organization.Comparers;
|
using Dlhis.Basic.Organization.Comparers;
|
||||||
using Dlhis.Entity.Basic.Entity;
|
using Dlhis.Entity.Basic.Entity;
|
||||||
using Dlhis.Entity.Basic.Enums;
|
using Dlhis.Entity.Basic.Enums;
|
||||||
@@ -186,7 +187,7 @@ public class GainfoUpdateService : IGainfoUpdateService
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private GainfoEntity GainfoSapToGainfo(GainfoSapEntity item)
|
private static GainfoEntity GainfoSapToGainfo(GainfoSapEntity item)
|
||||||
{
|
{
|
||||||
var info = new GainfoEntity
|
var info = new GainfoEntity
|
||||||
{
|
{
|
||||||
@@ -319,20 +320,24 @@ public class GainfoUpdateService : IGainfoUpdateService
|
|||||||
{
|
{
|
||||||
var resignationDate = DateOnly.FromDateTime(gainfo.ModifiedTime);
|
var resignationDate = DateOnly.FromDateTime(gainfo.ModifiedTime);
|
||||||
|
|
||||||
var workGridSchedules = await _dbContext.Queryable<WorkGridScheduleEntity>().Where(x => x.UserCode == gainfo.Code)
|
var workGridSchedules = await _dbContext.Queryable<WorkGridScheduleEntity>()
|
||||||
|
.Where(x => x.UserCode == gainfo.Code)
|
||||||
.Where(x => x.Date >= resignationDate)
|
.Where(x => x.Date >= resignationDate)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
if (workGridSchedules.Any())
|
if (workGridSchedules.Any())
|
||||||
{
|
{
|
||||||
var dates = workGridSchedules.Select(x => $"{x.Date.ToString("yyyy年-MM月-dd日")}的{x.PeriodType.GetDescription()}").Join(",");
|
var dates = workGridSchedules.Select(x => $"{x.Date.ToString("yyyy年-MM月-dd日")}的{x.PeriodType.GetDescription()}").Join(",");
|
||||||
var workGrid = await _dbContext.Queryable<WorkGridEntity>().Where(x => x.Code == workGridUser.WorkGridCode).Select(x => new
|
var workGrid = await _dbContext.Queryable<WorkGridEntity>()
|
||||||
{
|
.Where(x => x.Code == workGridUser.WorkGridCode)
|
||||||
x.LeaderUserCode, x.Name
|
.Select(x => new
|
||||||
}).SingleAsync();
|
{
|
||||||
var content = $"{workGrid.Name}的网格长,你好,检测到你网格中 {gainfo.Name}({gainfo.Code}),因发生离职或者异动,现已经删除该员工{dates}的排班信息,请前往系统处理!";
|
x.LeaderUserCode, x.Name
|
||||||
|
}).SingleAsync();
|
||||||
|
|
||||||
await _dingTalkApi.SendWorkMessageAsync(new JinkoSendWorkMessageRequest
|
var content = $"{workGrid.Name}的网格长,你好,检测到你网格中 {gainfo.Name}({gainfo.Code}),因发生离职或者异动,现已经删除该员工{dates}的排班信息,请前往系统处理!";
|
||||||
|
|
||||||
|
await _dingTalkApi.SendWorkMessageAsync(new DingTalkWorkMessageRequest
|
||||||
{
|
{
|
||||||
Content = content,
|
Content = content,
|
||||||
WorkCodes = new List<string> { workGrid.LeaderUserCode }
|
WorkCodes = new List<string> { workGrid.LeaderUserCode }
|
||||||
@@ -364,30 +369,39 @@ public class GainfoUpdateService : IGainfoUpdateService
|
|||||||
await _dbContext.Client.Insertable(gainfo).AS("GainfoLeave").ExecuteCommandAsync();
|
await _dbContext.Client.Insertable(gainfo).AS("GainfoLeave").ExecuteCommandAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
await _dbContext.Deleteable<GainfoGroupRelationshipEntity>().Where(x => x.UserNo == gainfo.No).ExecuteCommandAsync();
|
await _dbContext.Deleteable<GainfoGroupRelationshipEntity>()
|
||||||
await _dbContext.Deleteable<DevicePermissionEntity>().Where(x => x.AssignType == AssignTypeEnumType.User && x.AssignValue == gainfo.No).ExecuteCommandAsync();
|
.Where(x => x.UserNo == gainfo.No)
|
||||||
|
.ExecuteCommandAsync();
|
||||||
|
await _dbContext.Deleteable<DevicePermissionEntity>()
|
||||||
|
.Where(x => x.AssignType == AssignTypeEnumType.User && x.AssignValue == gainfo.No)
|
||||||
|
.ExecuteCommandAsync();
|
||||||
|
|
||||||
var workGridUser = await _dbContext.Queryable<WorkGridUserEntity>().Where(x => x.UserCode == gainfo.Code).SingleAsync();
|
var workGridUser = await _dbContext.Queryable<WorkGridUserEntity>()
|
||||||
|
.Where(x => x.UserCode == gainfo.Code)
|
||||||
|
.SingleAsync();
|
||||||
if (workGridUser != null)
|
if (workGridUser != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var resignationDate = DateOnly.FromDateTime(gainfo.ResignationDate!.Value);
|
var resignationDate = DateOnly.FromDateTime(gainfo.ResignationDate!.Value);
|
||||||
|
|
||||||
var workGridSchedules = await _dbContext.Queryable<WorkGridScheduleEntity>().Where(x => x.UserCode == gainfo.Code)
|
var workGridSchedules = await _dbContext.Queryable<WorkGridScheduleEntity>()
|
||||||
|
.Where(x => x.UserCode == gainfo.Code)
|
||||||
.Where(x => x.Date >= resignationDate)
|
.Where(x => x.Date >= resignationDate)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
if (workGridSchedules.Any())
|
if (workGridSchedules.Any())
|
||||||
{
|
{
|
||||||
var dates = workGridSchedules.Select(x => $"{x.Date.ToString("yyyy年-MM月-dd日")}的{x.PeriodType.GetDescription()}").Join(",");
|
var dates = workGridSchedules.Select(x => $"{x.Date.ToString("yyyy年-MM月-dd日")}的{x.PeriodType.GetDescription()}").Join(",");
|
||||||
var workGrid = await _dbContext.Queryable<WorkGridEntity>().Where(x => x.Code == workGridUser.WorkGridCode).Select(x => new
|
var workGrid = await _dbContext.Queryable<WorkGridEntity>()
|
||||||
{
|
.Where(x => x.Code == workGridUser.WorkGridCode)
|
||||||
x.LeaderUserCode, x.Name
|
.Select(x => new
|
||||||
}).SingleAsync();
|
{
|
||||||
|
x.LeaderUserCode, x.Name
|
||||||
|
}).SingleAsync();
|
||||||
var content = $"{workGrid.Name}的网格长,你好,检测到你网格中 {gainfo.Name}({gainfo.Code}),因发生离职或者异动,现已经删除该员工{dates}的排班信息,请前往系统处理!";
|
var content = $"{workGrid.Name}的网格长,你好,检测到你网格中 {gainfo.Name}({gainfo.Code}),因发生离职或者异动,现已经删除该员工{dates}的排班信息,请前往系统处理!";
|
||||||
|
|
||||||
await _dingTalkApi.SendWorkMessageAsync(new JinkoSendWorkMessageRequest
|
await _dingTalkApi.SendWorkMessageAsync(new DingTalkWorkMessageRequest
|
||||||
{
|
{
|
||||||
Content = content,
|
Content = content,
|
||||||
WorkCodes = new List<string> { workGrid.LeaderUserCode }
|
WorkCodes = new List<string> { workGrid.LeaderUserCode }
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ class Program
|
|||||||
{
|
{
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
KurisuHost.Builder(args)
|
KurisuHost.Builder(args).RunKurisu<Startup>();
|
||||||
//.EnableAppSettingsReload()
|
|
||||||
.RunKurisu<Startup>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +27,7 @@ public class Startup : DefaultStartup
|
|||||||
options.KnownNetworks.Clear();
|
options.KnownNetworks.Clear();
|
||||||
options.KnownProxies.Clear();
|
options.KnownProxies.Clear();
|
||||||
});
|
});
|
||||||
|
|
||||||
base.ConfigureServices(services);
|
base.ConfigureServices(services);
|
||||||
services.AddRedis();
|
services.AddRedis();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using Dlhis.Basic.WorkGrids.Response;
|
||||||
|
|
||||||
|
namespace Dlhis.Basic.WorkGrids.Repositories;
|
||||||
|
|
||||||
|
public interface IWorkGridScheduleRepository : IScopeDependency
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取用户在指定天数内最大连续排班信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userCodes">用户编码列表</param>
|
||||||
|
/// <param name="days">天数</param>s
|
||||||
|
/// <param name="date">日期</param>
|
||||||
|
/// <returns>最大连续排班信息列表</returns>
|
||||||
|
Task<List<WorkGridScheduleMaximumConsecutiveDto>> MaximumConsecutiveUserCodesAsync(List<string> userCodes, int days, DateOnly date);
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
using Dlhis.Basic.WorkGrids.Response;
|
||||||
|
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
||||||
|
using Kurisu.AspNetCore.Utils.Extensions;
|
||||||
|
|
||||||
|
namespace Dlhis.Basic.WorkGrids.Repositories.Implements;
|
||||||
|
|
||||||
|
public class WorkGridScheduleRepository : IWorkGridScheduleRepository
|
||||||
|
{
|
||||||
|
private readonly IDbContext _dbContext;
|
||||||
|
|
||||||
|
public WorkGridScheduleRepository(IDbContext dbContext)
|
||||||
|
{
|
||||||
|
_dbContext = dbContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<WorkGridScheduleMaximumConsecutiveDto>> MaximumConsecutiveUserCodesAsync(List<string> userCodes, int days, DateOnly date)
|
||||||
|
{
|
||||||
|
var userCodesStr = userCodes.Select(x => $"@param{x.Replace("-", "A_")}").Join(",");
|
||||||
|
var parameters = userCodes.ToDictionary(x => $"param{x.Replace("-", "A_")}", x => x);
|
||||||
|
|
||||||
|
parameters.Add("dateBefore", date.AddDays(-1).ToString("yyyy-MM-dd"));
|
||||||
|
parameters.Add("dateAfter", date.AddDays(1).ToString("yyyy-MM-dd"));
|
||||||
|
parameters.Add("days", days.ToString());
|
||||||
|
|
||||||
|
/* 1.用户按日期排序,标记序号
|
||||||
|
* 2.将日期减去序号,需要得出结果一致 == 数据连续 == 连续排班
|
||||||
|
* 3.根据减去序号后的日期分组,统计连续排班的天数
|
||||||
|
* 4.数据过滤,取当前排班的前后一天
|
||||||
|
*
|
||||||
|
* 根据以上结果,获取连续排班天数大于等于指定天数的用户
|
||||||
|
*/
|
||||||
|
var sql = $@"
|
||||||
|
|
||||||
|
WITH ranked_dates AS (SELECT UserCode,
|
||||||
|
Date,
|
||||||
|
ROW_NUMBER() OVER (PARTITION BY UserCode ORDER BY Date) AS rn
|
||||||
|
FROM WorkGridSchedules
|
||||||
|
where IsDeleted = 0 and UserCode in ({userCodesStr})
|
||||||
|
GROUP BY UserCode, Date),
|
||||||
|
grouped AS (SELECT UserCode,
|
||||||
|
Date,
|
||||||
|
DATE_SUB(Date, INTERVAL rn DAY) AS grp
|
||||||
|
FROM ranked_dates),
|
||||||
|
streaks AS (SELECT UserCode,
|
||||||
|
grp,
|
||||||
|
COUNT(*) AS streak_days,
|
||||||
|
MIN(Date) AS start_date,
|
||||||
|
MAX(Date) AS end_date
|
||||||
|
FROM grouped
|
||||||
|
GROUP BY UserCode, grp
|
||||||
|
HAVING streak_days >= @days)
|
||||||
|
SELECT UserCode, streak_days as Count, start_date as Start, end_date as End
|
||||||
|
FROM streaks
|
||||||
|
where (@dateBefore >= start_date
|
||||||
|
and @dateBefore <= end_date)
|
||||||
|
or (@dateAfter >= start_date
|
||||||
|
and @dateAfter <= end_date)
|
||||||
|
";
|
||||||
|
|
||||||
|
return await _dbContext.Client.Ado.SqlQueryAsync<WorkGridScheduleMaximumConsecutiveDto>(sql, parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ namespace Dlhis.Basic.WorkGrids.Request;
|
|||||||
public class WorkGridPageRequest : PageDto
|
public class WorkGridPageRequest : PageDto
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 网格code,不传则取我的网格
|
/// 网格code,默认为当前用户网格
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid? WorkGridCode { get; set; }
|
public Guid? WorkGridCode { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class WorkGridScheduleSaveRequest : IValidatableObject
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 班次
|
/// 班次
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EnumDataType(typeof(WorkGridTimePeriodEnumType))]
|
[EnumDataType(typeof(WorkGridTimePeriodEnumType), ErrorMessage = "班次类型错误")]
|
||||||
public WorkGridTimePeriodEnumType PeriodType { get; set; }
|
public WorkGridTimePeriodEnumType PeriodType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -27,7 +27,7 @@ public class WorkGridScheduleSaveRequest : IValidatableObject
|
|||||||
[MinLength(1, ErrorMessage = "人员不可为空")]
|
[MinLength(1, ErrorMessage = "人员不可为空")]
|
||||||
public List<string> UserCodes { get; set; }
|
public List<string> UserCodes { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||||
{
|
{
|
||||||
var now = DateTime.Now;
|
var now = DateTime.Now;
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
|
using Dlhis.Basic.WorkGrids.Repositories;
|
||||||
|
|
||||||
namespace Dlhis.Basic.WorkGrids.Response;
|
namespace Dlhis.Basic.WorkGrids.Response;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 连续排班信息
|
||||||
|
/// <see cref="IWorkGridScheduleRepository.MaximumConsecutiveUserCodesAsync"/>的方法返回类型
|
||||||
|
/// </summary>
|
||||||
public class WorkGridScheduleMaximumConsecutiveDto
|
public class WorkGridScheduleMaximumConsecutiveDto
|
||||||
{
|
{
|
||||||
public string UserCode { get; set; }
|
public string UserCode { get; set; }
|
||||||
|
|||||||
@@ -10,21 +10,60 @@ namespace Dlhis.Basic.WorkGrids.Services;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IWorkGridScheduleService : IScopeDependency
|
public interface IWorkGridScheduleService : IScopeDependency
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 保存网格排班信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">排班保存请求参数</param>
|
||||||
Task SaveAsync(WorkGridScheduleSaveRequest request);
|
Task SaveAsync(WorkGridScheduleSaveRequest request);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除网格排班信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">排班移除请求参数</param>
|
||||||
Task RemoveAsync(WorkGridScheduleSaveRequest request);
|
Task RemoveAsync(WorkGridScheduleSaveRequest request);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取指定网格、日期和时段的排班列表
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workGridCode">网格编码</param>
|
||||||
|
/// <param name="date">日期</param>
|
||||||
|
/// <param name="periodType">时段类型</param>
|
||||||
|
/// <returns>排班列表</returns>
|
||||||
Task<List<WorkGridScheduleResponse>> GetListAsync(Guid workGridCode, DateOnly date, WorkGridTimePeriodEnumType? periodType);
|
Task<List<WorkGridScheduleResponse>> GetListAsync(Guid workGridCode, DateOnly date, WorkGridTimePeriodEnumType? periodType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取指定网格和日期范围的排班汇总列表
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workGridCode">网格编码</param>
|
||||||
|
/// <param name="start">开始日期</param>
|
||||||
|
/// <param name="end">结束日期</param>
|
||||||
|
/// <returns>排班汇总列表</returns>
|
||||||
Task<IEnumerable<WorkGridScheduleSummaryResponse>> GetListSummaryAsync(Guid workGridCode, DateOnly start, DateOnly end);
|
Task<IEnumerable<WorkGridScheduleSummaryResponse>> GetListSummaryAsync(Guid workGridCode, DateOnly start, DateOnly end);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取排班考勤分页数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">考勤分页请求参数</param>
|
||||||
|
/// <returns>排班考勤分页数据</returns>
|
||||||
Task<Pagination<WorkGridScheduleAttendancePageResponse>> GetAttendancePageAsync(WorkGridScheduleAttendancePageRequest request);
|
Task<Pagination<WorkGridScheduleAttendancePageResponse>> GetAttendancePageAsync(WorkGridScheduleAttendancePageRequest request);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取所有排班考勤分页数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">考勤分页请求参数</param>
|
||||||
|
/// <returns>排班考勤分页数据</returns>
|
||||||
Task<Pagination<WorkGridScheduleAttendancePageResponse>> GetAllAttendancePageAsync(WorkGridScheduleAttendancePageRequest request);
|
Task<Pagination<WorkGridScheduleAttendancePageResponse>> GetAllAttendancePageAsync(WorkGridScheduleAttendancePageRequest request);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 手动上传考勤日志
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logIds">考勤日志ID列表</param>
|
||||||
Task ManuallyUploadAsync(List<long> logIds);
|
Task ManuallyUploadAsync(List<long> logIds);
|
||||||
|
|
||||||
Task<List<WorkGridScheduleMaximumConsecutiveDto>> MaximumConsecutiveUserCodesAsync(List<string> userCodes, int days, DateOnly date);
|
/// <summary>
|
||||||
|
/// 测试接口
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">排班保存请求参数</param>
|
||||||
|
/// <returns>测试结果</returns>
|
||||||
Task<object> TestAsync(WorkGridScheduleSaveRequest request);
|
Task<object> TestAsync(WorkGridScheduleSaveRequest request);
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
using Dlhis.Basic.Common.ApiLog.Services;
|
using Dlhis.Basic.Common.ApiLog.Services;
|
||||||
using Dlhis.Basic.Common.Message;
|
using Dlhis.Basic.Common.Message.Requests;
|
||||||
|
using Dlhis.Basic.Common.Message.Services;
|
||||||
|
using Dlhis.Basic.WorkGrids.Repositories;
|
||||||
using Dlhis.Basic.WorkGrids.Request;
|
using Dlhis.Basic.WorkGrids.Request;
|
||||||
using Dlhis.Basic.WorkGrids.Response;
|
using Dlhis.Basic.WorkGrids.Response;
|
||||||
using Dlhis.Constants;
|
using Dlhis.Constants;
|
||||||
@@ -27,6 +29,7 @@ public class WorkGridScheduleService : IWorkGridScheduleService
|
|||||||
private readonly IOperateLog _operateLog;
|
private readonly IOperateLog _operateLog;
|
||||||
private readonly ILogger<WorkGridScheduleService> _logger;
|
private readonly ILogger<WorkGridScheduleService> _logger;
|
||||||
private readonly IJinkoApiService _jinkoApiService;
|
private readonly IJinkoApiService _jinkoApiService;
|
||||||
|
private readonly IWorkGridScheduleRepository _workGridScheduleRepository;
|
||||||
private readonly ICurrentUser _currentUser;
|
private readonly ICurrentUser _currentUser;
|
||||||
|
|
||||||
public WorkGridScheduleService(IDbContext dbContext,
|
public WorkGridScheduleService(IDbContext dbContext,
|
||||||
@@ -34,6 +37,7 @@ public class WorkGridScheduleService : IWorkGridScheduleService
|
|||||||
IOperateLog operateLog,
|
IOperateLog operateLog,
|
||||||
ILogger<WorkGridScheduleService> logger,
|
ILogger<WorkGridScheduleService> logger,
|
||||||
IJinkoApiService jinkoApiService,
|
IJinkoApiService jinkoApiService,
|
||||||
|
IWorkGridScheduleRepository workGridScheduleRepository,
|
||||||
ICurrentUser currentUser)
|
ICurrentUser currentUser)
|
||||||
{
|
{
|
||||||
_dbContext = dbContext;
|
_dbContext = dbContext;
|
||||||
@@ -41,6 +45,7 @@ public class WorkGridScheduleService : IWorkGridScheduleService
|
|||||||
_operateLog = operateLog;
|
_operateLog = operateLog;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_jinkoApiService = jinkoApiService;
|
_jinkoApiService = jinkoApiService;
|
||||||
|
_workGridScheduleRepository = workGridScheduleRepository;
|
||||||
_currentUser = currentUser;
|
_currentUser = currentUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +66,11 @@ public class WorkGridScheduleService : IWorkGridScheduleService
|
|||||||
.SingleAsync();
|
.SingleAsync();
|
||||||
workGrid.ThrowIfNull("工作网格不存在");
|
workGrid.ThrowIfNull("工作网格不存在");
|
||||||
|
|
||||||
var timeSetting = await _dbContext.Queryable<WorkGridTimePeriodEntity>().Where(x => x.Type == request.PeriodType).Select(x => new { x.Start, x.Before }).SingleAsync();
|
var timeSetting = await _dbContext.Queryable<WorkGridTimePeriodEntity>()
|
||||||
|
.Where(x => x.Type == request.PeriodType)
|
||||||
|
.Select(x => new { x.Start, x.Before })
|
||||||
|
.SingleAsync();
|
||||||
|
|
||||||
timeSetting.ThrowIfNull("工作网格时间尚未配置,无法操作");
|
timeSetting.ThrowIfNull("工作网格时间尚未配置,无法操作");
|
||||||
|
|
||||||
var currentLimit = request.Date.ToDateTime(timeSetting.Start.Add(-TimeSpan.FromHours(1)));
|
var currentLimit = request.Date.ToDateTime(timeSetting.Start.Add(-TimeSpan.FromHours(1)));
|
||||||
@@ -103,8 +112,8 @@ public class WorkGridScheduleService : IWorkGridScheduleService
|
|||||||
existsUserCodes.ThrowIfExists(existsUserCodes.Join(",") + $"在{dateAfter.ToString("yyyy-MM-dd")}已存在{WorkGridTimePeriodEnumType.Day.GetDescription()}");
|
existsUserCodes.ThrowIfExists(existsUserCodes.Join(",") + $"在{dateAfter.ToString("yyyy-MM-dd")}已存在{WorkGridTimePeriodEnumType.Day.GetDescription()}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var maximumConsecutiveDtos = await MaximumConsecutiveUserCodesAsync(request.UserCodes, workGrid.MaxConsecutiveLimitCount, request.Date);
|
var maximumConsecutiveListDto = await _workGridScheduleRepository.MaximumConsecutiveUserCodesAsync(request.UserCodes, workGrid.MaxConsecutiveLimitCount, request.Date);
|
||||||
maximumConsecutiveDtos.ThrowIfExists(maximumConsecutiveDtos.Select(x => $"{x.UserCode}已经连续排班{workGrid.MaxConsecutiveLimitCount}天({x.Start}-{x.End}),禁止排班").Join("\r\n"));
|
maximumConsecutiveListDto.ThrowIfExists(maximumConsecutiveListDto.Select(x => $"{x.UserCode}已经连续排班{workGrid.MaxConsecutiveLimitCount}天({x.Start}-{x.End}),禁止排班").Join("\r\n"));
|
||||||
|
|
||||||
var toInserts = request.UserCodes.Select(x => new WorkGridScheduleEntity
|
var toInserts = request.UserCodes.Select(x => new WorkGridScheduleEntity
|
||||||
{
|
{
|
||||||
@@ -120,12 +129,15 @@ public class WorkGridScheduleService : IWorkGridScheduleService
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var gainfos = await _dbContext.Queryable<GainfoEntity>().Where(x => request.UserCodes.Contains(x.Code)).Select(x => new { x.Code, x.Name }).ToListAsync();
|
var codeAndNameList = await _dbContext.Queryable<GainfoEntity>().Where(x => request.UserCodes.Contains(x.Code))
|
||||||
foreach (var gainfo in gainfos)
|
.Select(x => new { x.Code, x.Name })
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
foreach (var gainfo in codeAndNameList)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _jinkoApiService.SendWorkMessageAsync(new JinkoSendWorkMessageRequest
|
await _jinkoApiService.SendWorkMessageAsync(new DingTalkWorkMessageRequest
|
||||||
{
|
{
|
||||||
Content = $"{gainfo.Name}({gainfo.Code})你好,系统检测到你被{workGrid.Name}网格的网格长{workGrid.LeaderUserName}({workGrid.LeaderUserCode})安排了{request.Date.ToString("yyyy年MM月dd日")}{request.PeriodType.GetDescription()},请按时上班",
|
Content = $"{gainfo.Name}({gainfo.Code})你好,系统检测到你被{workGrid.Name}网格的网格长{workGrid.LeaderUserName}({workGrid.LeaderUserCode})安排了{request.Date.ToString("yyyy年MM月dd日")}{request.PeriodType.GetDescription()},请按时上班",
|
||||||
WorkCodes = new List<string> { gainfo.Code }
|
WorkCodes = new List<string> { gainfo.Code }
|
||||||
@@ -210,7 +222,7 @@ public class WorkGridScheduleService : IWorkGridScheduleService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _jinkoApiService.SendWorkMessageAsync(new JinkoSendWorkMessageRequest
|
await _jinkoApiService.SendWorkMessageAsync(new DingTalkWorkMessageRequest
|
||||||
{
|
{
|
||||||
Content = $"{gainfo.Name}({gainfo.Code})你好,系统检测到你被{workGrid.Name}网格的网格长{workGrid.LeaderUserName}({workGrid.LeaderUserCode})删除了{request.Date.ToString("yyyy年MM月dd日")}{request.PeriodType.GetDescription()},如有疑问,请联系网格长!",
|
Content = $"{gainfo.Name}({gainfo.Code})你好,系统检测到你被{workGrid.Name}网格的网格长{workGrid.LeaderUserName}({workGrid.LeaderUserCode})删除了{request.Date.ToString("yyyy年MM月dd日")}{request.PeriodType.GetDescription()},如有疑问,请联系网格长!",
|
||||||
WorkCodes = new List<string> { gainfo.Code }
|
WorkCodes = new List<string> { gainfo.Code }
|
||||||
@@ -432,44 +444,4 @@ public class WorkGridScheduleService : IWorkGridScheduleService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<WorkGridScheduleMaximumConsecutiveDto>> MaximumConsecutiveUserCodesAsync(List<string> userCodes, int days, DateOnly date)
|
|
||||||
{
|
|
||||||
var p = userCodes.Select(x => $"@param{x.Replace("-", "A_")}").Join(",");
|
|
||||||
var values = userCodes.ToDictionary(x => $"param{x.Replace("-", "A_")}", x => x);
|
|
||||||
|
|
||||||
values.Add("dateBefore", date.AddDays(-1).ToString("yyyy-MM-dd"));
|
|
||||||
values.Add("dateAfter", date.AddDays(1).ToString("yyyy-MM-dd"));
|
|
||||||
values.Add("days", days.ToString());
|
|
||||||
|
|
||||||
var sql = $@"
|
|
||||||
WITH ranked_dates AS (SELECT UserCode,
|
|
||||||
date,
|
|
||||||
ROW_NUMBER() OVER (PARTITION BY UserCode ORDER BY date) AS rn
|
|
||||||
FROM WorkGridSchedules where IsDeleted = 0 and UserCode in ({p})
|
|
||||||
GROUP BY UserCode, date),
|
|
||||||
grouped AS (SELECT UserCode,
|
|
||||||
date,
|
|
||||||
DATE_SUB(date, INTERVAL rn DAY) AS grp
|
|
||||||
FROM ranked_dates),
|
|
||||||
streaks AS (SELECT UserCode,
|
|
||||||
grp,
|
|
||||||
COUNT(*) AS streak_days,
|
|
||||||
MIN(date) AS start_date,
|
|
||||||
MAX(date) AS end_date
|
|
||||||
FROM grouped
|
|
||||||
GROUP BY UserCode, grp
|
|
||||||
HAVING streak_days >= @days)
|
|
||||||
SELECT UserCode, streak_days as Count, start_date as Start, end_date as End
|
|
||||||
FROM streaks
|
|
||||||
where (@dateBefore >= start_date
|
|
||||||
and @dateBefore <= end_date)
|
|
||||||
or (@dateAfter >= start_date
|
|
||||||
and @dateAfter <= end_date);
|
|
||||||
|
|
||||||
";
|
|
||||||
|
|
||||||
var data = await _dbContext.Client.Ado.SqlQueryAsync<WorkGridScheduleMaximumConsecutiveDto>(sql, values);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
using Dlhis.Basic.Common.ApiLog.Services;
|
using Dlhis.Basic.Common.ApiLog.Services;
|
||||||
|
using Dlhis.Basic.WorkGrids.Repositories;
|
||||||
using Dlhis.Basic.WorkGrids.Request;
|
using Dlhis.Basic.WorkGrids.Request;
|
||||||
using Dlhis.Basic.WorkGrids.Response;
|
using Dlhis.Basic.WorkGrids.Response;
|
||||||
|
using Dlhis.Basic.WorkGrids.Validations;
|
||||||
using Dlhis.Constants;
|
using Dlhis.Constants;
|
||||||
using Dlhis.Entity.Basic.Entity;
|
using Dlhis.Entity.Basic.Entity;
|
||||||
using Dlhis.Entity.Basic.Enums;
|
using Dlhis.Entity.Basic.Enums;
|
||||||
@@ -19,17 +21,20 @@ public class WorkGridService : IWorkGridService
|
|||||||
{
|
{
|
||||||
private readonly IDbContext _dbContext;
|
private readonly IDbContext _dbContext;
|
||||||
private readonly ICurrentUser _currentUser;
|
private readonly ICurrentUser _currentUser;
|
||||||
private readonly IWorkGridScheduleService _workGridScheduleService;
|
private readonly IWorkGridValidateService _workGridValidateService;
|
||||||
|
private readonly IWorkGridScheduleRepository _workGridScheduleRepository;
|
||||||
private readonly IOperateLog _operateLog;
|
private readonly IOperateLog _operateLog;
|
||||||
|
|
||||||
public WorkGridService(IDbContext dbContext,
|
public WorkGridService(IDbContext dbContext,
|
||||||
ICurrentUser currentUser,
|
ICurrentUser currentUser,
|
||||||
IWorkGridScheduleService workGridScheduleService,
|
IWorkGridValidateService workGridValidateService,
|
||||||
|
IWorkGridScheduleRepository workGridScheduleRepository,
|
||||||
IOperateLog operateLog)
|
IOperateLog operateLog)
|
||||||
{
|
{
|
||||||
_dbContext = dbContext;
|
_dbContext = dbContext;
|
||||||
_currentUser = currentUser;
|
_currentUser = currentUser;
|
||||||
_workGridScheduleService = workGridScheduleService;
|
_workGridValidateService = workGridValidateService;
|
||||||
|
_workGridScheduleRepository = workGridScheduleRepository;
|
||||||
_operateLog = operateLog;
|
_operateLog = operateLog;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +43,7 @@ public class WorkGridService : IWorkGridService
|
|||||||
{
|
{
|
||||||
var factory = _currentUser.GetStringTenantId();
|
var factory = _currentUser.GetStringTenantId();
|
||||||
|
|
||||||
var r = await _dbContext.Queryable<GainfoEntity>()
|
var pagination = await _dbContext.Queryable<GainfoEntity>()
|
||||||
.LeftJoin<DepartmentEntity>((x, dept) => x.DepartmentNo == dept.No)
|
.LeftJoin<DepartmentEntity>((x, dept) => x.DepartmentNo == dept.No)
|
||||||
.LeftJoin<WorkGridUserEntity>((x, dept, wgu) => x.Code == wgu.UserCode)
|
.LeftJoin<WorkGridUserEntity>((x, dept, wgu) => x.Code == wgu.UserCode)
|
||||||
.LeftJoin<WorkGridEntity>((x, dept, wgu, wg) => wgu.WorkGridCode == wg.Code)
|
.LeftJoin<WorkGridEntity>((x, dept, wgu, wg) => wgu.WorkGridCode == wg.Code)
|
||||||
@@ -59,50 +64,29 @@ public class WorkGridService : IWorkGridService
|
|||||||
})
|
})
|
||||||
.ToPageListAsync(request);
|
.ToPageListAsync(request);
|
||||||
|
|
||||||
var userCodes = r.Data.Select(x => x.Code).ToList();
|
var userCodeList = pagination.Data.Select(x => x.Code).ToList();
|
||||||
if (userCodes.Any())
|
if (userCodeList.Any())
|
||||||
{
|
{
|
||||||
var maximumConsecutiveUserCodes = await _workGridScheduleService.MaximumConsecutiveUserCodesAsync(userCodes, 1, DateOnly.FromDateTime(request.Date));
|
var maximumConsecutiveUserCodeList = await _workGridScheduleRepository.MaximumConsecutiveUserCodesAsync(userCodeList, 1, DateOnly.FromDateTime(request.Date));
|
||||||
|
|
||||||
foreach (var item in r.Data)
|
foreach (var item in pagination.Data)
|
||||||
{
|
{
|
||||||
item.MaximumConsecutiveSchedules = maximumConsecutiveUserCodes.FirstOrDefault(x => x.UserCode == item.Code);
|
item.MaximumConsecutiveSchedules = maximumConsecutiveUserCodeList.FirstOrDefault(x => x.UserCode == item.Code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return pagination;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public async Task SaveAsync(List<WorkGridSaveRequest> requests)
|
public async Task SaveAsync(List<WorkGridSaveRequest> requests)
|
||||||
{
|
{
|
||||||
var factory = _currentUser.GetStringTenantId();
|
await _workGridValidateService.ValidateSaveAsync(requests);
|
||||||
|
|
||||||
var insertGrids = new List<string>();
|
var insertGrids = new List<string>();
|
||||||
var updateGrids = new List<string>();
|
var updateGrids = new List<string>();
|
||||||
|
|
||||||
var leaderUserCodes = requests.Select(x => x.LeaderUserCode).Distinct().ToList();
|
|
||||||
var existsUserInfos = await _dbContext.Queryable<GainfoEntity>()
|
|
||||||
.Where(x => leaderUserCodes.Contains(x.Code))
|
|
||||||
.Select(x => new { x.Code, x.Factory })
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
var excludeCodes = existsUserInfos.Where(x => x.Factory != factory).Select(x => x.Code).ToList();
|
|
||||||
excludeCodes.ThrowIfExists($"工号:{excludeCodes.Join(",")}不属于当前厂区");
|
|
||||||
|
|
||||||
var existsUserCodes = existsUserInfos.Select(x => x.Code).ToList();
|
|
||||||
var notExistsUserCodes = leaderUserCodes.Except(existsUserCodes).ToList();
|
|
||||||
notExistsUserCodes.ThrowIfExists($"工号:{notExistsUserCodes.Join(",")}不存在");
|
|
||||||
|
|
||||||
foreach (var request in requests)
|
foreach (var request in requests)
|
||||||
{
|
{
|
||||||
if (await _dbContext.Queryable<WorkGridEntity>().Where(x => x.Name == request.Name)
|
|
||||||
.WhereIF(request.Id.HasValue, x => x.Id != request.Id)
|
|
||||||
.AnyAsync())
|
|
||||||
{
|
|
||||||
true.ThrowIfTrue($"网格区域名称[{request.Name}]重复");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!request.Id.HasValue)
|
if (!request.Id.HasValue)
|
||||||
{
|
{
|
||||||
var exists = await _dbContext.Queryable<WorkGridEntity>()
|
var exists = await _dbContext.Queryable<WorkGridEntity>()
|
||||||
@@ -145,7 +129,6 @@ public class WorkGridService : IWorkGridService
|
|||||||
await _operateLog.LogAsync(OperateLogType.WorkGrid, "修改网格:" + updateGrids.Join("\r\n"));
|
await _operateLog.LogAsync(OperateLogType.WorkGrid, "修改网格:" + updateGrids.Join("\r\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public async Task<Pagination<WorkGridPageResponse>> GetPageAsync(WorkGridPageRequest request)
|
public async Task<Pagination<WorkGridPageResponse>> GetPageAsync(WorkGridPageRequest request)
|
||||||
{
|
{
|
||||||
var role = _currentUser.GetRole();
|
var role = _currentUser.GetRole();
|
||||||
@@ -190,7 +173,6 @@ public class WorkGridService : IWorkGridService
|
|||||||
.ToPageListAsync(request);
|
.ToPageListAsync(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public async Task ChangeAsync(string from, string to)
|
public async Task ChangeAsync(string from, string to)
|
||||||
{
|
{
|
||||||
if (await _dbContext.Queryable<WorkGridEntity>().Where(x => x.LeaderUserCode == to).AnyAsync())
|
if (await _dbContext.Queryable<WorkGridEntity>().Where(x => x.LeaderUserCode == to).AnyAsync())
|
||||||
@@ -216,7 +198,6 @@ public class WorkGridService : IWorkGridService
|
|||||||
await _operateLog.LogAsync(OperateLogType.WorkGrid, $"网格({workGrid.Name})修改负责人{from}->{to}");
|
await _operateLog.LogAsync(OperateLogType.WorkGrid, $"网格({workGrid.Name})修改负责人{from}->{to}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public async Task<WorkGridUserPageResponse> GetMyWorkGridAsync(WorkGridPageRequest request)
|
public async Task<WorkGridUserPageResponse> GetMyWorkGridAsync(WorkGridPageRequest request)
|
||||||
{
|
{
|
||||||
var currentUserCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode);
|
var currentUserCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode);
|
||||||
@@ -253,11 +234,11 @@ public class WorkGridService : IWorkGridService
|
|||||||
var userCodes = myWorkGrid.UserInfos.Select(x => x.Code).ToList();
|
var userCodes = myWorkGrid.UserInfos.Select(x => x.Code).ToList();
|
||||||
if (userCodes.Any())
|
if (userCodes.Any())
|
||||||
{
|
{
|
||||||
var maximumConsecutiveUserCodes = await _workGridScheduleService.MaximumConsecutiveUserCodesAsync(userCodes, 1, DateOnly.FromDateTime(request.Date));
|
var maximumConsecutiveUserCodeList = await _workGridScheduleRepository.MaximumConsecutiveUserCodesAsync(userCodes, 1, DateOnly.FromDateTime(request.Date));
|
||||||
|
|
||||||
foreach (var item in myWorkGrid.UserInfos)
|
foreach (var item in myWorkGrid.UserInfos)
|
||||||
{
|
{
|
||||||
item.MaximumConsecutiveSchedules = maximumConsecutiveUserCodes.FirstOrDefault(x => x.UserCode == item.Code);
|
item.MaximumConsecutiveSchedules = maximumConsecutiveUserCodeList.FirstOrDefault(x => x.UserCode == item.Code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,7 +246,6 @@ public class WorkGridService : IWorkGridService
|
|||||||
return myWorkGrid;
|
return myWorkGrid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public async Task AssignAsync(WorkGridUserAssignRequest request)
|
public async Task AssignAsync(WorkGridUserAssignRequest request)
|
||||||
{
|
{
|
||||||
var currentFactory = _currentUser.GetStringTenantId();
|
var currentFactory = _currentUser.GetStringTenantId();
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using Dlhis.Basic.WorkGrids.Request;
|
||||||
|
|
||||||
|
namespace Dlhis.Basic.WorkGrids.Validations;
|
||||||
|
|
||||||
|
public interface IWorkGridValidateService : IScopeDependency
|
||||||
|
{
|
||||||
|
Task ValidateSaveAsync(List<WorkGridSaveRequest> requests);
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
using Dlhis.Basic.WorkGrids.Request;
|
||||||
|
using Dlhis.Entity.Basic.Entity;
|
||||||
|
using Kurisu.AspNetCore.Authentication.Abstractions;
|
||||||
|
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
||||||
|
using Kurisu.AspNetCore.Utils.Extensions;
|
||||||
|
|
||||||
|
namespace Dlhis.Basic.WorkGrids.Validations.Implements
|
||||||
|
{
|
||||||
|
public class WorkGridValidateService : IWorkGridValidateService
|
||||||
|
{
|
||||||
|
private readonly ICurrentUser _currentUser;
|
||||||
|
private readonly IDbContext _dbContext;
|
||||||
|
|
||||||
|
public WorkGridValidateService(ICurrentUser currentUser, IDbContext dbContext)
|
||||||
|
{
|
||||||
|
_currentUser = currentUser;
|
||||||
|
_dbContext = dbContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证保存请求
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="requests"></param>
|
||||||
|
public async Task ValidateSaveAsync(List<WorkGridSaveRequest> requests)
|
||||||
|
{
|
||||||
|
var duplicateUserCodes = requests.GroupBy(x => x.LeaderUserCode)
|
||||||
|
.Where(g => g.Count() > 1)
|
||||||
|
.Select(g => g.Key)
|
||||||
|
.ToList();
|
||||||
|
duplicateUserCodes.ThrowIfExists($"请求中存在重复工号:{duplicateUserCodes.Join(",")}");
|
||||||
|
|
||||||
|
var duplicateNames = requests.GroupBy(x => x.Name)
|
||||||
|
.Where(g => g.Count() > 1)
|
||||||
|
.Select(g => g.Key)
|
||||||
|
.ToList();
|
||||||
|
duplicateNames.ThrowIfExists($"请求中存在重复网格名称:{duplicateNames.Join(",")}");
|
||||||
|
|
||||||
|
var factory = _currentUser.GetStringTenantId();
|
||||||
|
|
||||||
|
var leaderUserCodes = requests.Select(x => x.LeaderUserCode).Distinct().ToList();
|
||||||
|
var userCodeWithFactories = await _dbContext.Queryable<GainfoEntity>()
|
||||||
|
.Where(x => leaderUserCodes.Contains(x.Code))
|
||||||
|
.Select(x => new { x.Code, x.Factory })
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
//检查工号是否存在
|
||||||
|
var existsUserCodes = userCodeWithFactories.Select(x => x.Code).ToList();
|
||||||
|
var notExistsUserCodes = leaderUserCodes.Except(existsUserCodes).ToList();
|
||||||
|
notExistsUserCodes.ThrowIfExists($"工号:{notExistsUserCodes.Join(",")}不存在");
|
||||||
|
|
||||||
|
//检查负责人工号是否存在
|
||||||
|
var excludeCodes = userCodeWithFactories
|
||||||
|
.Where(x => x.Factory != factory)
|
||||||
|
.Select(x => x.Code)
|
||||||
|
.ToList();
|
||||||
|
excludeCodes.ThrowIfExists($"工号:{excludeCodes.Join(",")}不属于当前厂区");
|
||||||
|
|
||||||
|
//检查网格名称是否重复
|
||||||
|
var where = LinqExpressionExtensions.False<WorkGridEntity>();
|
||||||
|
foreach (var req in requests)
|
||||||
|
{
|
||||||
|
where = req.Id.HasValue
|
||||||
|
? where.Or(x => x.Name == req.Name && x.Id != req.Id.Value)
|
||||||
|
: where.Or(x => x.Name == req.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
var existsNames = await _dbContext.Queryable<WorkGridEntity>().Where(where).Select(x => x.Name).ToListAsync();
|
||||||
|
if (existsNames.Any())
|
||||||
|
{
|
||||||
|
true.ThrowIfTrue($"网格区域名称[{existsNames.Join(",")}]重复");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
},
|
},
|
||||||
"SwaggerOptions": {
|
"SwaggerOptions": {
|
||||||
"Enable": true,
|
"Enable": true,
|
||||||
"Authority": "http://localhost:5000",
|
"Authority": "https://park.yaens.com/oauth2",
|
||||||
"ClientId": "98958aa485d38412",
|
"ClientId": "98958aa485d38412",
|
||||||
"ClientSecret": "52589e011f02fe19",
|
"ClientSecret": "52589e011f02fe19",
|
||||||
"Scopes": {
|
"Scopes": {
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"IdentityServerOptions": {
|
"IdentityServerOptions": {
|
||||||
"Authority": "http://localhost:5000",
|
"Authority": "https://park.yaens.com/oauth2",
|
||||||
"RequireHttpsMetadata": false,
|
"RequireHttpsMetadata": false,
|
||||||
"Issuer": "identity.isawesome.cn",
|
"Issuer": "identity.isawesome.cn",
|
||||||
"Audience": "",
|
"Audience": "",
|
||||||
|
|||||||
@@ -34,9 +34,9 @@
|
|||||||
},
|
},
|
||||||
"SwaggerOptions": {
|
"SwaggerOptions": {
|
||||||
"Enable": true,
|
"Enable": true,
|
||||||
"Authority": "http://identity.oauth.svc.cluster.local",
|
"Authority": "https://192.168.199.124/oauth2",
|
||||||
"ClientId": "4fb184324eac4180",
|
"ClientId": "98958aa485d38412",
|
||||||
"ClientSecret": "8ac8f235152f1524",
|
"ClientSecret": "52589e011f02fe19",
|
||||||
"Scopes": {
|
"Scopes": {
|
||||||
"openid": "openid",
|
"openid": "openid",
|
||||||
"profile": "profile",
|
"profile": "profile",
|
||||||
@@ -47,10 +47,10 @@
|
|||||||
"ConnectionString": "192.168.199.124:6379,defaultDatabase=1,password=dlhis123"
|
"ConnectionString": "192.168.199.124:6379,defaultDatabase=1,password=dlhis123"
|
||||||
},
|
},
|
||||||
"IdentityServerOptions": {
|
"IdentityServerOptions": {
|
||||||
"Authority": "http://identity.oauth.svc.cluster.local",
|
"Authority": "https://192.168.199.124/oauth2",
|
||||||
"RequireHttpsMetadata": false,
|
"RequireHttpsMetadata": false,
|
||||||
"Issuer": "identity.isawesome.cn",
|
"Issuer": "identity.isawesome.cn",
|
||||||
"Audience": "",
|
"Audience": "yikatong",
|
||||||
"Pat": {
|
"Pat": {
|
||||||
"Enable": false,
|
"Enable": false,
|
||||||
"Scheme": "token",
|
"Scheme": "token",
|
||||||
@@ -60,8 +60,8 @@
|
|||||||
},
|
},
|
||||||
"MinIO": {
|
"MinIO": {
|
||||||
"Endpoint": "http://192.168.199.124:9000",
|
"Endpoint": "http://192.168.199.124:9000",
|
||||||
"AccessKey": "bmQOlK0COe5nL56kzGd3",
|
"AccessKey": "7z9Aeat9givpNbnAt36T",
|
||||||
"SecretKey": "Udc5uBrGcT2yukfGXQtHKpqLQ27L1FmbrLyYunBr",
|
"SecretKey": "tW3WqS1wQZMbIrXKZokyxfF0CDL4vqrthTUNVMdB",
|
||||||
"DefaultBucket": "apk"
|
"DefaultBucket": "apk"
|
||||||
},
|
},
|
||||||
"Serilog": {
|
"Serilog": {
|
||||||
@@ -75,24 +75,17 @@
|
|||||||
},
|
},
|
||||||
"WriteTo": [
|
"WriteTo": [
|
||||||
{
|
{
|
||||||
"Name": "Async",
|
"Name": "Console",
|
||||||
"Args": {
|
"Args": {
|
||||||
"configure": [
|
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}"
|
||||||
{
|
}
|
||||||
"Name": "Console",
|
},
|
||||||
"Args": {
|
{
|
||||||
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}"
|
"Name": "MySQL",
|
||||||
}
|
"Args": {
|
||||||
},
|
"connectionString": "server=192.168.199.124;port=3306;userid=root;password=dlhis123;database=log;charset=utf8mb4;",
|
||||||
{
|
"tableName": "Logs",
|
||||||
"Name": "MySQL",
|
"autoCreateSqlTable": true
|
||||||
"Args": {
|
|
||||||
"connectionString": "server=192.168.199.124;port=3306;userid=root;password=dlhis123;database=log;charset=utf8mb4;",
|
|
||||||
"tableName": "Logs",
|
|
||||||
"autoCreateSqlTable": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user