Files
jinko.yikatong/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs
2025-07-08 17:42:50 +08:00

460 lines
20 KiB
C#

using Dlhis.Basic.Common.ApiLog.Services;
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.Response;
using Dlhis.Constants;
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Basic.Enums;
using Dlhis.Entity.Common.Enums;
using Dlhis.Entity.Device.Entities;
using Dlhis.Entity.Device.Enums;
using Dlhis.Jip.Api;
using Dlhis.Jip.Api.Requests;
using Kurisu.AspNetCore.Authentication.Abstractions;
using Kurisu.AspNetCore.CustomClass;
using Kurisu.AspNetCore.DataAccess.Dto;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
using Kurisu.AspNetCore.Utils.Extensions;
using SqlSugar;
namespace Dlhis.Basic.WorkGrids.Services.Implements;
public class WorkGridScheduleService : IWorkGridScheduleService
{
private readonly IDbContext _dbContext;
private readonly IJinkoJipApi _jinkoJipApi;
private readonly IOperateLog _operateLog;
private readonly ILogger<WorkGridScheduleService> _logger;
private readonly IJinkoApiService _jinkoApiService;
private readonly IWorkGridScheduleRepository _workGridScheduleRepository;
private readonly ICurrentUser _currentUser;
public WorkGridScheduleService(IDbContext dbContext,
IJinkoJipApi jinkoJipApi,
IOperateLog operateLog,
ILogger<WorkGridScheduleService> logger,
IJinkoApiService jinkoApiService,
IWorkGridScheduleRepository workGridScheduleRepository,
ICurrentUser currentUser)
{
_dbContext = dbContext;
_jinkoJipApi = jinkoJipApi;
_operateLog = operateLog;
_logger = logger;
_jinkoApiService = jinkoApiService;
_workGridScheduleRepository = workGridScheduleRepository;
_currentUser = currentUser;
}
public async Task SaveAsync(WorkGridScheduleSaveRequest request)
{
request.UserCodes = request.UserCodes.Distinct().ToList();
var workGrid = await _dbContext.Queryable<WorkGridEntity>()
.LeftJoin<GainfoEntity>((x, ga) => x.LeaderUserCode == ga.Code)
.Where(x => x.Code == request.WorkGridCode)
.Select((x, ga) => new
{
x.Code, x.Name,
x.LeaderUserCode,
LeaderUserName = ga.Name,
x.MaxConsecutiveLimitCount
})
.SingleAsync();
workGrid.ThrowIfNull("工作网格不存在");
var timeSetting = await _dbContext.Queryable<WorkGridTimePeriodEntity>()
.Where(x => x.Type == request.PeriodType)
.Select(x => new { x.Start, x.Before })
.SingleAsync();
timeSetting.ThrowIfNull("工作网格时间尚未配置,无法操作");
var currentLimit = request.Date.ToDateTime(timeSetting.Start.Add(-TimeSpan.FromHours(1)));
(DateTime.Now >= currentLimit).ThrowIfTrue("当前时间不可修改排班信息");
var workGridUserCodes = await _dbContext.Queryable<WorkGridUserEntity>()
.Where(x => x.WorkGridCode == workGrid.Code && request.UserCodes.Contains(x.UserCode))
.Select(x => x.UserCode)
.ToListAsync();
var others = request.UserCodes.Except(workGridUserCodes).ToList();
others.ThrowIfExists($"{others.Join(",")}非当前网格人员");
var dateBefore = request.Date.AddDays(-1);
var dateAfter = request.Date.AddDays(1);
var scheduleRange = await _dbContext.Queryable<WorkGridScheduleEntity>()
.Where(x => x.WorkGridCode == request.WorkGridCode
&& x.Date >= dateBefore && x.Date <= dateAfter
&& request.UserCodes.Contains(x.UserCode)
)
.ToListAsync();
var existsUserCodes = scheduleRange.Where(x => x.Date == request.Date && request.UserCodes.Contains(x.UserCode)).Select(x => x.UserCode).ToList();
existsUserCodes.ThrowIfExists(existsUserCodes.Join(",") + "当天已存在排班");
if (request.PeriodType == WorkGridTimePeriodEnumType.Day)
{
existsUserCodes = scheduleRange
.Where(x => x.Date == dateBefore && x.PeriodType == WorkGridTimePeriodEnumType.Night && request.UserCodes.Contains(x.UserCode))
.Select(x => x.UserCode).ToList();
existsUserCodes.ThrowIfExists(existsUserCodes.Join(",") + $"在{dateBefore.ToString("yyyy-MM-dd")}已存在{WorkGridTimePeriodEnumType.Night.GetDescription()}");
}
else if (request.PeriodType == WorkGridTimePeriodEnumType.Night)
{
existsUserCodes = scheduleRange
.Where(x => x.Date == dateAfter && x.PeriodType == WorkGridTimePeriodEnumType.Day && request.UserCodes.Contains(x.UserCode))
.Select(x => x.UserCode).ToList();
existsUserCodes.ThrowIfExists(existsUserCodes.Join(",") + $"在{dateAfter.ToString("yyyy-MM-dd")}已存在{WorkGridTimePeriodEnumType.Day.GetDescription()}");
}
var maximumConsecutiveListDto = await _workGridScheduleRepository.MaximumConsecutiveUserCodesAsync(request.UserCodes, workGrid.MaxConsecutiveLimitCount, request.Date);
maximumConsecutiveListDto.ThrowIfExists(maximumConsecutiveListDto.Select(x => $"{x.UserCode}已经连续排班{workGrid.MaxConsecutiveLimitCount}天({x.Start}-{x.End}),禁止排班").Join("\r\n"));
var toInserts = request.UserCodes.Select(x => new WorkGridScheduleEntity
{
WorkGridCode = request.WorkGridCode,
Date = request.Date,
PeriodType = request.PeriodType,
UserCode = x
}).ToList();
await _dbContext.InsertAsync(toInserts);
await _operateLog.LogAsync(OperateLogType.WorkGrid, $"新增网格({workGrid.Name}){request.Date.ToString("yyyy-M-d")}的{request.PeriodType.GetDescription()}人员:{request.UserCodes.Join(",")}");
try
{
var codeAndNameList = await _dbContext.Queryable<GainfoEntity>().Where(x => request.UserCodes.Contains(x.Code))
.Select(x => new { x.Code, x.Name })
.ToListAsync();
foreach (var gainfo in codeAndNameList)
{
try
{
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()},请按时上班",
WorkCodes = new List<string> { gainfo.Code }
});
}
catch (Exception e)
{
_logger.LogError("推送信息错误{code}:{error}", gainfo.Code, e.Message);
}
}
}
catch (Exception e)
{
_logger.LogError("推送信息错误save,{error}", e.Message);
}
}
public async Task ManuallyCancelAsync(long id, string reason)
{
var currentDate = DateOnly.FromDateTime(DateTime.Today);
var workGridSchedule = await _dbContext.Queryable<WorkGridScheduleEntity>()
.Where(x => x.Date < currentDate)
.SingleAsync(x => x.Id == id);
workGridSchedule.ThrowIfNull("排班信息不存在或不可操作");
workGridSchedule.IsCancel.ThrowIfTrue("排班信息已被取消,请勿重复操作");
var start = workGridSchedule.Date.ToDateTime(TimeOnly.MinValue);
var end = workGridSchedule.Date.ToDateTime(TimeOnly.MaxValue);
var exists = await _dbContext.Queryable<DeviceUploadLogEntity>().Where(x => x.UserUniqueNo == workGridSchedule.UserCode)
.Where(x => x.RaiseDateTime >= start && x.RaiseDateTime <= end).AnyAsync();
exists.ThrowIfTrue("排班信息已存在打卡记录,请勿取消");
await _workGridScheduleRepository.CancelAsync(id, reason);
}
public async Task<object> TestAsync(WorkGridScheduleSaveRequest request)
{
request.UserCodes = request.UserCodes.Distinct().ToList();
var workGrid = await _dbContext.Queryable<WorkGridEntity>()
.LeftJoin<GainfoEntity>((x, ga) => x.LeaderUserCode == ga.Code)
.Where(x => x.Code == request.WorkGridCode)
.Select((x, ga) => new
{
x.Code, x.Name,
x.LeaderUserCode,
LeaderUserName = ga.Name,
x.MaxConsecutiveLimitCount
})
.SingleAsync();
workGrid.ThrowIfNull("工作网格不存在");
var timeSetting = await _dbContext.Queryable<WorkGridTimePeriodEntity>().Where(x => x.Type == request.PeriodType).Select(x => new { x.Start, x.Before }).SingleAsync();
timeSetting.ThrowIfNull("工作网格时间尚未配置,无法操作");
var currentLimit = request.Date.ToDateTime(timeSetting.Start.Add(-TimeSpan.FromHours(1)));
(DateTime.Now >= currentLimit).ThrowIfTrue("当前时间不可修改排班信息");
return currentLimit;
}
/// <inheritdoc />
public async Task RemoveAsync(WorkGridScheduleSaveRequest request)
{
var workGrid = await _dbContext.Queryable<WorkGridEntity>()
.LeftJoin<GainfoEntity>((x, ga) => x.LeaderUserCode == ga.Code)
.Where(x => x.Code == request.WorkGridCode)
.Select((x, ga) => new
{
x.Code, x.Name,
x.LeaderUserCode,
LeaderUserName = ga.Name
})
.SingleAsync();
workGrid.ThrowIfNull("工作网格不存在");
var timeSetting = await _dbContext.Queryable<WorkGridTimePeriodEntity>().Where(x => x.Type == request.PeriodType).Select(x => new { x.Start, x.Before }).SingleAsync();
var currentLimit = request.Date.ToDateTime(timeSetting.Start.Add(-TimeSpan.FromSeconds(timeSetting.Before)));
(DateTime.Now >= currentLimit).ThrowIfTrue("当前时间不可修改排班信息");
var data = await _dbContext.Queryable<WorkGridScheduleEntity>()
.Where(x => x.WorkGridCode == request.WorkGridCode)
.Where(x => x.Date == request.Date)
.Where(x => x.PeriodType == request.PeriodType)
.Where(x => request.UserCodes.Contains(x.UserCode))
.ToListAsync();
if (data.Any())
{
await _dbContext.DeleteAsync(data);
await _operateLog.LogAsync(OperateLogType.WorkGrid, $"移除网格({workGrid.Name}){request.Date.ToString("yyyy-M-d")}的{request.PeriodType.GetDescription()}人员:{request.UserCodes.Join(",")}");
try
{
var userCodes = data.Select(x => x.UserCode).Distinct().ToList();
var gainfos = await _dbContext.Queryable<GainfoEntity>().Where(x => userCodes.Contains(x.Code)).Select(x => new { x.Code, x.Name }).ToListAsync();
foreach (var gainfo in gainfos)
{
try
{
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()},如有疑问,请联系网格长!",
WorkCodes = new List<string> { gainfo.Code }
});
}
catch (Exception e)
{
_logger.LogError("推送信息错误{code}:{error}", gainfo.Code, e.Message);
}
}
}
catch (Exception e)
{
_logger.LogError("推送信息错误remove,{error}", e.Message);
}
}
}
public async Task<List<WorkGridScheduleResponse>> GetListAsync(Guid workGridCode, DateOnly date, WorkGridTimePeriodEnumType? periodType)
{
var data = await _dbContext.Queryable<WorkGridScheduleEntity>()
.LeftJoin<GainfoEntity>((x, ga) => x.UserCode == ga.Code)
.Where(x => x.WorkGridCode == workGridCode && x.Date == date)
.WhereIF(periodType.HasValue, x => x.PeriodType == periodType)
.Select((x, ga) => new WorkGridScheduleResponse
{
Id = x.Id,
Date = x.Date,
PeriodType = x.PeriodType,
UserCode = x.UserCode,
UserName = ga.Name,
IsCancel = x.IsCancel
})
.ToListAsync();
return data;
}
public async Task<List<WorkGridScheduleSummaryResponse>> GetListSummaryAsync(Guid workGridCode, DateTimePeriod dateTimePeriod)
{
var start = dateTimePeriod.Start!.Value;
var end = dateTimePeriod.End!.Value;
return await _workGridScheduleRepository.GetListSummaryAsync(workGridCode,
new DateOnly(start.Year, start.Month, start.Day),
new DateOnly(end.Year, end.Month, end.Day)
);
}
/// <inheritdoc />
public async Task<Pagination<WorkGridScheduleAttendancePageResponse>> GetAttendancePageAsync(WorkGridScheduleAttendancePageRequest request)
{
var jinkoCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode);
var workGrid = await _dbContext.Queryable<WorkGridEntity>()
.WhereIF(request.WorkGridCode.HasValue, x => x.Code == request.WorkGridCode)
.WhereIF(request.WorkGridCode.HasValue == false, x => x.LeaderUserCode == jinkoCode)
.SingleAsync();
if (workGrid == null)
{
return new Pagination<WorkGridScheduleAttendancePageResponse>
{
PageIndex = request.PageIndex,
PageSize = request.PageSize,
Total = 0,
Data = null
};
}
var t = request.IsError.ToString().ToLower();
var filterString = $"{{\"IsError\":{t}";
var r = await _dbContext.Queryable<DeviceUploadLogEntity>()
.LeftJoin<DeviceEntity>((log, d) => log.DeviceUniqueNo == d.UniqueNo)
.LeftJoin<GainfoEntity>((log, d, ga) => log.UserUniqueNo == ga.Code)
.WhereIF(request.DateTimePeriod.HasValue(), log => log.RaiseDateTime >= request.DateTimePeriod.Start
&& log.RaiseDateTime <= request.DateTimePeriod.End)
.WhereIF(request.UserCode.IsPresent(), log => log.UserUniqueNo == request.UserCode)
.WhereIF(request.UserCode.IsEmpty(), log => SqlFunc.Subqueryable<WorkGridUserEntity>()
.Where(p => p.WorkGridCode == workGrid.Code && p.UserCode == log.UserUniqueNo && p.IsDeleted == false)
.Any()
)
.Where(log => log.WorkGridInfo.StartsWith(filterString))
.Where((log, d) => d.Type == DeviceTypeEnumType.Attendance || (d.Type == DeviceTypeEnumType.Door && d.AsAttendance))
.OrderBy(log => log.RaiseDateTime)
.Select((log, d, ga) => new WorkGridScheduleAttendancePageResponse
{
Id = log.Id,
OriginUserUniqueNo = log.UserUniqueNo,
DeviceUniqueNo = log.DeviceUniqueNo,
RaiseDateTime = log.RaiseDateTime,
CreateTime = log.CreateTime,
SerialNo = log.SerialNo,
DeployPlace = d.DeployPlace,
UserCode = log.UserUniqueNo,
UserName = ga.Name,
Sync = log.Sync,
NeedUpload = log.NeedUpload,
Status = log.Status,
WorkGridInfo = log.WorkGridInfo,
})
.ToPageListAsync(request.PageIndex, request.PageSize);
return new Pagination<WorkGridScheduleAttendancePageResponse>
{
PageIndex = request.PageIndex,
PageSize = request.PageSize,
Total = 0,
Data = r
};
}
public async Task<Pagination<WorkGridScheduleAttendancePageResponse>> GetAllAttendancePageAsync(WorkGridScheduleAttendancePageRequest request)
{
var t = request.IsError.ToString().ToLower();
var filterString = $"{{\"IsError\":{t}";
if (request.UserCode.IsEmpty())
{
request.UserCode = request.Search;
}
var page = await _dbContext.Queryable<DeviceUploadLogEntity>()
.LeftJoin<DeviceEntity>((log, d) => log.DeviceUniqueNo == d.UniqueNo)
.LeftJoin<GainfoEntity>((log, d, ga) => log.UserUniqueNo == ga.Code)
.WhereIF(request.DateTimePeriod.HasValue(), log => log.RaiseDateTime >= request.DateTimePeriod.Start
&& log.RaiseDateTime <= request.DateTimePeriod.End)
.Where(log => SqlFunc.Subqueryable<WorkGridUserEntity>()
.Where(p => p.UserCode == log.UserUniqueNo && p.IsDeleted == false)
.WhereIF(request.WorkGridCode.HasValue, p => p.WorkGridCode == request.WorkGridCode)
.WhereIF(request.UserCode.IsPresent(), p => p.UserCode == request.UserCode)
.Any()
)
.Where(log => log.WorkGridInfo.StartsWith(filterString))
.Where((log, d) => d.Type == DeviceTypeEnumType.Attendance || (d.Type == DeviceTypeEnumType.Door && d.AsAttendance))
.OrderBy(log => log.RaiseDateTime, OrderByType.Desc)
.Select((log, d, ga) => new WorkGridScheduleAttendancePageResponse
{
Id = log.Id,
OriginUserUniqueNo = log.UserUniqueNo,
DeviceUniqueNo = log.DeviceUniqueNo,
RaiseDateTime = log.RaiseDateTime,
CreateTime = log.CreateTime,
SerialNo = log.SerialNo,
DeployPlace = d.DeployPlace,
UserCode = log.UserUniqueNo,
UserName = ga.Name,
Sync = log.Sync,
NeedUpload = log.NeedUpload,
Status = log.Status,
WorkGridInfo = log.WorkGridInfo,
})
.ToPageListAsync(request);
var leaderUserCodes = page.Data.Select(x => x.LeaderUserCode).Distinct().ToList();
var gainfos = await _dbContext.Queryable<GainfoEntity>().Where(x => leaderUserCodes.Contains(x.Code)).Select(x => new { x.Code, x.Name }).ToListAsync();
page.Data.ForEach(x =>
{
var gainfo = gainfos.FirstOrDefault(p => p.Code == x.LeaderUserCode);
if (gainfo != null)
{
x.LeaderUserName = gainfo.Name;
}
});
return page;
}
/// <inheritdoc />
public async Task ManuallyUploadAsync(List<long> logIds)
{
var sub = _currentUser.GetIntSubjectId();
const string filterString = "{\"IsError\":true";
var requests = await _dbContext.Queryable<DeviceUploadLogEntity>()
.LeftJoin<DeviceEntity>((x, device) => x.DeviceUniqueNo == device.UniqueNo)
.Where(x => logIds.Contains(x.Id) && x.Sync == false)
.Where(x => x.WorkGridInfo.StartsWith(filterString))
.Select((x, device) => new UploadAttendanceRequestItem
{
Id = x.Id,
RaiseDateTime = x.RaiseDateTime,
ZNOTE = device.DeployPlace,
ZWORKCODE = x.UserUniqueNo
})
.ToListAsync();
if (requests.Any())
{
foreach (var items in requests.Chunk(500))
{
var ids = items.Select(x => x.Id).ToList();
var r = await _jinkoJipApi.UploadAttendancesAsync(new UploadAttendanceRequest { Data = items.ToList() });
if (r.OLX == "0")
{
await _dbContext.Updateable<DeviceUploadLogEntity>()
.SetColumns(x => x.Sync == true)
.SetColumns(x => x.ModifiedTime == DateTime.Now)
.SetColumns(x => x.ModifiedBy == sub)
.Where(x => ids.Contains(x.Id))
.ExecuteCommandAsync();
await _operateLog.LogAsync(OperateLogType.WorkGrid, $"重提上传考勤{DateTime.Now:yyyy-MM-dd HH:mm:ss}:{items.Select(x => x.ZWORKCODE + $"打卡时间{x.RaiseDateTime:yyyy-MM-dd HH:mm:ss}").Join("\r\n")}");
}
}
}
}
}