Files
jinko.yikatong/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs
2025-03-11 11:04:37 +08:00

279 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Dlhis.Basic.Common.ApiLog.Services;
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 ICurrentUser _currentUser;
public WorkGridScheduleService(IDbContext dbContext,
IJinkoJipApi jinkoJipApi,
IOperateLog operateLog,
ICurrentUser currentUser)
{
_dbContext = dbContext;
_jinkoJipApi = jinkoJipApi;
_operateLog = operateLog;
_currentUser = currentUser;
}
public async Task SaveAsync(WorkGridScheduleSaveRequest request)
{
var workGrid = await _dbContext.Queryable<WorkGridEntity>().SingleAsync(x => x.Code == request.WorkGridCode);
workGrid.ThrowIfNull("工作网格不存在");
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 maximumConsecutiveDtos = await MaximumConsecutiveUserCodesAsync(request.UserCodes, 10, request.Date);
//张三(工号)已连续排班10天,超10休1规定,禁止排班,请处理
maximumConsecutiveDtos.ThrowIfExists(maximumConsecutiveDtos.Select(x => $"{x.UserCode}已经连续排班10天({x.Start}-{x.End}),超10休1规定,禁止排班").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(",")}");
}
/// <inheritdoc />
public async Task RemoveAsync(WorkGridScheduleSaveRequest request)
{
var workGrid = await _dbContext.Queryable<WorkGridEntity>().SingleAsync(x => x.Code == request.WorkGridCode);
workGrid.ThrowIfNull("工作网格不存在");
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();
await _dbContext.DeleteAsync(data);
await _operateLog.LogAsync(OperateLogType.WorkGrid, $"移除网格({workGrid.Name}){request.Date.ToString("yyyy-M-d")}的{request.PeriodType.GetDescription()}人员:{request.UserCodes.Join(",")}");
}
/// <inheritdoc />
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
{
Date = x.Date,
PeriodType = x.PeriodType,
UserCode = x.UserCode,
UserName = ga.Name
})
.ToListAsync();
return data;
}
/// <inheritdoc />
public async Task<IEnumerable<WorkGridScheduleSummaryResponse>> GetListSummaryAsync(Guid workGridCode, DateOnly start, DateOnly end)
{
var workGridSchedules = await _dbContext.Queryable<WorkGridScheduleEntity>()
.Where(x => x.WorkGridCode == workGridCode && x.Date >= start && x.Date <= end)
.ToListAsync();
return workGridSchedules.GroupBy(x => x.Date).Select(x =>
{
return new WorkGridScheduleSummaryResponse
{
Date = x.Key,
Details = x.GroupBy(p => p.PeriodType).Select(p => new WorkGridScheduleSummaryDetailResponse
{
PeriodType = p.Key,
Count = p.Count()
})
};
});
}
/// <inheritdoc />
public async Task<Pagination<WorkGridScheduleAttendancePageResponse>> GetAttendancePageAsync(WorkGridScheduleAttendancePageRequest request)
{
var jinkoCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode);
var workGrid = await _dbContext.Queryable<WorkGridEntity>().Where(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}";
return 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).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);
}
/// <inheritdoc />
public async Task ManuallyUploadAsync(List<long> logIds)
{
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)
.Where(x => ids.Contains(x.Id))
.ExecuteCommandAsync();
}
}
}
await _operateLog.LogAsync(OperateLogType.WorkGrid, $"重提上传考勤:{requests.Select(x => x.Id).Join(",")}");
}
public async Task<List<WorkGridScheduleMaximumConsecutiveDto>> MaximumConsecutiveUserCodesAsync(List<string> userCodes, int days, DateOnly date)
{
var p = userCodes.Select(x => $"@param{x}").Join(",");
var values = userCodes.ToDictionary(x => $"param{x}", 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;
}
}