From fae8a3a6f4da8116b6194cdcd7a089bdcff00ad4 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 18 Feb 2025 16:10:38 +0800 Subject: [PATCH 01/25] =?UTF-8?q?feat=20=E5=B7=A5=E4=BD=9C=E7=BD=91?= =?UTF-8?q?=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Src/Dlhis.Basic/Organization/Dto/GainfoDto.cs | 2 - .../Controllers/WorkGridsController.cs | 154 ++++++++++++++++++ .../Request/WorkGridChangeRequest.cs | 12 ++ .../WorkGrids/Request/WorkGridPageRequest.cs | 8 + .../WorkGrids/Request/WorkGridSaveRequest.cs | 22 +++ .../Request/WorkGridScheduleSaveRequest.cs | 14 ++ .../Request/WorkGridTimePeriodRequest.cs | 7 + .../Request/WorkGridTimePeriodSaveRequest.cs | 36 ++++ .../Request/WorkGridUserAssignRequest.cs | 14 ++ .../Request/WorkGridUserRemoveRequest.cs | 14 ++ .../Response/WorkGridPageResponse.cs | 31 ++++ .../Response/WorkGridScheduleResponse.cs | 12 ++ .../WorkGridScheduleSummaryResponse.cs | 16 ++ .../WorkGridTimePeriodPageResponse.cs | 72 ++++++++ .../Response/WorkGridUserPageResponse.cs | 57 +++++++ .../Services/IWorkGridScheduleService.cs | 16 ++ .../WorkGrids/Services/IWorkGridService.cs | 52 ++++++ .../Services/IWorkGridTimePeriodService.cs | 25 +++ .../Implements/WorkGridScheduleService.cs | 81 +++++++++ .../Services/Implements/WorkGridService.cs | 154 ++++++++++++++++++ .../Implements/WorkGridTimePeriodService.cs | 93 +++++++++++ .../Basic/Entity/WorkGridEntity.cs | 37 +++++ .../Basic/Entity/WorkGridScheduleEntity.cs | 42 +++++ .../Basic/Entity/WorkGridTimePeriodEntity.cs | 44 +++++ .../Basic/Entity/WorkGridUserEntity.cs | 35 ++++ .../Basic/Enums/WorkGridTimePeriodEnumType.cs | 22 +++ 26 files changed, 1070 insertions(+), 2 deletions(-) create mode 100644 Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridChangeRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridPageRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridSaveRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleSaveRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridTimePeriodRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridTimePeriodSaveRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridUserAssignRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridUserRemoveRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Response/WorkGridPageResponse.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleResponse.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleSummaryResponse.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Response/WorkGridTimePeriodPageResponse.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Response/WorkGridUserPageResponse.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Services/IWorkGridService.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Services/IWorkGridTimePeriodService.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs create mode 100644 Src/Dlhis.Entity/Basic/Entity/WorkGridEntity.cs create mode 100644 Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs create mode 100644 Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs create mode 100644 Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs create mode 100644 Src/Dlhis.Entity/Basic/Enums/WorkGridTimePeriodEnumType.cs diff --git a/Src/Dlhis.Basic/Organization/Dto/GainfoDto.cs b/Src/Dlhis.Basic/Organization/Dto/GainfoDto.cs index 0b378beb..0cf86880 100644 --- a/Src/Dlhis.Basic/Organization/Dto/GainfoDto.cs +++ b/Src/Dlhis.Basic/Organization/Dto/GainfoDto.cs @@ -21,8 +21,6 @@ public class GainfoDto public class AnalyzePackDto { - - public string UserNo { get; set; } public string UserDepartment { get; set; } diff --git a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs new file mode 100644 index 00000000..4549aca8 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs @@ -0,0 +1,154 @@ +using Dlhis.Basic.WorkGrids.Request; +using Dlhis.Basic.WorkGrids.Response; +using Dlhis.Basic.WorkGrids.Services; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Dlhis.Basic.WorkGrids.Controllers; + +/// +/// 工作网格 +/// +[Authorize] +[Route("api/[controller]")] +[ApiController] +public class WorkGridsController : ControllerBase +{ + private readonly IWorkGridService _workGridService; + private readonly IWorkGridTimePeriodService _workGridTimePeriodService; + private readonly IWorkGridScheduleService _workGridScheduleService; + + public WorkGridsController(IWorkGridService workGridService, + IWorkGridTimePeriodService workGridTimePeriodService, + IWorkGridScheduleService workGridScheduleService) + { + _workGridService = workGridService; + _workGridTimePeriodService = workGridTimePeriodService; + _workGridScheduleService = workGridScheduleService; + } + + /// + /// 保存 + /// + /// + /// + [HttpPost("save")] + [Transactional] + public async Task SaveWorkGridsAsync(List requests) + { + await _workGridService.SaveAsync(requests); + } + + /// + /// /网格分页 + /// + /// + /// + [HttpGet("page")] + public async Task> GetWorkGridPageAsync([FromQuery] WorkGridPageRequest request) + { + return await _workGridService.GetPageAsync(request); + } + + /// + /// 修改网格管理者 + /// + /// + [HttpPost("leader/change")] + public async Task ChangeWorkGridLeaderAsync(WorkGridChangeRequest request) + { + await _workGridService.ChangeAsync(request.From, request.To); + } + + /// + /// 获取我的网格信息 + /// + /// + /// + [HttpGet("info")] + public async Task GetMyWorkGridAsync([FromQuery] WorkGridPageRequest request) + { + return await _workGridService.GetMyWorkGridAsync(request); + } + + /// + /// 保存网格工作时间 + /// + /// + /// + [HttpPost("timePeriod/save")] + public async Task SaveWorkGridTimePeriodAsync(WorkGridTimePeriodSaveRequest request) + { + await _workGridTimePeriodService.SaveAsync(request); + } + + /// + /// /获取网格工作时间分页 + /// + /// + /// + [HttpGet("timePeriod/page")] + public async Task> GetWorkGridTimePeriodPageAsync([FromQuery] WorkGridTimePeriodPageRequest request) + { + return await _workGridTimePeriodService.GetPageAsync(request); + } + + /// + /// 分配人员到网格中 + /// + /// + /// + [HttpPost("user/assign")] + public async Task AssignUsersToWorkGridAsync(WorkGridUserAssignRequest request) + { + await _workGridService.AssignAsync(request); + } + + /// + /// 移除网格的人员 + /// + /// + /// + [HttpPost("user/remove")] + public async Task RemoveUsersFromWorkGridAsync(WorkGridUserRemoveRequest request) + { + await _workGridService.RemoveAsync(request); + } + + /// + /// 保存网格人员排班 + /// + /// + [HttpPost("user/schedule/save")] + public async Task SaveScheduleAsync(WorkGridScheduleSaveRequest request) + { + await _workGridScheduleService.SaveAsync(request); + } + + /// + /// 获取人网格员排班列表 + /// + /// 网格code + /// + /// + [HttpGet("user/schedule/list")] + public async Task> GetListAsync(Guid workGridCode, DateOnly date) + { + return await _workGridScheduleService.GetListAsync(workGridCode, date); + } + + /// + /// 获取网格人员排班详情 + /// + /// 网格 + /// 开始日期 + /// 结束日期 + /// + [HttpGet("user/schedule/summary")] + public async Task> GetListSummaryAsync([FromQuery] Guid workGridCode, [FromQuery] DateOnly start, [FromQuery] DateOnly end) + { + return await _workGridScheduleService.GetListSummaryAsync(workGridCode, start, end); + } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridChangeRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridChangeRequest.cs new file mode 100644 index 00000000..568cd2f1 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridChangeRequest.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridChangeRequest +{ + [Required] + public string From { get; set; } + + [Required] + public string To { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridPageRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridPageRequest.cs new file mode 100644 index 00000000..936ee923 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridPageRequest.cs @@ -0,0 +1,8 @@ +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridPageRequest : PageDto +{ + +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridSaveRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridSaveRequest.cs new file mode 100644 index 00000000..8b5f8029 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridSaveRequest.cs @@ -0,0 +1,22 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridSaveRequest +{ + public long? Id { get; set; } + + [Required(ErrorMessage = "名称不可为空")] + public string Name { get; set; } + + /// + /// 负责人 + /// + [Required(ErrorMessage = "负责人不可为空")] + public string LeaderUserCode { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleSaveRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleSaveRequest.cs new file mode 100644 index 00000000..dcede077 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleSaveRequest.cs @@ -0,0 +1,14 @@ +using Dlhis.Entity.Basic.Enums; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridScheduleSaveRequest +{ + public Guid WorkGridCode { get; set; } + + public DateOnly Date { get; set; } + + public WorkGridTimePeriodEnumType PeriodType { get; set; } + + public List UserCodes { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridTimePeriodRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridTimePeriodRequest.cs new file mode 100644 index 00000000..0103492f --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridTimePeriodRequest.cs @@ -0,0 +1,7 @@ +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridTimePeriodPageRequest : PageDto +{ +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridTimePeriodSaveRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridTimePeriodSaveRequest.cs new file mode 100644 index 00000000..85bcc07a --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridTimePeriodSaveRequest.cs @@ -0,0 +1,36 @@ +using System.ComponentModel.DataAnnotations; +using Dlhis.Entity.Basic.Enums; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridTimePeriodSaveRequest +{ + public long? Id { get; set; } + + /// + /// 班次, eg: 禁止编辑 + /// + public WorkGridTimePeriodEnumType Type { get; set; } + + /// + /// 前(min) + /// + [Range(1, int.MaxValue)] + public int Before { get; set; } + + /// + /// 后(min) + /// + [Range(1, int.MaxValue)] + public int After { get; set; } + + /// + /// 开始时间 + /// + public TimeOnly Start { get; set; } + + /// + /// 结束时间 + /// + public TimeOnly End { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridUserAssignRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridUserAssignRequest.cs new file mode 100644 index 00000000..c13e6e7c --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridUserAssignRequest.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridUserAssignRequest +{ + public Guid? WorkGridCode { get; set; } + + /// + /// 人员 + /// + [MinLength(1, ErrorMessage = "请选择人员")] + public List UserCodes { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridUserRemoveRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridUserRemoveRequest.cs new file mode 100644 index 00000000..e5358bc5 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridUserRemoveRequest.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridUserRemoveRequest +{ + public Guid? WorkGridCode { get; set; } + + /// + /// 人员 + /// + [MinLength(1, ErrorMessage = "请选择人员")] + public List UserCodes { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridPageResponse.cs b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridPageResponse.cs new file mode 100644 index 00000000..3494011a --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridPageResponse.cs @@ -0,0 +1,31 @@ +namespace Dlhis.Basic.WorkGrids.Response; + +public class WorkGridPageResponse +{ + public long Id { get; set; } + + /// + /// 网格code + /// + public Guid Code { get; set; } + + /// + /// 网格名称 + /// + public string Name { get; set; } + + /// + /// 负责人工号 + /// + public string LeaderUserCode { get; set; } + + /// + /// 负责人姓名 + /// + public string UserName { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleResponse.cs b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleResponse.cs new file mode 100644 index 00000000..eddfad3e --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleResponse.cs @@ -0,0 +1,12 @@ +using Dlhis.Entity.Basic.Enums; + +namespace Dlhis.Basic.WorkGrids.Response; + +public class WorkGridScheduleResponse +{ + public DateOnly Date { get; set; } + + public WorkGridTimePeriodEnumType PeriodType { get; set; } + + public string UserCode { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleSummaryResponse.cs b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleSummaryResponse.cs new file mode 100644 index 00000000..b55d9606 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleSummaryResponse.cs @@ -0,0 +1,16 @@ +using Dlhis.Entity.Basic.Enums; + +namespace Dlhis.Basic.WorkGrids.Response; + +public class WorkGridScheduleSummaryResponse +{ + public DateOnly Date { get; set; } + public IEnumerable Details { get; set; } +} + +public class WorkGridScheduleSummaryDetailResponse +{ + public WorkGridTimePeriodEnumType PeriodType { get; set; } + + public int Count { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridTimePeriodPageResponse.cs b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridTimePeriodPageResponse.cs new file mode 100644 index 00000000..03c23873 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridTimePeriodPageResponse.cs @@ -0,0 +1,72 @@ +using Dlhis.Entity.Basic.Enums; +using Kurisu.AspNetCore.Utils.Extensions; + +namespace Dlhis.Basic.WorkGrids.Response; + +public class WorkGridTimePeriodPageResponse +{ + public long Id { get; set; } + + /// + /// 班次 + /// + public WorkGridTimePeriodEnumType Type { get; set; } + + /// + /// 班次描述 + /// + public string TypeDesc => Type.GetDescription(); + + /// + /// 前 + /// + public int Before { get; set; } + + /// + /// 后 + /// + public int After { get; set; } + + /// + /// 开始时间 + /// + public TimeOnly Start { get; set; } + + /// + /// 结束时间 + /// + public TimeOnly End { get; set; } + + /// + /// 配置描述 + /// + public string Description + { + get { return Type.GetDescription() + "打卡时间从" + Start + "到" + End + "\r\n" + "上班允许提前" + GetTimeDescription(Before) + "\r\n" + "下班允许延迟" + GetTimeDescription(After); } + } + + + private string GetTimeDescription(int minutes) + { + string d; + + if (minutes >= 60) + { + var remaining = minutes % 60; + + d = $"{minutes / 60}小时"; + + if (remaining > 0) + { + d += $"{remaining}分钟"; + } + } + else + { + d = $"{minutes}分钟"; + } + + + return d; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridUserPageResponse.cs b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridUserPageResponse.cs new file mode 100644 index 00000000..bd601ea0 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridUserPageResponse.cs @@ -0,0 +1,57 @@ +namespace Dlhis.Basic.WorkGrids.Response; + +public class WorkGridUserPageResponse +{ + public long Id { get; set; } + + /// + /// 网格code + /// + public Guid Code { get; set; } + + /// + /// 网格名称 + /// + public string Name { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + + /// + /// 员工明细 + /// + public List UserInfos { get; set; } +} + +public class WorkGridUserPageDetailResponse +{ + /// + /// 人员工号 + /// + public string Code { get; set; } + + /// + /// 人员姓名 + /// + public string Name { get; set; } + + // /// + // /// 排班值 + // /// + // public WorkGridTimePeriodEnumType? ScheduleType { get; set; } + // + // /// + // /// 排班描述 + // /// + // public string ScheduleTypeDesc + // { + // get + // { + // return !ScheduleType.HasValue + // ? "未排班" + // : ScheduleType.Value.GetDescription(); + // } + // } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs new file mode 100644 index 00000000..2b6783d9 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs @@ -0,0 +1,16 @@ +using Dlhis.Basic.WorkGrids.Request; +using Dlhis.Basic.WorkGrids.Response; + +namespace Dlhis.Basic.WorkGrids.Services; + +/// +/// 网格排班 +/// +public interface IWorkGridScheduleService : IScopeDependency +{ + Task SaveAsync(WorkGridScheduleSaveRequest request); + + Task> GetListAsync(Guid workGridCode, DateOnly date); + + Task> GetListSummaryAsync(Guid workGridCode, DateOnly start, DateOnly end); +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridService.cs b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridService.cs new file mode 100644 index 00000000..0270987f --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridService.cs @@ -0,0 +1,52 @@ +using Dlhis.Basic.WorkGrids.Request; +using Dlhis.Basic.WorkGrids.Response; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Basic.WorkGrids.Services; + +/// +/// 工作网格 +/// +public interface IWorkGridService : IScopeDependency +{ + /// + /// 保存 + /// + /// + /// + Task SaveAsync(List requests); + + /// + /// /网格分页 + /// + /// + /// + Task> GetPageAsync(WorkGridPageRequest request); + + /// + /// 修改管理者 + /// + /// + Task ChangeAsync(string from, string to); + + /// + /// 获取 + /// + /// + /// + Task GetMyWorkGridAsync(WorkGridPageRequest request); + + /// + /// 分配人员 + /// + /// + /// + Task AssignAsync(WorkGridUserAssignRequest request); + + /// + /// 移除人员 + /// + /// + /// + Task RemoveAsync(WorkGridUserRemoveRequest request); +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridTimePeriodService.cs b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridTimePeriodService.cs new file mode 100644 index 00000000..f2f848da --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridTimePeriodService.cs @@ -0,0 +1,25 @@ +using Dlhis.Basic.WorkGrids.Request; +using Dlhis.Basic.WorkGrids.Response; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Basic.WorkGrids.Services; + +/// +/// 工作网格班次时段配置 +/// +public interface IWorkGridTimePeriodService : IScopeDependency +{ + /// + /// 保存 + /// + /// + /// + Task SaveAsync(WorkGridTimePeriodSaveRequest request); + + /// + /// 获取分页 + /// + /// + /// + Task> GetPageAsync(WorkGridTimePeriodPageRequest request); +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs new file mode 100644 index 00000000..1e2f25c7 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs @@ -0,0 +1,81 @@ +using Dlhis.Basic.WorkGrids.Request; +using Dlhis.Basic.WorkGrids.Response; +using Dlhis.Entity.Basic.Entity; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.Utils.Extensions; + +namespace Dlhis.Basic.WorkGrids.Services.Implements; + +public class WorkGridScheduleService : IWorkGridScheduleService +{ + private readonly IDbContext _dbContext; + + public WorkGridScheduleService(IDbContext dbContext) + { + _dbContext = dbContext; + } + + public async Task SaveAsync(WorkGridScheduleSaveRequest request) + { + var exists = await _dbContext.Queryable() + .Where(x => x.Date == request.Date) + .Where(x => x.PeriodType != request.PeriodType) + .Where(x => request.UserCodes.Contains(x.UserCode)) + .AnyAsync(); + + exists.ThrowIfTrue($"存在已经分配的人员"); + + var data = await _dbContext.Queryable() + .Where(x => x.WorkGridCode == request.WorkGridCode) + .Where(x => x.Date == request.Date) + .Where(x => x.PeriodType == request.PeriodType) + .ToListAsync(); + + await _dbContext.DeleteReallyAsync(data); + + var toInserts = request.UserCodes.Select(x => new WorkGridScheduleEntity + { + WorkGridCode = request.WorkGridCode, + Date = request.Date, + PeriodType = request.PeriodType, + UserCode = x + }).ToList(); + + await _dbContext.InsertAsync(toInserts); + } + + /// + public async Task> GetListAsync(Guid workGridCode, DateOnly date) + { + return await _dbContext.Queryable() + .Where(x => x.WorkGridCode == workGridCode && x.Date == date) + .Select(x => new WorkGridScheduleResponse + { + Date = x.Date, + PeriodType = x.PeriodType, + UserCode = x.UserCode + }) + .ToListAsync(); + } + + /// + public async Task> GetListSummaryAsync(Guid workGridCode, DateOnly start, DateOnly end) + { + var workGridSchedules = await _dbContext.Queryable() + .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() + }) + }; + }); + } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs new file mode 100644 index 00000000..f087dd94 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs @@ -0,0 +1,154 @@ +using Dlhis.Basic.WorkGrids.Request; +using Dlhis.Basic.WorkGrids.Response; +using Dlhis.Entity.Basic.Entity; +using Kurisu.AspNetCore.Authentication.Abstractions; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.Utils.Extensions; +using Mapster; +using SqlSugar; + +namespace Dlhis.Basic.WorkGrids.Services.Implements; + +public class WorkGridService : IWorkGridService +{ + private readonly IDbContext _dbContext; + private readonly ICurrentUser _currentUser; + + public WorkGridService(IDbContext dbContext, ICurrentUser currentUser) + { + _dbContext = dbContext; + _currentUser = currentUser; + } + + /// + public async Task SaveAsync(List requests) + { + foreach (var request in requests) + { + var exists = await _dbContext.Queryable() + .Where(x => x.LeaderUserCode == request.LeaderUserCode) + .WhereIF(request.Id.HasValue, x => x.Id != request.Id) + .AnyAsync(); + + exists.ThrowIfTrue($"{request.LeaderUserCode}已存在管理的网格"); + + if (!request.Id.HasValue) + { + var entity = request.Adapt(); + entity.Code = Guid.NewGuid(); + + await _dbContext.InsertAsync(entity); + } + else + { + var entity = await _dbContext.Queryable().Where(x => x.Id == request.Id).SingleAsync(); + request.Adapt(entity); + + await _dbContext.UpdateAsync(entity); + } + } + } + + /// + public async Task> GetPageAsync(WorkGridPageRequest request) + { + return await _dbContext.Queryable() + .LeftJoin((x, ga) => x.LeaderUserCode == ga.Code) + .Select((x, ga) => new WorkGridPageResponse + { + Id = x.Id, + Code = x.Code, + Name = x.Name, + LeaderUserCode = x.LeaderUserCode, + UserName = ga.Name, + Remark = x.Remark + }) + .ToPageListAsync(request); + } + + /// + public async Task ChangeAsync(string from, string to) + { + var workGrid = await _dbContext.Queryable().Where(x => x.LeaderUserCode == from).SingleAsync(); + workGrid.ThrowIfNull("网格不存在"); + + var gainfo = await _dbContext.Queryable().Where(x => x.Code == to).SingleAsync(); + gainfo.ThrowIfNull($"{to}人员不存在"); + + workGrid.LeaderUserCode = to; + await _dbContext.UpdateAsync(workGrid); + } + + /// + public async Task GetMyWorkGridAsync(WorkGridPageRequest request) + { + var currentUserCode = _currentUser.GetUserClaim("jinko-code"); + var myWorkGrid = await _dbContext.Queryable() + .Where(x => x.LeaderUserCode == currentUserCode) + .Select(x => new WorkGridUserPageResponse + { + Id = x.Id, + Code = x.Code, + Name = x.Name, + Remark = x.Remark, + UserInfos = SqlFunc.Subqueryable() + .LeftJoin((p, ga) => p.UserCode == ga.Code) + .Where((p, ga) => p.WorkGridCode == x.Code) + .ToList((p, ga) => new WorkGridUserPageDetailResponse + { + Code = p.UserCode, + Name = ga.Name + }) + }) + .SingleAsync(); + + return myWorkGrid; + } + + /// + public async Task AssignAsync(WorkGridUserAssignRequest request) + { + var currentFactory = _currentUser.GetStringTenantId(); + var currentUserCode = _currentUser.GetUserClaim("jinko-code"); + + var myWorkGrid = await _dbContext.Queryable().Where(x => x.LeaderUserCode == currentUserCode).SingleAsync(); + myWorkGrid.ThrowIfNull("工作网格尚未配置,请联系管理员"); + + //检查配置的人员 + var count = await _dbContext.Queryable() + .Where(x => x.Factory == currentFactory) + .Where(x => request.UserCodes.Contains(x.Code)) + .CountAsync(); + + (count != request.UserCodes.Count).ThrowIfTrue("存在非当前厂区人员,请检查"); + + var existsAssigned = await _dbContext.Queryable().Where(x => x.WorkGridCode == myWorkGrid.Code) + .Where(x => request.UserCodes.Contains(x.UserCode)) + .AnyAsync(); + existsAssigned.ThrowIfTrue("存在已经分配人员,请勿重复分配"); + + var dataToInserts = request.UserCodes.Select(x => new WorkGridUserEntity + { + WorkGridCode = myWorkGrid.Code, + UserCode = x + }).ToList(); + + await _dbContext.InsertAsync(dataToInserts); + } + + /// + public async Task RemoveAsync(WorkGridUserRemoveRequest request) + { + var currentUserCode = _currentUser.GetUserClaim("jinko-code"); + var myWorkGrid = await _dbContext.Queryable().Where(x => x.LeaderUserCode == currentUserCode).SingleAsync(); + myWorkGrid.ThrowIfNull("工作网格尚未配置,请联系管理员"); + + var workGridUsers = await _dbContext.Queryable().Where(x => x.WorkGridCode == myWorkGrid.Code) + .Where(x => request.UserCodes.Contains(x.UserCode)) + .ToListAsync(); + + await _dbContext.DeleteReallyAsync(workGridUsers); + } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs new file mode 100644 index 00000000..b07b4396 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs @@ -0,0 +1,93 @@ +using Dlhis.Basic.WorkGrids.Request; +using Dlhis.Basic.WorkGrids.Response; +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Basic.Enums; +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 Mapster; + +namespace Dlhis.Basic.WorkGrids.Services.Implements; + +public class WorkGridTimePeriodService : IWorkGridTimePeriodService +{ + private readonly IDbContext _dbContext; + + public WorkGridTimePeriodService(IDbContext dbContext) + { + _dbContext = dbContext; + } + + /// + public async Task SaveAsync(WorkGridTimePeriodSaveRequest request) + { + //await CheckDuplicateTimePeriodAsync(request); + + if (!request.Id.HasValue) + { + //判断重复配置 + var existsSameType = await _dbContext.Queryable() + .Where(x => x.Type == request.Type) + .AnyAsync(); + + existsSameType.ThrowIfTrue($"已存在{request.Type}配置"); + + var data = request.Adapt(); + data.Type = request.Type; + await _dbContext.InsertAsync(data); + } + else + { + var entity = await _dbContext.Queryable().Where(x => x.Id == request.Id).SingleAsync(); + request.Adapt(entity); + + await _dbContext.UpdateAsync(entity); + } + } + + /// + public async Task> GetPageAsync(WorkGridTimePeriodPageRequest request) + { + return await _dbContext.Queryable() + .Select() + .ToPageListAsync(request); + } + + //************************************************************************************************************************************************* + + /// + /// 根据类型获取配置 + /// + /// + /// + private async Task GetSettingAsync(WorkGridTimePeriodEnumType timePeriodType) + { + return await _dbContext.Queryable() + .Where(x => x.Type == timePeriodType) + .SingleAsync(); + } + + /// + /// 检查时间段重合检查 + /// + /// + /// + private async Task CheckDuplicateTimePeriodAsync(WorkGridTimePeriodSaveRequest request) + { + var periods = await _dbContext.Queryable() + .Where(x => x.Type != request.Type) + .Select(x => new TimePeriod + { + Start = x.Start, + End = x.End + }) + .ToListAsync(); + + foreach (var period in periods) + { + period.IsDuplicate(request.Adapt()).ThrowIfTrue($"存在时间段重合[{period.Start}-{period.End}]"); + } + } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Basic/Entity/WorkGridEntity.cs b/Src/Dlhis.Entity/Basic/Entity/WorkGridEntity.cs new file mode 100644 index 00000000..f616edcf --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Entity/WorkGridEntity.cs @@ -0,0 +1,37 @@ +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using Mapster; +using SqlSugar; + +namespace Dlhis.Entity.Basic.Entity; + +/// +/// 工作网格 +/// +[SugarTable(TableName = "WorkGrid")] +public class WorkGridEntity : SugarBaseEntity +{ + /// + /// 网格code + /// + [AdaptIgnore(MemberSide.Destination)] + [SugarColumn(IsNullable = false, ColumnDescription = "网格code")] + public Guid Code { get; set; } + + /// + /// 网格名称 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "网格名称")] + public string Name { get; set; } + + /// + /// 负责人工号 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "负责人工号", UniqueGroupNameList = new[] { "idx_WorkGrid_LeaderUserCode" })] + public string LeaderUserCode { get; set; } + + /// + /// 备注 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "备注")] + public string Remark { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs b/Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs new file mode 100644 index 00000000..22e58f7d --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs @@ -0,0 +1,42 @@ +using Dlhis.Entity.Basic.Enums; +using Kurisu.AspNetCore.DataAccess.Entity; +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using SqlSugar; +using SqlSugar.DbConvert; + +namespace Dlhis.Entity.Basic.Entity; + +/// +/// +/// +[SugarTable(TableName = "WorkGridSchedule")] +public class WorkGridScheduleEntity : SugarBaseEntity, ITenantId +{ + /// + /// 网格code + /// + [SugarColumn(IsNullable = false, ColumnDescription = "网格code")] + public Guid WorkGridCode { get; set; } + + /// + /// 排班日期 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "排班日期")] + public DateOnly Date { get; set; } + + /// + /// 排班类型 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "排班类型", SqlParameterDbType = typeof(EnumToStringConvert))] + public WorkGridTimePeriodEnumType PeriodType { get; set; } + + /// + /// 工号 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "工号")] + public string UserCode { get; set; } + + + /// + public string TenantId { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs b/Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs new file mode 100644 index 00000000..1d842130 --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs @@ -0,0 +1,44 @@ +using Dlhis.Entity.Basic.Enums; +using Kurisu.AspNetCore.DataAccess.Entity; +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using Mapster; +using SqlSugar; + +namespace Dlhis.Entity.Basic.Entity; + +/// +/// 工作网格 +/// +[SugarTable(TableName = "WorkGridTimePeriod")] +public class WorkGridTimePeriodEntity : SugarBaseEntity, ITenantId +{ + /// + /// 班次 + /// + [AdaptIgnore(MemberSide.Destination)] + public WorkGridTimePeriodEnumType Type { get; set; } + + /// + /// 前 + /// + public int Before { get; set; } + + /// + /// 后 + /// + public int After { get; set; } + + /// + /// 开始时间 + /// + public TimeOnly Start { get; set; } + + /// + /// 结束时间 + /// + public TimeOnly End { get; set; } + + + [SugarColumn(UniqueGroupNameList = new[] { "idx_workGridTimePeriod_type_tenantId" })] + public string TenantId { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs b/Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs new file mode 100644 index 00000000..7685a578 --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs @@ -0,0 +1,35 @@ +using Dlhis.Entity.Basic.Enums; +using Kurisu.AspNetCore.DataAccess.Entity; +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using SqlSugar; +using SqlSugar.DbConvert; + +namespace Dlhis.Entity.Basic.Entity; + +/// +/// 网格人员 +/// +[SugarTable(TableName = "WorkGridUsers")] +public class WorkGridUserEntity : SugarBaseEntity, ITenantId +{ + /// + /// 网格code + /// + [SugarColumn(IsNullable = false, ColumnDescription = "网格code")] + public Guid WorkGridCode { get; set; } + + /// + /// 网格人员 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "网格人员")] + public string UserCode { get; set; } + + /// + /// 排班类型 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "排班类型", SqlParameterDbType = typeof(EnumToStringConvert))] + public WorkGridTimePeriodEnumType? ScheduleType { get; set; } + + /// + public string TenantId { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Basic/Enums/WorkGridTimePeriodEnumType.cs b/Src/Dlhis.Entity/Basic/Enums/WorkGridTimePeriodEnumType.cs new file mode 100644 index 00000000..e666372a --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Enums/WorkGridTimePeriodEnumType.cs @@ -0,0 +1,22 @@ +using System.ComponentModel; + +namespace Dlhis.Entity.Basic.Enums; + +/// +/// 网格班次 +/// +[Description("网格班次")] +public enum WorkGridTimePeriodEnumType +{ + /// + /// 白班 + /// + [Description("白班")] + Day = 1, + + /// + /// 晚班 + /// + [Description("晚班")] + Night = 2, +} \ No newline at end of file From 03584778e5d21a12b9725251c179d5bd064d9125 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 11 Feb 2025 16:33:21 +0800 Subject: [PATCH 02/25] feat tickets --- Dlhis.Jinko.Face.sln | 13 ++++ .../Services/Implements/DishesService.cs | 5 +- Src/Dlhis.Basic/Dlhis.Basic.csproj | 1 + .../Implements/GainfoQrCodeService.cs | 6 +- .../Services/Implements/GainfoService.cs | 3 +- .../Implements/IdentityUserSyncService.cs | 3 +- .../Dlhis.Canteen.Api.csproj | 13 ++++ Src/Dlhis.Canteen.Api/ITicketApi.cs | 16 +++++ Src/Dlhis.Canteen/Dlhis.Canteen.csproj | 1 + .../Implements/EMealVoucherService.cs | 5 +- .../Implements/MealSupplementRecordService.cs | 3 +- .../Services/Implements/BalanceService.cs | 3 +- .../Order/Services/Implements/OrderService.cs | 21 ++++-- .../Services/Implements/WalletService.cs | 3 +- .../Tickets/Controllers/TicketsController.cs | 50 ++++++++++++++ .../Tickets/Request/TicketPageRequest.cs | 19 ++++++ .../Tickets/Response/TicketPageResponse.cs | 41 ++++++++++++ .../Services/IBirthdayTicketService.cs | 6 ++ .../Tickets/Services/ITicketService.cs | 24 +++++++ .../Implements/BirthdayTicketService.cs | 65 +++++++++++++++++++ .../Services/Implements/TicketService.cs | 32 +++++++++ Src/Dlhis.Constants/Dlhis.Constants.csproj | 9 +++ Src/Dlhis.Constants/QrCodeConstants.cs | 19 ++++++ Src/Dlhis.Constants/TickConstants.cs | 6 ++ Src/Dlhis.Constants/UserClaimConstants.cs | 9 +++ .../Canteen/Entities/TicketEntity.cs | 52 +++++++++++++++ .../Canteen/Enums/TicketEnumType.cs | 16 +++++ .../Implements/DeviceUploadLogService.cs | 5 +- .../Dlhis.ScheduledTask.csproj | 3 + Src/Dlhis.ScheduledTask/Dockerfile | 13 +++- .../Jobs/CreateBirthdayTicketJob.cs | 22 +++++++ .../appsettings.Development.json | 19 +++--- Src/Dlhis.ScheduledTask/appsettings.json | 3 +- 33 files changed, 479 insertions(+), 30 deletions(-) create mode 100644 Src/Dlhis.Canteen.Api/Dlhis.Canteen.Api.csproj create mode 100644 Src/Dlhis.Canteen.Api/ITicketApi.cs create mode 100644 Src/Dlhis.Canteen/Tickets/Controllers/TicketsController.cs create mode 100644 Src/Dlhis.Canteen/Tickets/Request/TicketPageRequest.cs create mode 100644 Src/Dlhis.Canteen/Tickets/Response/TicketPageResponse.cs create mode 100644 Src/Dlhis.Canteen/Tickets/Services/IBirthdayTicketService.cs create mode 100644 Src/Dlhis.Canteen/Tickets/Services/ITicketService.cs create mode 100644 Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs create mode 100644 Src/Dlhis.Canteen/Tickets/Services/Implements/TicketService.cs create mode 100644 Src/Dlhis.Constants/Dlhis.Constants.csproj create mode 100644 Src/Dlhis.Constants/QrCodeConstants.cs create mode 100644 Src/Dlhis.Constants/TickConstants.cs create mode 100644 Src/Dlhis.Constants/UserClaimConstants.cs create mode 100644 Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs create mode 100644 Src/Dlhis.Entity/Canteen/Enums/TicketEnumType.cs create mode 100644 Src/Dlhis.ScheduledTask/Jobs/CreateBirthdayTicketJob.cs diff --git a/Dlhis.Jinko.Face.sln b/Dlhis.Jinko.Face.sln index 8ab23f97..0cf2b39a 100644 --- a/Dlhis.Jinko.Face.sln +++ b/Dlhis.Jinko.Face.sln @@ -47,6 +47,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dlhis.Jip.Api", "Src\Dlhis. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dlhis.Dh.Api", "Src\Dlhis.Dh.Api\Dlhis.Dh.Api.csproj", "{E673CA04-3567-4E03-9A86-994F50291ACC}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dlhis.Constants", "Src\Dlhis.Constants\Dlhis.Constants.csproj", "{F98329D8-F8CA-4794-B1BF-8659112119F7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dlhis.Canteen.Api", "Src\Dlhis.Canteen.Api\Dlhis.Canteen.Api.csproj", "{7934BE46-9409-4D28-8B35-82A0F900DD01}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -117,6 +121,14 @@ Global {E673CA04-3567-4E03-9A86-994F50291ACC}.Debug|Any CPU.Build.0 = Debug|Any CPU {E673CA04-3567-4E03-9A86-994F50291ACC}.Release|Any CPU.ActiveCfg = Release|Any CPU {E673CA04-3567-4E03-9A86-994F50291ACC}.Release|Any CPU.Build.0 = Release|Any CPU + {F98329D8-F8CA-4794-B1BF-8659112119F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F98329D8-F8CA-4794-B1BF-8659112119F7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F98329D8-F8CA-4794-B1BF-8659112119F7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F98329D8-F8CA-4794-B1BF-8659112119F7}.Release|Any CPU.Build.0 = Release|Any CPU + {7934BE46-9409-4D28-8B35-82A0F900DD01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7934BE46-9409-4D28-8B35-82A0F900DD01}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7934BE46-9409-4D28-8B35-82A0F900DD01}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7934BE46-9409-4D28-8B35-82A0F900DD01}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -134,6 +146,7 @@ Global {A501D16E-638F-4156-989C-2BACCC2FAC2B} = {4EBCE46B-CE3A-4A47-9432-82A1854CA58A} {841B7B43-5394-413F-9D68-A07EBDD6D4CD} = {4EBCE46B-CE3A-4A47-9432-82A1854CA58A} {E673CA04-3567-4E03-9A86-994F50291ACC} = {4EBCE46B-CE3A-4A47-9432-82A1854CA58A} + {7934BE46-9409-4D28-8B35-82A0F900DD01} = {3D8A98C1-83C9-4375-AEAB-4F72AFAF365B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7439494A-E2FD-4FEA-8ABF-74AE57A4A5A0} diff --git a/Src/Dlhis.Basic/Dishes/Services/Implements/DishesService.cs b/Src/Dlhis.Basic/Dishes/Services/Implements/DishesService.cs index 17d54967..4e738197 100644 --- a/Src/Dlhis.Basic/Dishes/Services/Implements/DishesService.cs +++ b/Src/Dlhis.Basic/Dishes/Services/Implements/DishesService.cs @@ -1,6 +1,7 @@ using Dlhis.Basic.Dishes.Request; using Dlhis.Basic.Dishes.Response; using Dlhis.Basic.Places.Services; +using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; @@ -45,7 +46,7 @@ public class DishesService : IDishesService .ToPageListAsync(request); } - + public async Task SaveDishesAsync(DishesSaveRequest request) { if (!request.Id.HasValue) @@ -68,7 +69,7 @@ public class DishesService : IDishesService { var subjectId = _currentUser.GetIntSubjectId(); var gainfo = await _dbContext.Queryable().Where(x => x.IdentityUserId == subjectId).FirstAsync(); - var jinkoCode = _currentUser.GetUserClaim("jinko-code") ?? string.Empty; + var jinkoCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode) ?? string.Empty; if (jinkoCode.IsPresent()) { gainfo = await _dbContext.Queryable().Where(x => x.Code == jinkoCode).FirstAsync(); diff --git a/Src/Dlhis.Basic/Dlhis.Basic.csproj b/Src/Dlhis.Basic/Dlhis.Basic.csproj index eb9f5b54..7b161cb8 100644 --- a/Src/Dlhis.Basic/Dlhis.Basic.csproj +++ b/Src/Dlhis.Basic/Dlhis.Basic.csproj @@ -26,6 +26,7 @@ + diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoQrCodeService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoQrCodeService.cs index ab6564d7..fac551b2 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoQrCodeService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoQrCodeService.cs @@ -1,4 +1,5 @@ using System.Text; +using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Kurisu.AspNetCore.Authentication.Abstractions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; @@ -21,7 +22,7 @@ public class GainfoQrCodeService : IGainfoQrCodeService public async Task GetMyQrCodeAsync(bool isNeedRefresh = false) { - var jinkoCode = _currentUser.GetUserClaim("jinko-code"); + var jinkoCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode); if (jinkoCode.IsEmpty()) { return null; @@ -63,11 +64,12 @@ public class GainfoQrCodeService : IGainfoQrCodeService var ts = DateTimeOffset.Now.ToUnixTimeMilliseconds(); var qrCode = string.Concat("consumer", ":", code, ":"); - return "01" + qrCode.ToArray().Select(x => + return QrCodeConstants.User + qrCode.ToArray().Select(x => { var b = Encoding.ASCII.GetBytes(x.ToString()); int i = b[0]; return Convert.ToString(i); + }).Join(string.Empty) + ts; } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs index f6b88f2f..198382e6 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs @@ -2,6 +2,7 @@ using Dlhis.Basic.Device.Services; using Dlhis.Basic.Organization.Request; using Dlhis.Basic.Organization.Response; +using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Basic.Enums; using Dlhis.Entity.Device.Entities; @@ -195,7 +196,7 @@ public class GainfoService : IGainfoService public async Task CurrentUserInfoAsync() { - var code = _currentUser.GetUserClaim("jinko-code"); + var code = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode); if (code.IsEmpty()) { _logger.LogWarning("工号为空尝试获取人员信息"); diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/IdentityUserSyncService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/IdentityUserSyncService.cs index 5bde9773..a68e296d 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/IdentityUserSyncService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/IdentityUserSyncService.cs @@ -1,3 +1,4 @@ +using Dlhis.Constants; using Dlhis.Entity.Sys.Entities; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using Kurisu.AspNetCore.Utils.Extensions; @@ -41,7 +42,7 @@ public class IdentityUserSyncService : IIdentityUserSyncService var id = (int)await _identityDbContext.InsertReturnIdentityAsync(user); user.Id = id; - await AddUserClaim(_identityDbContext, id, "jinko-code", userName); + await AddUserClaim(_identityDbContext, id, UserClaimConstants.JinkoCode, userName); await AddUserClaim(_identityDbContext, id, "name", name); } diff --git a/Src/Dlhis.Canteen.Api/Dlhis.Canteen.Api.csproj b/Src/Dlhis.Canteen.Api/Dlhis.Canteen.Api.csproj new file mode 100644 index 00000000..dba64aca --- /dev/null +++ b/Src/Dlhis.Canteen.Api/Dlhis.Canteen.Api.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + disable + + + + + + + diff --git a/Src/Dlhis.Canteen.Api/ITicketApi.cs b/Src/Dlhis.Canteen.Api/ITicketApi.cs new file mode 100644 index 00000000..149b9826 --- /dev/null +++ b/Src/Dlhis.Canteen.Api/ITicketApi.cs @@ -0,0 +1,16 @@ +using Kurisu.RemoteCall.Attributes; + +namespace Dlhis.Canteen.Api; + +[RequestResultHandler] +[EnableRemoteClient(Name = "canteen-service", BaseUrl = "${InternalRequest:CanteenRequestUrl}")] +public interface ITicketApi +{ + /// + /// 创建券 + /// + /// + /// + [Post("/api/tickets/{type}/create")] + Task CreateAsync(string type); +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Dlhis.Canteen.csproj b/Src/Dlhis.Canteen/Dlhis.Canteen.csproj index f893a588..b3030c28 100644 --- a/Src/Dlhis.Canteen/Dlhis.Canteen.csproj +++ b/Src/Dlhis.Canteen/Dlhis.Canteen.csproj @@ -22,6 +22,7 @@ + diff --git a/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs b/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs index 466e2e5d..9bb4b838 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs +++ b/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs @@ -3,6 +3,7 @@ using Dlhis.Canteen.EMealVoucher.Request; using Dlhis.Canteen.EMealVoucher.Response; using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Response; +using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; @@ -65,7 +66,7 @@ public class EMealVoucherService : IEMealVoucherService public async Task> GetMyEMealVoucherPageAsync(EMealVoucherPageRequest request) { - var code = _currentUser.GetUserClaim("jinko-code"); + var code = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode); return await _dbContext.Queryable() .Where(x => x.Code == code) @@ -126,7 +127,7 @@ public class EMealVoucherService : IEMealVoucherService var ts = DateTimeOffset.Now.ToUnixTimeMilliseconds().ToString().Reverse().Join(string.Empty); var originData = string.Concat(eMealVoucher.No, ":", ts, ":", eMealVoucher.Code, ":", eMealVoucherDetail.IdNo); - var qrCode = "02" + originData.ToArray().Select(x => + var qrCode = QrCodeConstants.EMealVoucher + originData.ToArray().Select(x => { var b = Encoding.ASCII.GetBytes(x.ToString()); int i = b[0]; diff --git a/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs b/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs index 0e2094cf..79f03e25 100644 --- a/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs +++ b/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs @@ -1,5 +1,6 @@ using Dlhis.Canteen.MealSupplementRecord.Request; using Dlhis.Canteen.MealSupplementRecord.Response; +using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; @@ -93,7 +94,7 @@ public class MealSupplementRecordService : IMealSupplementRecordService public async Task GetMyMealSupplementRecords(MealSupplementRecordMyRequest request) { - var code = _currentUser.GetUserClaim("jinko-code") ?? string.Empty; + var code = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode) ?? string.Empty; var data = await _dbContext.Queryable() .Where(x => x.CostDateTime >= request.SearchDateTimePeriod.Start && x.CostDateTime <= request.SearchDateTimePeriod.End) diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs index 8929aed6..1e9457e5 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs @@ -3,6 +3,7 @@ using Dlhis.Canteen.Order.Repository; using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Response; using Dlhis.Canteen.Setting.Services; +using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; @@ -332,7 +333,7 @@ public class BalanceService : IBalanceService public async Task GetPageByUserAsync(BalanceRecordUserPageRequest request) { - var userCode = _currentUser.GetUserClaim("jinko-code") ?? string.Empty; + var userCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode) ?? string.Empty; var factory = await _dbContext.Queryable().Where(x => x.Code == request.WalletCode).Select(x => x.Factory).FirstAsync(); var factories = await _balanceRepository.GetWalletFactoriesAsync(factory); diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs index 6a849f72..d6284a13 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs @@ -21,6 +21,7 @@ using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using Kurisu.AspNetCore.UnifyResultAndValidation; +using Dlhis.Constants; namespace Dlhis.Canteen.Order.Services.Implements; @@ -88,7 +89,7 @@ public class OrderService : IOrderService { var subjectId = _currentUser.GetIntSubjectId(); var gainfo = await _dbContext.Queryable().Where(x => x.IdentityUserId == subjectId).FirstAsync(); - var jinkoCode = _currentUser.GetUserClaim("jinko-code") ?? string.Empty; + var jinkoCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode) ?? string.Empty; if (jinkoCode.IsPresent()) { gainfo = await _dbContext.Queryable().Where(x => x.Code == jinkoCode).SingleAsync(); @@ -153,12 +154,12 @@ public class OrderService : IOrderService if (request.Source == BalanceRecordSourceEnumType.QrCode) { - if (request.UserUniqueNo.StartsWith("01")) + if (request.UserUniqueNo.StartsWith(QrCodeConstants.User)) { gainfo = await GetUserByQrCodeAsync(request.UserUniqueNo); await CheckPermissionAsync(gainfo.Code, request.DeviceUniqueNo); } - else if (request.UserUniqueNo.StartsWith("02")) + else if (request.UserUniqueNo.StartsWith(QrCodeConstants.EMealVoucher)) { request.Source = BalanceRecordSourceEnumType.EMealVoucher; var eMealVoucherQrCode = await _dbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); @@ -166,6 +167,12 @@ public class OrderService : IOrderService var code = eMealVoucherQrCode.OriginData.Split(':')[2]; gainfo = await _dbContext.Queryable().Where(x => x.Code == code).SingleAsync(); } + else if (request.UserUniqueNo.StartsWith(QrCodeConstants.Birthday)) + { + var ticket = await _dbContext.Queryable().Where(x => x.Type == TicketEnumType.Birthday).Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); + ticket.ThrowIfNull("无法识别"); + gainfo = await _dbContext.Queryable().Where(x => x.Code == ticket.UserCode).SingleAsync(); + } else { throw new UserFriendlyException($"无法识别{request.UserUniqueNo}"); @@ -276,7 +283,9 @@ public class OrderService : IOrderService .Where(x => x.DeviceUniqueNo == request.DeviceUniqueNo && x.BusinessPlaceCode.HasValue) .Select((x, b, bs) => new { - b.Code, bs.ShiftCode, Factory = x.TenantId + b.Code, + bs.ShiftCode, + Factory = x.TenantId }) .SingleAsync(); @@ -615,7 +624,9 @@ public class OrderService : IOrderService .Where(x => x.DeviceUniqueNo == deviceUniqueNo && x.BusinessPlaceCode.HasValue) .Select((x, b, bs) => new { - b.Code, bs.ShiftCode, Factory = x.TenantId + b.Code, + bs.ShiftCode, + Factory = x.TenantId }) .SingleAsync(); diff --git a/Src/Dlhis.Canteen/Setting/Services/Implements/WalletService.cs b/Src/Dlhis.Canteen/Setting/Services/Implements/WalletService.cs index 42f3a8fc..ffe3dd45 100644 --- a/Src/Dlhis.Canteen/Setting/Services/Implements/WalletService.cs +++ b/Src/Dlhis.Canteen/Setting/Services/Implements/WalletService.cs @@ -1,5 +1,6 @@ using Dlhis.Canteen.Order.Repository; using Dlhis.Canteen.Setting.Response; +using Dlhis.Constants; using Dlhis.Entity.Canteen.Entities; using Kurisu.AspNetCore.Authentication.Abstractions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; @@ -37,7 +38,7 @@ public class WalletService : IWalletService /// public async Task GetBalanceAsync(string walletCode) { - var userCode = _currentUser.GetUserClaim("jinko-code"); + var userCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode); if (!await _dbContext.Queryable().Where(x => x.UserCode == userCode).AnyAsync()) { diff --git a/Src/Dlhis.Canteen/Tickets/Controllers/TicketsController.cs b/Src/Dlhis.Canteen/Tickets/Controllers/TicketsController.cs new file mode 100644 index 00000000..9dfb8ae1 --- /dev/null +++ b/Src/Dlhis.Canteen/Tickets/Controllers/TicketsController.cs @@ -0,0 +1,50 @@ +using Dlhis.Canteen.Tickets.Request; +using Dlhis.Canteen.Tickets.Response; +using Dlhis.Canteen.Tickets.Services; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.Utils.Extensions; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Dlhis.Canteen.Tickets.Controllers; + +/// +/// 券 +/// +[Authorize] +[Route("api/[controller]")] +[ApiController] +public class TicketsController : ControllerBase +{ + private readonly INamedResolver _namedResolver; + + public TicketsController(INamedResolver namedResolver) + { + _namedResolver = namedResolver; + } + + /// + /// 获取分页数据(按券类型) + /// + /// + /// + [HttpGet("page")] + public async Task> GetPageAsync(TicketPageRequest request) + { + return await _namedResolver.GetService(request.Type.ToString()).GetPageAsync(request); + } + + /// + /// 创建券 + /// + /// 券类型,需要后端支持 + [AllowAnonymous] + [HttpPost("{type:required}/create")] + public async Task CreateAsync(string type) + { + var srv = _namedResolver.GetService(type); + srv.ThrowIfNull("不支持的券类型"); + + await srv.CreateAsync(); + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Request/TicketPageRequest.cs b/Src/Dlhis.Canteen/Tickets/Request/TicketPageRequest.cs new file mode 100644 index 00000000..02620a43 --- /dev/null +++ b/Src/Dlhis.Canteen/Tickets/Request/TicketPageRequest.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; +using Dlhis.Entity.Canteen.Enums; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Canteen.Tickets.Request; + +public class TicketPageRequest : PageDto +{ + /// + /// 类型 + /// + [EnumDataType(typeof(TicketEnumType))] + public TicketEnumType Type { get; set; } + + /// + /// 工号 + /// + public string UserCode { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Response/TicketPageResponse.cs b/Src/Dlhis.Canteen/Tickets/Response/TicketPageResponse.cs new file mode 100644 index 00000000..b7be7bc6 --- /dev/null +++ b/Src/Dlhis.Canteen/Tickets/Response/TicketPageResponse.cs @@ -0,0 +1,41 @@ +using Dlhis.Entity.Canteen.Enums; + +namespace Dlhis.Canteen.Tickets.Response; + +public class TicketPageResponse +{ + /// + /// 券类型 + /// + public TicketEnumType Type { get; set; } + + /// + /// 工号 + /// + public string UserCode { get; set; } + + /// + /// 用户名称 + /// + public string UserName { get; set; } + + /// + /// 初始余额 + /// + public decimal OriginalAmount { get; set; } + + /// + /// 当前余额 + /// + public decimal Amount { get; set; } + + /// + /// 消费码 + /// + public string QrCode { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Services/IBirthdayTicketService.cs b/Src/Dlhis.Canteen/Tickets/Services/IBirthdayTicketService.cs new file mode 100644 index 00000000..1b67cc3a --- /dev/null +++ b/Src/Dlhis.Canteen/Tickets/Services/IBirthdayTicketService.cs @@ -0,0 +1,6 @@ +namespace Dlhis.Canteen.Tickets.Services; + +public interface IBirthdayTicketService : ITicketService +{ + +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Services/ITicketService.cs b/Src/Dlhis.Canteen/Tickets/Services/ITicketService.cs new file mode 100644 index 00000000..bc8731f2 --- /dev/null +++ b/Src/Dlhis.Canteen/Tickets/Services/ITicketService.cs @@ -0,0 +1,24 @@ +using Dlhis.Canteen.Tickets.Request; +using Dlhis.Canteen.Tickets.Response; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Canteen.Tickets.Services; + +/// +/// 券 +/// +public interface ITicketService : IScopeDependency +{ + /// + /// 分页数据 + /// + /// + /// + Task> GetPageAsync(TicketPageRequest request); + + /// + /// 创建 + /// + /// + Task CreateAsync(); +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs b/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs new file mode 100644 index 00000000..ba75b0e9 --- /dev/null +++ b/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs @@ -0,0 +1,65 @@ +using System.Text; +using Dlhis.Constants; +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Canteen.Entities; +using Dlhis.Entity.Canteen.Enums; +using Kurisu.AspNetCore.DataAccess.Entity; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.Utils.Extensions; +using SqlSugar; + +namespace Dlhis.Canteen.Tickets.Services.Implements; + +[Service(nameof(TicketEnumType.Birthday))] +public class BirthdayTicketService : BaseTicketService, IBirthdayTicketService +{ + /// + public BirthdayTicketService(IDbContext dbContext) : base(dbContext) + { + } + + /// + public override async Task CreateAsync() + { + await DbContext.IgnoreAsync(async () => + { + var today = DateTime.Today; + var userCodes = await DbContext.Queryable() + .Where(x => SqlFunc.DateIsSame(SqlFunc.ToDate(x.Birthday), today, DateType.Day)) + .Select(x => new { x.Code, x.Factory }) + .ToListAsync(); + + const decimal amount = 30; + var todayStr = today.ToString("yyyy-MM-dd"); + foreach (var item in userCodes) + { + var qrCode = GetQrCode(item.Code + todayStr); + if (!await DbContext.Queryable().Where(x => x.Type == TicketEnumType.Birthday && x.UserCode == item.Code && x.QrCode == qrCode).AnyAsync()) + { + await DbContext.InsertAsync(new TicketEntity + { + Type = TicketEnumType.Birthday, + UserCode = item.Code, + OriginalAmount = amount, + Amount = amount, + QrCode = qrCode, + Remark = todayStr + "生日券", + TenantId = item.Factory + }); + } + } + }); + } + + private static string GetQrCode(string data) + { + var qrCode = QrCodeConstants.Birthday + data.ToArray().Select(x => + { + var b = Encoding.ASCII.GetBytes(x.ToString()); + int i = b[0]; + return Convert.ToString(i); + }).Join(string.Empty); + + return qrCode; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Services/Implements/TicketService.cs b/Src/Dlhis.Canteen/Tickets/Services/Implements/TicketService.cs new file mode 100644 index 00000000..8af5da71 --- /dev/null +++ b/Src/Dlhis.Canteen/Tickets/Services/Implements/TicketService.cs @@ -0,0 +1,32 @@ +using Dlhis.Canteen.Tickets.Request; +using Dlhis.Canteen.Tickets.Response; +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Canteen.Entities; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.Utils.Extensions; + +namespace Dlhis.Canteen.Tickets.Services.Implements; + +public abstract class BaseTicketService : ITicketService +{ + protected IDbContext DbContext { get; set; } + + protected BaseTicketService(IDbContext dbContext) + { + DbContext = dbContext; + } + + public async Task> GetPageAsync(TicketPageRequest request) + { + return await DbContext.Queryable() + .LeftJoin((x, ga) => x.UserCode == ga.Code) + .Where(x => x.Type == request.Type) + .WhereIF(request.UserCode.IsPresent(), x => x.UserCode == request.UserCode) + .Select((x, ga) => new TicketPageResponse { UserName = ga.Name }, true) + .ToPageListAsync(request); + } + + public abstract Task CreateAsync(); +} \ No newline at end of file diff --git a/Src/Dlhis.Constants/Dlhis.Constants.csproj b/Src/Dlhis.Constants/Dlhis.Constants.csproj new file mode 100644 index 00000000..132c02c5 --- /dev/null +++ b/Src/Dlhis.Constants/Dlhis.Constants.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/Src/Dlhis.Constants/QrCodeConstants.cs b/Src/Dlhis.Constants/QrCodeConstants.cs new file mode 100644 index 00000000..ed15fccc --- /dev/null +++ b/Src/Dlhis.Constants/QrCodeConstants.cs @@ -0,0 +1,19 @@ +namespace Dlhis.Constants; + +public class QrCodeConstants +{ + /// + /// 个人码 + /// + public const string User = "01"; + + /// + /// 电子餐券 + /// + public const string EMealVoucher = "02"; + + /// + /// 生日券 + /// + public const string Birthday = "03"; +} diff --git a/Src/Dlhis.Constants/TickConstants.cs b/Src/Dlhis.Constants/TickConstants.cs new file mode 100644 index 00000000..b24c0775 --- /dev/null +++ b/Src/Dlhis.Constants/TickConstants.cs @@ -0,0 +1,6 @@ +// namespace Dlhis.Constants; +// +// public class TickConstants +// { +// public const string { get; set; } +// } diff --git a/Src/Dlhis.Constants/UserClaimConstants.cs b/Src/Dlhis.Constants/UserClaimConstants.cs new file mode 100644 index 00000000..635fdf0f --- /dev/null +++ b/Src/Dlhis.Constants/UserClaimConstants.cs @@ -0,0 +1,9 @@ +namespace Dlhis.Constants; + +public class UserClaimConstants +{ + /// + /// 晶科工号 + /// + public const string JinkoCode = "jinko-code"; +} diff --git a/Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs new file mode 100644 index 00000000..d3ca3c05 --- /dev/null +++ b/Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs @@ -0,0 +1,52 @@ +using Dlhis.Entity.Canteen.Enums; +using Kurisu.AspNetCore.DataAccess.Entity; +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using SqlSugar; +using SqlSugar.DbConvert; + +namespace Dlhis.Entity.Canteen.Entities; + +/// +/// 券 +/// +[SugarTable("Tickets", TableDescription = "券")] +public class TicketEntity : SugarBaseEntity, ITenantId +{ + /// + /// 类型 + /// + [SugarColumn(IsNullable = false, ColumnDataType = "varchar(50)", ColumnDescription = "券类型", SqlParameterDbType = typeof(EnumToStringConvert))] + public TicketEnumType Type { get; set; } + + /// + /// 工号 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "工号")] + public string UserCode { get; set; } + + /// + /// 初始余额 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "初始余额")] + public decimal OriginalAmount { get; set; } + + /// + /// 当前余额 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "当前余额")] + public decimal Amount { get; set; } + + /// + /// 消费码 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "消费码")] + public string QrCode { get; set; } + + /// + /// 备注 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "备注")] + public string Remark { get; set; } + + public string TenantId { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Enums/TicketEnumType.cs b/Src/Dlhis.Entity/Canteen/Enums/TicketEnumType.cs new file mode 100644 index 00000000..3df284e2 --- /dev/null +++ b/Src/Dlhis.Entity/Canteen/Enums/TicketEnumType.cs @@ -0,0 +1,16 @@ +using System.ComponentModel; + +namespace Dlhis.Entity.Canteen.Enums; + +/// +/// 券类型 +/// +[Description("券类型")] +public enum TicketEnumType +{ + /// + /// 生日券 + /// + [Description("生日券")] + Birthday = 1 +} \ No newline at end of file diff --git a/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs b/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs index da1be9e3..6336d998 100644 --- a/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs +++ b/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs @@ -1,4 +1,5 @@ -using Dlhis.Entity.Basic.Entity; +using Dlhis.Constants; +using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Basic.Enums; using Dlhis.Entity.Device.Entities; using Dlhis.Entity.Device.Enums; @@ -95,7 +96,7 @@ public class DeviceUploadLogService : IDeviceUploadLogService public async Task> GetMyRecordsAsync(DeviceUploadLogMyRecordRequest request) { - var jinkoCode = _currentUser.GetUserClaim("jinko-code") ?? string.Empty; + var jinkoCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode) ?? string.Empty; return await _dbContext.Queryable() .LeftJoin((log, d) => log.DeviceUniqueNo == d.UniqueNo) diff --git a/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj b/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj index 0376df7c..0429e8ce 100644 --- a/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj +++ b/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj @@ -20,10 +20,13 @@ + + + diff --git a/Src/Dlhis.ScheduledTask/Dockerfile b/Src/Dlhis.ScheduledTask/Dockerfile index babe2308..dadbd4fe 100644 --- a/Src/Dlhis.ScheduledTask/Dockerfile +++ b/Src/Dlhis.ScheduledTask/Dockerfile @@ -1,25 +1,34 @@ -#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. +# 请参阅 https://aka.ms/customizecontainer 以了解如何自定义调试容器,以及 Visual Studio 如何使用此 Dockerfile 生成映像以更快地进行调试。 +# 此阶段用于在快速模式(默认为调试配置)下从 VS 运行时 FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 80 + +# 此阶段用于生成服务项目 FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build ARG BUILD_CONFIGURATION=Release WORKDIR /src COPY ["Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj", "Src/Dlhis.ScheduledTask/"] COPY ["Src/Dlhis.Basic.Api/Dlhis.Basic.Api.csproj", "Src/Dlhis.Basic.Api/"] +COPY ["Src/Dlhis.Canteen.Api/Dlhis.Canteen.Api.csproj", "Src/Dlhis.Canteen.Api/"] +COPY ["Src/Dlhis.Constants/Dlhis.Constants.csproj", "Src/Dlhis.Constants/"] COPY ["Src/Dlhis.Entity/Dlhis.Entity.csproj", "Src/Dlhis.Entity/"] +COPY ["Src/Dlhis.DataPermission.Model/Dlhis.DataPermission.Model.csproj", "Src/Dlhis.DataPermission.Model/"] +COPY ["Src/Dlhis.Jip.Api/Dlhis.Jip.Api.csproj", "Src/Dlhis.Jip.Api/"] COPY ["Src/Dlhis.Sys.Api/Dlhis.Sys.Api.csproj", "Src/Dlhis.Sys.Api/"] -RUN dotnet restore "./Src/Dlhis.ScheduledTask/./Dlhis.ScheduledTask.csproj" +RUN dotnet restore "./Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj" COPY . . WORKDIR "/src/Src/Dlhis.ScheduledTask" RUN dotnet build "./Dlhis.ScheduledTask.csproj" -c $BUILD_CONFIGURATION -o /app/build +# 此阶段用于发布要复制到最终阶段的服务项目 FROM build AS publish ARG BUILD_CONFIGURATION=Release RUN dotnet publish "./Dlhis.ScheduledTask.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false +# 此阶段在生产中使用,或在常规模式下从 VS 运行时使用(在不使用调试配置时为默认值) FROM base AS final WORKDIR /app COPY --from=publish /app/publish . diff --git a/Src/Dlhis.ScheduledTask/Jobs/CreateBirthdayTicketJob.cs b/Src/Dlhis.ScheduledTask/Jobs/CreateBirthdayTicketJob.cs new file mode 100644 index 00000000..75058d75 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/Jobs/CreateBirthdayTicketJob.cs @@ -0,0 +1,22 @@ +using Dlhis.Canteen.Api; +using Dlhis.Entity.Canteen.Enums; +using Dlhis.ScheduledTask.Attributes; + +namespace Dlhis.ScheduledTask.Jobs; + +/// +/// +/// +[RecurringJob(nameof(CreateBirthdayTicketJob), "0 0 1 * * ?", Name = "生日券发放")] +public class CreateBirthdayTicketJob : BaseJob +{ + public CreateBirthdayTicketJob(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + + /// + protected override async Task RunAsync(IServiceProvider serviceProvider) + { + await serviceProvider.GetService().CreateAsync(TicketEnumType.Birthday.ToString()); + } +} \ No newline at end of file diff --git a/Src/Dlhis.ScheduledTask/appsettings.Development.json b/Src/Dlhis.ScheduledTask/appsettings.Development.json index da038ced..143db3b6 100644 --- a/Src/Dlhis.ScheduledTask/appsettings.Development.json +++ b/Src/Dlhis.ScheduledTask/appsettings.Development.json @@ -7,7 +7,8 @@ }, "InternalRequest": { "SysRequestUrl": "http://localhost:5003", - "BasicRequestUrl": "http://localhost:5002" + "BasicRequestUrl": "http://localhost:5002", + "CanteenRequestUrl": "http://localhost:5008" }, "FaceUrlOptions": { "Url": "http://192.168.199.115:5002/api/gainfos/face?token=", @@ -36,18 +37,18 @@ "ClientSecret": "123456" } }, -// "JinkoOptions": { -// "Jip": { -// "BaseUrl": "http://172.16.202.34:8000", -// "Key": "FACE-7409WIBX", -// "Secret": "be0a4b88-cd80-4509-b9b9-865205d0d3d8" -// } -// }, + // "JinkoOptions": { + // "Jip": { + // "BaseUrl": "http://172.16.202.34:8000", + // "Key": "FACE-7409WIBX", + // "Secret": "be0a4b88-cd80-4509-b9b9-865205d0d3d8" + // } + // }, "JinkoOptions": { "Jip": { "BaseUrl": "http://jip.jinkosolar.com", "Key": "FACE-CUOJG9N7", "Secret": "130c2f2d-03a0-4720-8e25-538ffac7a7cb" } - }, + } } diff --git a/Src/Dlhis.ScheduledTask/appsettings.json b/Src/Dlhis.ScheduledTask/appsettings.json index b2bd19b9..d3bba67c 100644 --- a/Src/Dlhis.ScheduledTask/appsettings.json +++ b/Src/Dlhis.ScheduledTask/appsettings.json @@ -7,7 +7,8 @@ }, "InternalRequest": { "SysRequestUrl": "http://sys", - "BasicRequestUrl": "http://basic" + "BasicRequestUrl": "http://basic", + "CanteenRequestUrl": "http://canteen" }, "DataProtectionOptions": { "Enable": true, From 636874efe47dc2ce3c7ded94db4352545567497d Mon Sep 17 00:00:00 2001 From: liguoyang Date: Thu, 13 Feb 2025 17:37:47 +0800 Subject: [PATCH 03/25] =?UTF-8?q?feat=20=E4=BC=98=E5=8C=96=E6=B6=88?= =?UTF-8?q?=E8=B4=B9=E8=BF=87=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Order/Dto/OrderCheckResultDto.cs | 31 ++ .../Order/Dto/OrderPreCheckDto.cs | 16 - .../Order/Repository/IOrderRepository.cs | 2 +- .../Repository/Implements/OrderRepository.cs | 2 +- .../ConsumeHandlers/BirthdayConsumeHandler.cs | 110 ++++++ .../ConsumeHandlers/EMealVoucherHandler.cs | 166 +++++++++ .../ConsumeHandlers/OrderCommonHandler.cs | 144 ++++++++ .../Order/Services/IConsumeHandler.cs | 20 ++ .../Order/Services/IOrderCommonHandler.cs | 29 ++ .../Order/Services/Implements/OrderService.cs | 340 ++++-------------- .../Implements/BirthdayTicketService.cs | 4 +- .../Canteen/Entities/TicketEntity.cs | 9 +- .../Enums/BalanceRecordSourceEnumType.cs | 10 +- 13 files changed, 579 insertions(+), 304 deletions(-) create mode 100644 Src/Dlhis.Canteen/Order/Dto/OrderCheckResultDto.cs delete mode 100644 Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs create mode 100644 Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/BirthdayConsumeHandler.cs create mode 100644 Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/EMealVoucherHandler.cs create mode 100644 Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/OrderCommonHandler.cs create mode 100644 Src/Dlhis.Canteen/Order/Services/IConsumeHandler.cs create mode 100644 Src/Dlhis.Canteen/Order/Services/IOrderCommonHandler.cs diff --git a/Src/Dlhis.Canteen/Order/Dto/OrderCheckResultDto.cs b/Src/Dlhis.Canteen/Order/Dto/OrderCheckResultDto.cs new file mode 100644 index 00000000..8d0af378 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Dto/OrderCheckResultDto.cs @@ -0,0 +1,31 @@ +using Dlhis.Entity.Canteen.Enums; + +namespace Dlhis.Canteen.Order.Dto; + +public class OrderCheckResultDto +{ + /// + /// 消费厂区 + /// + public string Factory { get; set; } + + /// + /// 消费日期 + /// + public DateTime CostDate { get; set; } + + /// + /// 消费餐次 + /// + public ShiftEnumType ShiftType { get; set; } + + /// + /// 消费营业点 + /// + public Guid BusinessPlaceCode { get; set; } + + /// + /// 消费餐别 + /// + public Guid BusinessShiftCode { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs b/Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs deleted file mode 100644 index c4f9c9dc..00000000 --- a/Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Dlhis.Entity.Canteen.Enums; - -namespace Dlhis.Canteen.Order.Dto; - -public class OrderPreCheckDto -{ - public string Factory { get; set; } - - public DateTime CostDate { get; set; } - - public ShiftEnumType ShiftType { get; set; } - - public Guid BusinessPlaceCode { get; set; } - - public Guid BusinessShiftCode { get; set; } -} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Repository/IOrderRepository.cs b/Src/Dlhis.Canteen/Order/Repository/IOrderRepository.cs index d9e904c4..f108f713 100644 --- a/Src/Dlhis.Canteen/Order/Repository/IOrderRepository.cs +++ b/Src/Dlhis.Canteen/Order/Repository/IOrderRepository.cs @@ -7,5 +7,5 @@ namespace Dlhis.Canteen.Order.Repository; public interface IOrderRepository : IScopeDependency { - Task CreateDeviceConsumeOrderAsync(OrderPreCheckDto checkData, ConsumeRequest request, GainfoEntity gainfo); + Task CreateDeviceConsumeOrderAsync(OrderCheckResultDto checkData, ConsumeRequest request, GainfoEntity gainfo); } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Repository/Implements/OrderRepository.cs b/Src/Dlhis.Canteen/Order/Repository/Implements/OrderRepository.cs index a9e31997..23402c47 100644 --- a/Src/Dlhis.Canteen/Order/Repository/Implements/OrderRepository.cs +++ b/Src/Dlhis.Canteen/Order/Repository/Implements/OrderRepository.cs @@ -19,7 +19,7 @@ public class OrderRepository : IOrderRepository } /// - public async Task CreateDeviceConsumeOrderAsync(OrderPreCheckDto checkData, ConsumeRequest request, GainfoEntity gainfo) + public async Task CreateDeviceConsumeOrderAsync(OrderCheckResultDto checkData, ConsumeRequest request, GainfoEntity gainfo) { var order = new CanteenOrderEntity { diff --git a/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/BirthdayConsumeHandler.cs b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/BirthdayConsumeHandler.cs new file mode 100644 index 00000000..dafafc7d --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/BirthdayConsumeHandler.cs @@ -0,0 +1,110 @@ +using Dlhis.Canteen.Order.Repository; +using Dlhis.Canteen.Order.Request; +using Dlhis.Canteen.Order.Response; +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Canteen.Entities; +using Dlhis.Entity.Canteen.Enums; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.UnifyResultAndValidation; +using Kurisu.AspNetCore.Utils; +using Kurisu.AspNetCore.Utils.Extensions; +using Mapster; + +namespace Dlhis.Canteen.Order.Services.ConsumeHandlers; + +/// +/// 生日券消费处理 +/// +[Service(nameof(BalanceRecordSourceEnumType.Birthday))] +public class BirthdayConsumeHandler : IConsumeHandler +{ + private readonly IDbContext _dbContext; + private readonly IOrderCommonHandler _orderCommonHandler; + private readonly IOrderRepository _orderRepository; + + public BirthdayConsumeHandler(IDbContext dbContext, + IOrderCommonHandler orderCommonHandler, + IOrderRepository orderRepository) + { + _dbContext = dbContext; + _orderCommonHandler = orderCommonHandler; + _orderRepository = orderRepository; + } + + public async Task> ConsumeAsync(OrderAddRequest request, GainfoEntity gainfo) + { + var msg = string.Empty; + var ticketNo = request.UserUniqueNo; + + var exists = await _dbContext.Queryable() + .Where(x => x.Type == TicketEnumType.Birthday) + .Where(x => x.QrCode == ticketNo) + .AnyAsync(); + + exists.ThrowIfFalse("生日券无效"); + + try + { + var checkData = await _orderCommonHandler.PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime!.Value); + var isSupermarket = await _dbContext.Queryable() + .Where(x => x.Code == checkData.BusinessPlaceCode) + .Select(x => x.Catalog == CanteenBusinessPlaceCatalogEnumType.Supermarket) + .SingleAsync(); + + isSupermarket.ThrowIfFalse("请在超市消费"); + + var order = await _orderRepository.CreateDeviceConsumeOrderAsync(checkData, request.Adapt(), gainfo); + + await _orderCommonHandler.TryConsumeAsync(order.Id, async () => + { + await CommonHelper.RetryAsync(async () => + { + var ticket = await _dbContext.Queryable() + .Where(x => x.Type == TicketEnumType.Birthday) + .Where(x => x.QrCode == ticketNo) + .SingleAsync(); + + //金额+- + ticket.Balance += order.Amount; + (ticket.Balance < 0).ThrowIfTrue("余额不足,无法消费"); + + await _dbContext.Updateable() + .SetColumns(x => x.Balance == ticket.Balance) + .SetColumns(x => x.Version == x.Version + 1) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.QrCode == ticketNo && x.Version == ticket.Version) //必须与查询时的version一致 + .ExecuteCommandThrowVersionAsync(); + + //写入记录 + var balanceRecord = order.Adapt(); + balanceRecord.Remark = $"{ticket.QrCode}(生日券消费)"; + await _dbContext.InsertAsync(balanceRecord); + }, 5); + }); + } + catch (Exception ex) + { + msg = ex.Message; + } + + //获取餐券余额 + var data = await _dbContext.Queryable() + .LeftJoin((x, ga) => x.UserCode == ga.Code) + .Where(x => x.Type == TicketEnumType.Birthday && x.QrCode == ticketNo) + .Select((x, ga) => new OrderResultResponse + { + UserCode = x.UserCode, + UserName = ga.Name, + CurrentBalance = x.Balance + }) + .SingleAsync(); + + return new DefaultApiResult + { + Code = msg.IsPresent() ? ApiStateCode.Error : ApiStateCode.Success, + Data = data, + Msg = msg + }; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/EMealVoucherHandler.cs b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/EMealVoucherHandler.cs new file mode 100644 index 00000000..86140edf --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/EMealVoucherHandler.cs @@ -0,0 +1,166 @@ +using Dlhis.Canteen.Order.Repository; +using Dlhis.Canteen.Order.Request; +using Dlhis.Canteen.Order.Response; +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Canteen.Entities; +using Dlhis.Entity.Canteen.Enums; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.UnifyResultAndValidation; +using Kurisu.AspNetCore.Utils; +using Kurisu.AspNetCore.Utils.Extensions; +using Mapster; + +namespace Dlhis.Canteen.Order.Services.ConsumeHandlers; + +/// +/// 电子餐券处理 +/// +[Service(nameof(BalanceRecordSourceEnumType.EMealVoucher))] +public class EMealVoucherHandler : IConsumeHandler +{ + private readonly IDbContext _dbContext; + private readonly IOrderRepository _orderRepository; + private readonly IOrderCommonHandler _orderCommonHandler; + + public EMealVoucherHandler(IDbContext dbContext, + IOrderRepository orderRepository, + IOrderCommonHandler orderCommonHandler) + { + _dbContext = dbContext; + _orderRepository = orderRepository; + _orderCommonHandler = orderCommonHandler; + } + + public async Task> ConsumeAsync(OrderAddRequest request, GainfoEntity gainfo) + { + var msg = string.Empty; + var originData = await _dbContext.Queryable() + .Where(x => x.QrCode == request.UserUniqueNo) + .Select(x => x.OriginData) + .SingleAsync(); + + if (originData.IsEmpty()) + { + msg = "无法识别"; + return new DefaultApiResult + { + Code = ApiStateCode.Error, + Data = null, + Msg = msg + }; + } + + var originDataItems = originData.Split(":"); + var no = originDataItems[0]; + var idNo = originDataItems[3]; + + try + { + await EMealVoucherConsumeAsync(request.Adapt(), gainfo, originData, no, idNo); + } + catch (Exception ex) + { + msg = ex.Message; + } + + //获取餐券余额 + var data = await _dbContext.Queryable() + .LeftJoin((x, d) => x.No == d.No) + .Where((x, d) => x.No == no && d.IdNo == idNo) + .Select((x, d) => new OrderResultResponse + { + UserCode = d.IdNo, + UserName = d.Name, + CurrentBalance = d.Balance + }) + .SingleAsync(); + + try + { + var v = data.UserCode ?? string.Empty; + var vc = v.ToCharArray().Reverse().ToList(); + + for (int i = 0; i < vc.Count; i++) + { + if (i + 1 > 4) + { + vc[i] = '*'; + } + } + + vc.Reverse(); + data.UserCode = string.Join("", vc); + } + catch (Exception) + { + //ignore + } + + return new DefaultApiResult + { + Code = msg.IsPresent() ? ApiStateCode.Error : ApiStateCode.Success, + Data = data, + Msg = msg + }; + } + + + /// + /// 电子餐券消费 + /// + /// + /// + /// + /// + /// + private async Task EMealVoucherConsumeAsync(ConsumeRequest request, GainfoEntity gainfo, string originData, string no, string idNo) + { + var now = DateTime.Now; + + var current = await _dbContext.Queryable() + .Where(x => x.No == no && x.IdNo == idNo) + .Select(x => new { x.Name, x.Start, x.End }) + .SingleAsync(); + + (now >= current.Start && now <= current.End).ThrowIfFalse("餐券已过期"); + + var eMealVoucher = await _dbContext.Queryable().Where(x => x.No == no).SingleAsync(); + + var checkData = await _orderCommonHandler.PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime); + var isSupermarket = await _dbContext.Queryable() + .Where(x => x.Code == checkData.BusinessPlaceCode) + .Select(x => x.Catalog == CanteenBusinessPlaceCatalogEnumType.Supermarket) + .SingleAsync(); + + isSupermarket.ThrowIfTrue("禁止在超市消费"); + + eMealVoucher.Factories.Contains(checkData.Factory).ThrowIfFalse("禁止在当前厂区消费"); + + gainfo.No = originData; + var order = await _orderRepository.CreateDeviceConsumeOrderAsync(checkData, request, gainfo); + + await _orderCommonHandler.TryConsumeAsync(order.Id, async () => + { + await CommonHelper.RetryAsync(async () => + { + var detail = await _dbContext.Queryable().Where(x => x.No == no && x.IdNo == idNo).SingleAsync(); + //金额+- + detail.Balance += order.Amount; + (detail.Balance < 0).ThrowIfTrue("余额不足,无法消费"); + + await _dbContext.Updateable() + .SetColumns(x => x.Balance == detail.Balance) + .SetColumns(x => x.Version == x.Version + 1) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.No == no && x.IdNo == idNo && x.Version == detail.Version) //必须与查询时的version一致 + .ExecuteCommandThrowVersionAsync(); + + //写入记录 + var balanceRecord = order.Adapt(); + balanceRecord.Remark = $"({no})" + current.Name; + await _dbContext.InsertAsync(balanceRecord); + }, 5); + }); + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/OrderCommonHandler.cs b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/OrderCommonHandler.cs new file mode 100644 index 00000000..21ac6801 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/OrderCommonHandler.cs @@ -0,0 +1,144 @@ +using Dlhis.Canteen.Order.Dto; +using Dlhis.Canteen.Setting.Services; +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.CustomClass; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.Utils.Extensions; + +namespace Dlhis.Canteen.Order.Services.ConsumeHandlers; + +/// +/// 订单通用处理 +/// +public class OrderCommonHandler : IOrderCommonHandler +{ + private readonly IDbContext _dbContext; + private readonly ICanteenSettingService _canteenSettingService; + private readonly ILogger _logger; + private readonly IHttpContextAccessor _httpContextAccessor; + + public OrderCommonHandler(IDbContext dbContext, + IHttpContextAccessor httpContextAccessor, + ICanteenSettingService canteenSettingService, + ILogger logger) + { + _dbContext = dbContext; + _canteenSettingService = canteenSettingService; + _httpContextAccessor = httpContextAccessor; + _logger = logger; + } + + /// + /// 设置设备ip + /// + /// + public async Task SetDeviceIpInfoAsync(string deviceNo) + { + try + { + if (_httpContextAccessor.HttpContext!.Request.Headers.TryGetValue("X-Requested-DeviceIp", out var ip)) + { + var device = await _dbContext.Queryable().Where(x => x.UniqueNo == deviceNo).SingleAsync(); + device.ConnectionInfo = new + { + ip = ip.ToString() + }.ToJson(); + + await _dbContext.UpdateAsync(device); + } + + _logger.LogInformation("设备ip获取:{deviceNo} {ip}", deviceNo, ip); + } + catch (Exception) + { + //ignore + } + } + + /// + /// 消费前预检 + /// + /// 设备号 + /// 消费时间 + /// + public async Task PreCheckAsync(string deviceUniqueNo, DateTime costDateTime) + { + var device = await _dbContext.Queryable().Where(x => x.UniqueNo == deviceUniqueNo).SingleAsync(); + device.ThrowIfNull("设备尚未登记"); + device.Enable.ThrowIfFalse("设备已被停用"); + (device.Type != DeviceTypeEnumType.Meal).ThrowIfTrue("设备类型有误"); + + var bindingInfo = await _dbContext.Queryable() + .LeftJoin((x, b) => x.BusinessPlaceCode == b.Code) + .LeftJoin((x, b, bs) => bs.PlaceCode == b.Code) + .Where(x => x.DeviceUniqueNo == deviceUniqueNo && x.BusinessPlaceCode.HasValue) + .Select((x, b, bs) => new + { + b.Code, + bs.ShiftCode, + Factory = x.TenantId + }) + .SingleAsync(); + + bindingInfo.ThrowIfNull("设备尚未登记营业点"); + + //获取当前消费餐次 + var shifts = await _dbContext.Queryable() + .Where(x => x.ShiftCode == bindingInfo.ShiftCode) + .Select(x => new { x.ShiftType, x.Start, x.End }) + .ToListAsync(); + shifts.ThrowIfEmpty("营业点餐次尚未设置"); + + var shift = shifts.FirstOrDefault(x => new TimePeriod + { + Start = x.Start, + End = x.End + }.IsPresent(costDateTime)); + shift.ThrowIfNull("非就餐时间"); + + var costDate = await _canteenSettingService.GetCostDateAsync(bindingInfo.Factory, costDateTime); + + return new OrderCheckResultDto + { + Factory = bindingInfo.Factory, + CostDate = costDate, + ShiftType = shift!.ShiftType, + BusinessPlaceCode = bindingInfo.Code, + BusinessShiftCode = bindingInfo.ShiftCode + }; + } + + /// + /// 消费更新处理 + /// + /// + /// + public async Task TryConsumeAsync(long orderId, Func action) + { + try + { + await action(); + + await _dbContext.Updateable() + .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Success) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.Id == orderId) + .ExecuteCommandAsync(); + } + catch (Exception ex) + { + await _dbContext.Updateable() + .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Failure) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .SetColumns(x => x.Result == ex.Message) + .Where(x => x.Id == orderId) + .ExecuteCommandAsync(); + + throw; + } + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/IConsumeHandler.cs b/Src/Dlhis.Canteen/Order/Services/IConsumeHandler.cs new file mode 100644 index 00000000..4de14676 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Services/IConsumeHandler.cs @@ -0,0 +1,20 @@ +using Dlhis.Canteen.Order.Request; +using Dlhis.Canteen.Order.Response; +using Dlhis.Entity.Basic.Entity; +using Kurisu.AspNetCore.UnifyResultAndValidation; + +namespace Dlhis.Canteen.Order.Services; + +/// +/// 消费处理器 +/// +public interface IConsumeHandler : IScopeDependency +{ + /// + /// 消费 + /// + /// + /// + /// + Task> ConsumeAsync(OrderAddRequest request, GainfoEntity gainfo); +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/IOrderCommonHandler.cs b/Src/Dlhis.Canteen/Order/Services/IOrderCommonHandler.cs new file mode 100644 index 00000000..c1762121 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Services/IOrderCommonHandler.cs @@ -0,0 +1,29 @@ +using Dlhis.Canteen.Order.Dto; + +namespace Dlhis.Canteen.Order.Services; + +public interface IOrderCommonHandler : IScopeDependency +{ + /// + /// 消费更新处理 + /// + /// + /// + /// + Task TryConsumeAsync(long orderId, Func action); + + /// + /// 设置设备ip + /// + /// + /// + Task SetDeviceIpInfoAsync(string deviceNo); + + /// + /// 消费前预检 + /// + /// 设备号 + /// 消费时间 + /// + Task PreCheckAsync(string deviceUniqueNo, DateTime costDateTime); +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs index d6284a13..22203026 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs @@ -1,19 +1,14 @@ using Dlhis.Basic.Api; -using Dlhis.Canteen.Order.Dto; using Dlhis.Canteen.Order.Repository; +using Dlhis.Canteen.Order.Request; +using Dlhis.Canteen.Order.Response; using Dlhis.Canteen.Setting.Services; +using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; -using Dlhis.Entity.Device.Entities; -using Kurisu.AspNetCore.Utils; -using Kurisu.AspNetCore.Utils.Extensions; -using Mapster; -using SqlSugar; -using Dlhis.Canteen.Order.Response; -using Dlhis.Canteen.Order.Request; using Dlhis.Entity.Device; -using Dlhis.Entity.Device.Enums; +using Dlhis.Entity.Device.Entities; using Kurisu.AspNetCore.Authentication.Abstractions; using Kurisu.AspNetCore.Cache; using Kurisu.AspNetCore.CustomClass; @@ -21,7 +16,10 @@ using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using Kurisu.AspNetCore.UnifyResultAndValidation; -using Dlhis.Constants; +using Kurisu.AspNetCore.Utils; +using Kurisu.AspNetCore.Utils.Extensions; +using Mapster; +using SqlSugar; namespace Dlhis.Canteen.Order.Services.Implements; @@ -30,31 +28,34 @@ public class OrderService : IOrderService private readonly ICanteenSettingService _canteenSettingService; private readonly IDbContext _dbContext; private readonly ICurrentUser _currentUser; - private readonly IHttpContextAccessor _httpContextAccessor; private readonly IBalanceRepository _balanceRepository; private readonly IOrderRepository _orderRepository; private readonly RedisCache _redisCache; private readonly IGainfoPermissionApi _gainfoPermissionApi; + private readonly IOrderCommonHandler _orderCommonHandler; + private readonly INamedResolver _namedResolver; private readonly ILogger _logger; public OrderService(ICanteenSettingService canteenSettingService, IDbContext dbContext, ICurrentUser currentUser, - IHttpContextAccessor httpContextAccessor, IBalanceRepository balanceRepository, IOrderRepository orderRepository, RedisCache redisCache, IGainfoPermissionApi gainfoPermissionApi, + IOrderCommonHandler orderCommonHandler, + INamedResolver namedResolver, ILogger logger) { _canteenSettingService = canteenSettingService; _dbContext = dbContext; _currentUser = currentUser; - _httpContextAccessor = httpContextAccessor; _balanceRepository = balanceRepository; _orderRepository = orderRepository; _redisCache = redisCache; _gainfoPermissionApi = gainfoPermissionApi; + _orderCommonHandler = orderCommonHandler; + _namedResolver = namedResolver; _logger = logger; } @@ -75,7 +76,7 @@ public class OrderService : IOrderService /// public async Task> AddAsync(OrderAddRequest request) { - await SetDeviceIpInfoAsync(request.DeviceUniqueNo); + await _orderCommonHandler.SetDeviceIpInfoAsync(request.DeviceUniqueNo); await using var handler = await _redisCache.LockAsync($"consume:device:{request.UserUniqueNo}"); handler.Acquired.ThrowIfFalse("请勿频繁消费"); @@ -152,39 +153,47 @@ public class OrderService : IOrderService var s = long.TryParse(request.UserUniqueNo, out var userId); GainfoEntity gainfo; + //条码消费 if (request.Source == BalanceRecordSourceEnumType.QrCode) { - if (request.UserUniqueNo.StartsWith(QrCodeConstants.User)) + var flag = request.UserUniqueNo.Substring(0, 2); + switch (flag) { - gainfo = await GetUserByQrCodeAsync(request.UserUniqueNo); - await CheckPermissionAsync(gainfo.Code, request.DeviceUniqueNo); - } - else if (request.UserUniqueNo.StartsWith(QrCodeConstants.EMealVoucher)) - { - request.Source = BalanceRecordSourceEnumType.EMealVoucher; - var eMealVoucherQrCode = await _dbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); - eMealVoucherQrCode.ThrowIfNull("无法识别"); - var code = eMealVoucherQrCode.OriginData.Split(':')[2]; - gainfo = await _dbContext.Queryable().Where(x => x.Code == code).SingleAsync(); - } - else if (request.UserUniqueNo.StartsWith(QrCodeConstants.Birthday)) - { - var ticket = await _dbContext.Queryable().Where(x => x.Type == TicketEnumType.Birthday).Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); - ticket.ThrowIfNull("无法识别"); - gainfo = await _dbContext.Queryable().Where(x => x.Code == ticket.UserCode).SingleAsync(); - } - else - { - throw new UserFriendlyException($"无法识别{request.UserUniqueNo}"); + case QrCodeConstants.User: + { + gainfo = await GetUserByQrCodeAsync(request.UserUniqueNo); + await CheckPermissionAsync(gainfo.Code, request.DeviceUniqueNo); + } + break; + case QrCodeConstants.EMealVoucher: + { + request.Source = BalanceRecordSourceEnumType.EMealVoucher; + var eMealVoucherQrCode = await _dbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); + eMealVoucherQrCode.ThrowIfNull("无法识别"); + var code = eMealVoucherQrCode.OriginData.Split(':')[2]; + gainfo = await _dbContext.Queryable().Where(x => x.Code == code).SingleAsync(); + } + break; + case QrCodeConstants.Birthday: + { + request.Source = BalanceRecordSourceEnumType.Birthday; + var ticket = await _dbContext.Queryable().Where(x => x.Type == TicketEnumType.Birthday).Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); + ticket.ThrowIfNull("无法识别"); + gainfo = await _dbContext.Queryable().Where(x => x.Code == ticket.UserCode).SingleAsync(); + } + break; + + default: throw new UserFriendlyException($"无法识别{request.UserUniqueNo}"); } } else { //根据档案号 + //区分userId和code: 工号纯数字避免跟userId相同导致查询到的消费人错误 gainfo = await _dbContext.Queryable() - .WhereIF(request.Source == BalanceRecordSourceEnumType.Card, x => x.CardNo == request.UserUniqueNo) - .WhereIF(request.Source != BalanceRecordSourceEnumType.Card && !request.IsUserId, x => x.Code == request.UserUniqueNo) - .WhereIF(request.Source != BalanceRecordSourceEnumType.Card && request.IsUserId && s, x => x.Id == userId) + .WhereIF(request.Source == BalanceRecordSourceEnumType.Card, x => x.CardNo == request.UserUniqueNo) //卡号 + .WhereIF(request.Source != BalanceRecordSourceEnumType.Card && !request.IsUserId, x => x.Code == request.UserUniqueNo) //工号 + .WhereIF(request.Source != BalanceRecordSourceEnumType.Card && request.IsUserId && s, x => x.Id == userId) //user id .SingleAsync(); } @@ -230,7 +239,7 @@ public class OrderService : IOrderService //一天消费金额 var dayCostMax = await _canteenSettingService.GetSettingAsync(CanteenSettingItemEnumType.DayCostMax, order.TenantId, order.UserNo); - if (dayCostMax != default) + if (dayCostMax != 0) { //消费记录一定会有营业点代码!.Value是安全用法 var cost = todayAllBalanceRecords @@ -242,7 +251,7 @@ public class OrderService : IOrderService //一次消费金额 var onceCostMax = await _canteenSettingService.GetSettingAsync(CanteenSettingItemEnumType.OnceCostMax, order.TenantId, order.UserNo); - if (onceCostMax != default) + if (onceCostMax != 0) { (Math.Abs(order.Amount) > onceCostMax).ThrowIfTrue($"单次消费金额不能超出{onceCostMax}元"); } @@ -251,7 +260,7 @@ public class OrderService : IOrderService if (order.BusinessPlaceCode.HasValue && supermarketCodes.Contains(order.BusinessPlaceCode.Value)) { var dayMarketCostMax = await _canteenSettingService.GetSettingAsync(CanteenSettingItemEnumType.DayMarketCostMax, order.TenantId, order.UserNo); - if (dayMarketCostMax != default) + if (dayMarketCostMax != 0) { var cost = todayAllBalanceRecords.Where(x => x.BusinessPlaceCode.HasValue) .Where(x => supermarketCodes.Contains(x.BusinessPlaceCode.Value)) @@ -354,7 +363,7 @@ public class OrderService : IOrderService /// private async Task ConsumeAsync(ConsumeRequest request, GainfoEntity gainfo) { - var checkData = await PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime); + var checkData = await _orderCommonHandler.PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime); var order = await _orderRepository.CreateDeviceConsumeOrderAsync(checkData, request, gainfo); if (request.Image.IsPresent()) @@ -367,7 +376,7 @@ public class OrderService : IOrderService }); } - await TryConsumeAsync(order.Id, async () => + await _orderCommonHandler.TryConsumeAsync(order.Id, async () => { //校验 await Verify(order); @@ -380,78 +389,11 @@ public class OrderService : IOrderService }); } - private async Task> EMealVoucherConsumeAsync(OrderAddRequest request, GainfoEntity gainfo) - { - var msg = string.Empty; - var originData = await _dbContext.Queryable() - .Where(x => x.QrCode == request.UserUniqueNo) - .Select(x => x.OriginData) - .SingleAsync(); - if (originData.IsEmpty()) - { - msg = "无法识别"; - return new DefaultApiResult - { - Code = ApiStateCode.Error, - Data = null, - Msg = msg - }; - } - - var originDataItems = originData.Split(":"); - var no = originDataItems[0]; - var idNo = originDataItems[3]; - - try - { - await EMealVoucherConsumeAsync(request.Adapt(), gainfo, originData, no, idNo); - } - catch (Exception ex) - { - msg = ex.Message; - } - - //获取餐券余额 - var data = await _dbContext.Queryable() - .LeftJoin((x, d) => x.No == d.No) - .Where((x, d) => x.No == no && d.IdNo == idNo) - .Select((x, d) => new OrderResultResponse - { - UserCode = d.IdNo, - UserName = d.Name, - CurrentBalance = d.Balance - }) - .SingleAsync(); - - try - { - var v = data.UserCode ?? string.Empty; - var vc = v.ToCharArray().Reverse().ToList(); - - for (int i = 0; i < vc.Count; i++) - { - if (i + 1 > 4) - { - vc[i] = '*'; - } - } - - vc.Reverse(); - data.UserCode = string.Join("", vc); - } - catch (Exception) - { - //ignore - } - - return new DefaultApiResult - { - Code = msg.IsPresent() ? ApiStateCode.Error : ApiStateCode.Success, - Data = data, - Msg = msg - }; - } + // private async Task> BirthdayConsumeAsync(OrderAddRequest request, GainfoEntity gainfo) + // { + // + // } private async Task OfflineConsumeAsync(OrderAddRequest request, GainfoEntity gainfo) @@ -490,8 +432,9 @@ public class OrderService : IOrderService { var message = string.Empty; - if (request.Source == BalanceRecordSourceEnumType.EMealVoucher) - return await EMealVoucherConsumeAsync(request, gainfo); + var otherTypes = new[] { BalanceRecordSourceEnumType.EMealVoucher, BalanceRecordSourceEnumType.Birthday }; + if (otherTypes.Contains(request.Source)) + return await _namedResolver.GetService(request.Source.ToString()).ConsumeAsync(request, gainfo); if (request.IsOffline) await OfflineConsumeAsync(request, gainfo); @@ -547,144 +490,6 @@ public class OrderService : IOrderService return await _dbContext.Queryable().Where(x => x.Code == gainfoQrCode.UserCode).SingleAsync(); } - /// - /// 电子餐券消费 - /// - /// - /// - /// - /// - /// - private async Task EMealVoucherConsumeAsync(ConsumeRequest request, GainfoEntity gainfo, string originData, string no, string idNo) - { - var now = DateTime.Now; - - var current = await _dbContext.Queryable() - .Where(x => x.No == no && x.IdNo == idNo) - .Select(x => new { x.Name, x.Start, x.End }) - .SingleAsync(); - - (now >= current.Start && now <= current.End).ThrowIfFalse("餐券已过期"); - - - var eMealVoucher = await _dbContext.Queryable().Where(x => x.No == no).SingleAsync(); - - var checkData = await PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime); - var isSupermarket = await _dbContext.Queryable().Where(x => x.Code == checkData.BusinessPlaceCode) - .Select(x => x.Catalog == CanteenBusinessPlaceCatalogEnumType.Supermarket) - .SingleAsync(); - - isSupermarket.ThrowIfTrue("禁止在超市消费"); - - eMealVoucher.Factories.Contains(checkData.Factory).ThrowIfFalse("禁止在当前厂区消费"); - - gainfo.No = originData; - var order = await _orderRepository.CreateDeviceConsumeOrderAsync(checkData, request, gainfo); - - await TryConsumeAsync(order.Id, async () => - { - await CommonHelper.RetryAsync(async () => - { - var detail = await _dbContext.Queryable().Where(x => x.No == no && x.IdNo == idNo).SingleAsync(); - //金额+- - detail.Balance += order.Amount; - (detail.Balance < 0).ThrowIfTrue("余额不足,无法消费"); - - await _dbContext.Updateable() - .SetColumns(x => x.Balance == detail.Balance) - .SetColumns(x => x.Version == x.Version + 1) - .SetColumns(x => x.ModifiedTime == DateTime.Now) - .Where(x => x.No == no && x.IdNo == idNo && x.Version == detail.Version) //必须与查询时的version一致 - .ExecuteCommandThrowVersionAsync(); - - //写入记录 - var balanceRecord = order.Adapt(); - balanceRecord.Remark = $"({no})" + current.Name; - await _dbContext.InsertAsync(balanceRecord); - }, 5); - }); - } - - /// - /// 消费前预检 - /// - /// - /// - /// - private async Task PreCheckAsync(string deviceUniqueNo, DateTime costDateTime) - { - var device = await _dbContext.Queryable().Where(x => x.UniqueNo == deviceUniqueNo).SingleAsync(); - device.ThrowIfNull("设备尚未登记"); - device.Enable.ThrowIfFalse("设备已被停用"); - (device.Type != DeviceTypeEnumType.Meal).ThrowIfTrue("设备类型有误"); - - var bindingInfo = await _dbContext.Queryable() - .LeftJoin((x, b) => x.BusinessPlaceCode == b.Code) - .LeftJoin((x, b, bs) => bs.PlaceCode == b.Code) - .Where(x => x.DeviceUniqueNo == deviceUniqueNo && x.BusinessPlaceCode.HasValue) - .Select((x, b, bs) => new - { - b.Code, - bs.ShiftCode, - Factory = x.TenantId - }) - .SingleAsync(); - - bindingInfo.ThrowIfNull("设备尚未登记营业点"); - - //获取当前消费餐次 - var shifts = await _dbContext.Queryable() - .Where(x => x.ShiftCode == bindingInfo.ShiftCode) - .Select(x => new { x.ShiftType, x.Start, x.End }) - .ToListAsync(); - shifts.ThrowIfEmpty("营业点餐次尚未设置"); - - var shift = shifts.FirstOrDefault(x => new TimePeriod - { - Start = x.Start, - End = x.End - }.IsPresent(costDateTime)); - shift.ThrowIfNull("非就餐时间"); - - var costDate = await _canteenSettingService.GetCostDateAsync(bindingInfo.Factory, costDateTime); - - return new OrderPreCheckDto - { - Factory = bindingInfo.Factory, - CostDate = costDate, - ShiftType = shift!.ShiftType, - BusinessPlaceCode = bindingInfo.Code, - BusinessShiftCode = bindingInfo.ShiftCode - }; - } - - /// - /// 设置设备ip - /// - /// - private async Task SetDeviceIpInfoAsync(string deviceNo) - { - try - { - if (_httpContextAccessor.HttpContext!.Request.Headers.TryGetValue("X-Requested-DeviceIp", out var ip)) - { - var device = await _dbContext.Queryable().Where(x => x.UniqueNo == deviceNo).SingleAsync(); - device.ConnectionInfo = new - { - ip = ip.ToString() - }.ToJson(); - - await _dbContext.UpdateAsync(device); - } - - _logger.LogInformation("设备ip获取:{deviceNo} {ip}", deviceNo, ip); - } - catch (Exception) - { - //ignore - } - } - /// /// 检查是否能够进行离线消费,处理hpt重复提交 /// @@ -700,34 +505,9 @@ public class OrderService : IOrderService if (orders.IsEmpty()) return true; - var order = orders.FirstOrDefault(); + var order = orders.FirstOrDefault()!; //存在在线order数据,但是状态未成功 return !order.IsOffline && order.OrderStatus != CanteenOrderStatusEnumType.Success; } - - private async Task TryConsumeAsync(long orderId, Func action) - { - try - { - await action(); - - await _dbContext.Updateable() - .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Success) - .SetColumns(x => x.ModifiedTime == DateTime.Now) - .Where(x => x.Id == orderId) - .ExecuteCommandAsync(); - } - catch (Exception ex) - { - await _dbContext.Updateable() - .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Failure) - .SetColumns(x => x.ModifiedTime == DateTime.Now) - .SetColumns(x => x.Result == ex.Message) - .Where(x => x.Id == orderId) - .ExecuteCommandAsync(); - - throw; - } - } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs b/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs index ba75b0e9..78bc5e07 100644 --- a/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs +++ b/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs @@ -40,8 +40,8 @@ public class BirthdayTicketService : BaseTicketService, IBirthdayTicketService { Type = TicketEnumType.Birthday, UserCode = item.Code, - OriginalAmount = amount, - Amount = amount, + OriginalBalance = amount, + Balance = amount, QrCode = qrCode, Remark = todayStr + "生日券", TenantId = item.Factory diff --git a/Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs index d3ca3c05..451b7ba4 100644 --- a/Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs +++ b/Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs @@ -10,7 +10,7 @@ namespace Dlhis.Entity.Canteen.Entities; /// 券 /// [SugarTable("Tickets", TableDescription = "券")] -public class TicketEntity : SugarBaseEntity, ITenantId +public class TicketEntity : SugarBaseEntity, ITenantId, IVersion { /// /// 类型 @@ -28,13 +28,13 @@ public class TicketEntity : SugarBaseEntity, ITenantId /// 初始余额 /// [SugarColumn(IsNullable = false, ColumnDescription = "初始余额")] - public decimal OriginalAmount { get; set; } + public decimal OriginalBalance { get; set; } /// /// 当前余额 /// [SugarColumn(IsNullable = false, ColumnDescription = "当前余额")] - public decimal Amount { get; set; } + public decimal Balance { get; set; } /// /// 消费码 @@ -49,4 +49,7 @@ public class TicketEntity : SugarBaseEntity, ITenantId public string Remark { get; set; } public string TenantId { get; set; } + + /// + public int Version { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs b/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs index 79d86f43..16f5a7fe 100644 --- a/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs +++ b/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs @@ -37,6 +37,14 @@ public enum BalanceRecordSourceEnumType /// [Description("电子餐券")] EMealVoucher, + + + /// + /// 生日券 + /// + [Description("生日券")] + Birthday, + //********************************************************************************************************* /// @@ -70,7 +78,7 @@ public enum BalanceRecordSourceEnumType /// [Description("其他基地餐补")] OtherTenantSubsidies, - + /// /// 余额写入 /// From 20e5350b4947472a4abfb742781c7b5703743225 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Wed, 19 Feb 2025 12:11:13 +0800 Subject: [PATCH 04/25] =?UTF-8?q?add=20=E8=80=83=E5=8B=A4=E5=88=86?= =?UTF-8?q?=E9=A1=B5=E5=92=8C=E8=A1=A5=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Implements/SapBusinessTripService.cs | 1 - .../Controllers/WorkGridsController.cs | 25 ++++++- .../WorkGridScheduleAttendancePageRequest.cs | 13 ++++ .../WorkGridScheduleAttendancePageResponse.cs | 63 +++++++++++++++++ .../Services/IWorkGridScheduleService.cs | 5 ++ .../Implements/WorkGridScheduleService.cs | 68 ++++++++++++++++++- 6 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleAttendancePageRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleAttendancePageResponse.cs diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/SapBusinessTripService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/SapBusinessTripService.cs index 7460cf1a..a89f549d 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/SapBusinessTripService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/SapBusinessTripService.cs @@ -1,4 +1,3 @@ -using Dlhis.Basic.Device.Services; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Device.Entities; using Dlhis.Entity.Device.Enums; diff --git a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs index 4549aca8..c8a31385 100644 --- a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs +++ b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs @@ -51,7 +51,7 @@ public class WorkGridsController : ControllerBase { return await _workGridService.GetPageAsync(request); } - + /// /// 修改网格管理者 /// @@ -61,7 +61,7 @@ public class WorkGridsController : ControllerBase { await _workGridService.ChangeAsync(request.From, request.To); } - + /// /// 获取我的网格信息 /// @@ -151,4 +151,25 @@ public class WorkGridsController : ControllerBase { return await _workGridScheduleService.GetListSummaryAsync(workGridCode, start, end); } + + /// + /// 获取网格人员考勤记录分页 + /// + /// + /// + [HttpGet("user/attendance/page")] + public async Task> GetAttendancePageAsync(WorkGridScheduleAttendancePageRequest request) + { + return await _workGridScheduleService.GetAttendancePageAsync(request); + } + + /// + /// 网格人员考勤记录补传 + /// + /// + [HttpPost("user/attendance/upload")] + public async Task ManuallyUploadAsync(List logIds) + { + await _workGridScheduleService.ManuallyUploadAsync(logIds); + } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleAttendancePageRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleAttendancePageRequest.cs new file mode 100644 index 00000000..bc783d40 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleAttendancePageRequest.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; +using Kurisu.AspNetCore.CustomClass; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridScheduleAttendancePageRequest : PageDto +{ + [Required(ErrorMessage = "工号不能为空")] + public string UserCode { get; set; } + + public DateTimePeriod DateTimePeriod { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleAttendancePageResponse.cs b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleAttendancePageResponse.cs new file mode 100644 index 00000000..e4e3ff16 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleAttendancePageResponse.cs @@ -0,0 +1,63 @@ +using Newtonsoft.Json; + +namespace Dlhis.Basic.WorkGrids.Response; + +public class WorkGridScheduleAttendancePageResponse +{ + public long Id { get; set; } + + /// + /// 设备号 + /// + public string DeviceUniqueNo { get; set; } + + /// + /// 设备部署点 + /// + public string DeployPlace { get; set; } + + /// + /// 用户学工号 + /// + public string UserCode { get; set; } + + + /// + /// 用户名称 + /// + public string UserName { get; set; } + + /// + /// 上传时间 + /// + public DateTime RaiseDateTime { get; set; } + + /// + /// 记录创建时间 + /// + public DateTime CreateTime { get; set; } + + /// + /// 序列号 + /// + public string SerialNo { get; set; } + + + [JsonIgnore] + public string OriginUserUniqueNo { get; set; } + + /// + /// 是否同步sap + /// + public bool Sync { get; set; } + + /// + /// 是否需要上传 + /// + public bool NeedUpload { get; set; } + + /// + /// 是否有效 + /// + public bool Status { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs index 2b6783d9..df2d46fc 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs @@ -1,5 +1,6 @@ using Dlhis.Basic.WorkGrids.Request; using Dlhis.Basic.WorkGrids.Response; +using Kurisu.AspNetCore.DataAccess.Dto; namespace Dlhis.Basic.WorkGrids.Services; @@ -13,4 +14,8 @@ public interface IWorkGridScheduleService : IScopeDependency Task> GetListAsync(Guid workGridCode, DateOnly date); Task> GetListSummaryAsync(Guid workGridCode, DateOnly start, DateOnly end); + + Task> GetAttendancePageAsync(WorkGridScheduleAttendancePageRequest request); + + Task ManuallyUploadAsync(List logIds); } \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs index 1e2f25c7..40c2d706 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs @@ -1,6 +1,12 @@ using Dlhis.Basic.WorkGrids.Request; using Dlhis.Basic.WorkGrids.Response; using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Device.Entities; +using Dlhis.Jip.Api; +using Dlhis.Jip.Api.Requests; +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; @@ -9,10 +15,12 @@ namespace Dlhis.Basic.WorkGrids.Services.Implements; public class WorkGridScheduleService : IWorkGridScheduleService { private readonly IDbContext _dbContext; + private readonly IJinkoJipApi _jinkoJipApi; - public WorkGridScheduleService(IDbContext dbContext) + public WorkGridScheduleService(IDbContext dbContext ,IJinkoJipApi jinkoJipApi) { _dbContext = dbContext; + _jinkoJipApi = jinkoJipApi; } public async Task SaveAsync(WorkGridScheduleSaveRequest request) @@ -78,4 +86,62 @@ public class WorkGridScheduleService : IWorkGridScheduleService }; }); } + + /// + public async Task> GetAttendancePageAsync(WorkGridScheduleAttendancePageRequest request) + { + return await _dbContext.Queryable() + .LeftJoin((log, d) => log.DeviceUniqueNo == d.UniqueNo) + .Where(log => log.UserUniqueNo == request.UserCode ) + .WhereIF(request.DateTimePeriod.HasValue(), log => log.RaiseDateTime >= request.DateTimePeriod.Start + && log.RaiseDateTime <= request.DateTimePeriod.End) + .OrderBy(log => log.RaiseDateTime) + .Select((log, d) => new WorkGridScheduleAttendancePageResponse + { + Id = log.Id, + OriginUserUniqueNo = log.UserUniqueNo, + DeviceUniqueNo = log.DeviceUniqueNo, + RaiseDateTime = log.RaiseDateTime, + CreateTime = log.CreateTime, + SerialNo = log.SerialNo, + DeployPlace = d.DeployPlace, + Sync = log.Sync, + Status = log.Status + }) + .ToPageListAsync(request); + } + + /// + public async Task ManuallyUploadAsync(List logIds) + { + var requests = await _dbContext.Queryable() + .LeftJoin((x, device) => x.DeviceUniqueNo == device.UniqueNo) + .Where(x => logIds.Contains(x.Id)) + .Where(x => x.NeedUpload && x.Sync == false) + .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() + .SetColumns(x => x.Sync == true) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => ids.Contains(x.Id)) + .ExecuteCommandAsync(); + } + } + } + } } \ No newline at end of file From 3cec23077393fac7f89adfb56dc30a11f0068ce8 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 18 Feb 2025 16:10:38 +0800 Subject: [PATCH 05/25] =?UTF-8?q?feat=20=E5=B7=A5=E4=BD=9C=E7=BD=91?= =?UTF-8?q?=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Src/Dlhis.Basic/Organization/Dto/GainfoDto.cs | 2 - .../Controllers/WorkGridsController.cs | 154 ++++++++++++++++++ .../Request/WorkGridChangeRequest.cs | 12 ++ .../WorkGrids/Request/WorkGridPageRequest.cs | 8 + .../WorkGrids/Request/WorkGridSaveRequest.cs | 22 +++ .../Request/WorkGridScheduleSaveRequest.cs | 14 ++ .../Request/WorkGridTimePeriodRequest.cs | 7 + .../Request/WorkGridTimePeriodSaveRequest.cs | 36 ++++ .../Request/WorkGridUserAssignRequest.cs | 14 ++ .../Request/WorkGridUserRemoveRequest.cs | 14 ++ .../Response/WorkGridPageResponse.cs | 31 ++++ .../Response/WorkGridScheduleResponse.cs | 12 ++ .../WorkGridScheduleSummaryResponse.cs | 16 ++ .../WorkGridTimePeriodPageResponse.cs | 72 ++++++++ .../Response/WorkGridUserPageResponse.cs | 57 +++++++ .../Services/IWorkGridScheduleService.cs | 16 ++ .../WorkGrids/Services/IWorkGridService.cs | 52 ++++++ .../Services/IWorkGridTimePeriodService.cs | 25 +++ .../Implements/WorkGridScheduleService.cs | 81 +++++++++ .../Services/Implements/WorkGridService.cs | 154 ++++++++++++++++++ .../Implements/WorkGridTimePeriodService.cs | 93 +++++++++++ .../Basic/Entity/WorkGridEntity.cs | 37 +++++ .../Basic/Entity/WorkGridScheduleEntity.cs | 42 +++++ .../Basic/Entity/WorkGridTimePeriodEntity.cs | 44 +++++ .../Basic/Entity/WorkGridUserEntity.cs | 35 ++++ .../Basic/Enums/WorkGridTimePeriodEnumType.cs | 22 +++ 26 files changed, 1070 insertions(+), 2 deletions(-) create mode 100644 Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridChangeRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridPageRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridSaveRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleSaveRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridTimePeriodRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridTimePeriodSaveRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridUserAssignRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridUserRemoveRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Response/WorkGridPageResponse.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleResponse.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleSummaryResponse.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Response/WorkGridTimePeriodPageResponse.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Response/WorkGridUserPageResponse.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Services/IWorkGridService.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Services/IWorkGridTimePeriodService.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs create mode 100644 Src/Dlhis.Entity/Basic/Entity/WorkGridEntity.cs create mode 100644 Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs create mode 100644 Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs create mode 100644 Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs create mode 100644 Src/Dlhis.Entity/Basic/Enums/WorkGridTimePeriodEnumType.cs diff --git a/Src/Dlhis.Basic/Organization/Dto/GainfoDto.cs b/Src/Dlhis.Basic/Organization/Dto/GainfoDto.cs index 0b378beb..0cf86880 100644 --- a/Src/Dlhis.Basic/Organization/Dto/GainfoDto.cs +++ b/Src/Dlhis.Basic/Organization/Dto/GainfoDto.cs @@ -21,8 +21,6 @@ public class GainfoDto public class AnalyzePackDto { - - public string UserNo { get; set; } public string UserDepartment { get; set; } diff --git a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs new file mode 100644 index 00000000..4549aca8 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs @@ -0,0 +1,154 @@ +using Dlhis.Basic.WorkGrids.Request; +using Dlhis.Basic.WorkGrids.Response; +using Dlhis.Basic.WorkGrids.Services; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Dlhis.Basic.WorkGrids.Controllers; + +/// +/// 工作网格 +/// +[Authorize] +[Route("api/[controller]")] +[ApiController] +public class WorkGridsController : ControllerBase +{ + private readonly IWorkGridService _workGridService; + private readonly IWorkGridTimePeriodService _workGridTimePeriodService; + private readonly IWorkGridScheduleService _workGridScheduleService; + + public WorkGridsController(IWorkGridService workGridService, + IWorkGridTimePeriodService workGridTimePeriodService, + IWorkGridScheduleService workGridScheduleService) + { + _workGridService = workGridService; + _workGridTimePeriodService = workGridTimePeriodService; + _workGridScheduleService = workGridScheduleService; + } + + /// + /// 保存 + /// + /// + /// + [HttpPost("save")] + [Transactional] + public async Task SaveWorkGridsAsync(List requests) + { + await _workGridService.SaveAsync(requests); + } + + /// + /// /网格分页 + /// + /// + /// + [HttpGet("page")] + public async Task> GetWorkGridPageAsync([FromQuery] WorkGridPageRequest request) + { + return await _workGridService.GetPageAsync(request); + } + + /// + /// 修改网格管理者 + /// + /// + [HttpPost("leader/change")] + public async Task ChangeWorkGridLeaderAsync(WorkGridChangeRequest request) + { + await _workGridService.ChangeAsync(request.From, request.To); + } + + /// + /// 获取我的网格信息 + /// + /// + /// + [HttpGet("info")] + public async Task GetMyWorkGridAsync([FromQuery] WorkGridPageRequest request) + { + return await _workGridService.GetMyWorkGridAsync(request); + } + + /// + /// 保存网格工作时间 + /// + /// + /// + [HttpPost("timePeriod/save")] + public async Task SaveWorkGridTimePeriodAsync(WorkGridTimePeriodSaveRequest request) + { + await _workGridTimePeriodService.SaveAsync(request); + } + + /// + /// /获取网格工作时间分页 + /// + /// + /// + [HttpGet("timePeriod/page")] + public async Task> GetWorkGridTimePeriodPageAsync([FromQuery] WorkGridTimePeriodPageRequest request) + { + return await _workGridTimePeriodService.GetPageAsync(request); + } + + /// + /// 分配人员到网格中 + /// + /// + /// + [HttpPost("user/assign")] + public async Task AssignUsersToWorkGridAsync(WorkGridUserAssignRequest request) + { + await _workGridService.AssignAsync(request); + } + + /// + /// 移除网格的人员 + /// + /// + /// + [HttpPost("user/remove")] + public async Task RemoveUsersFromWorkGridAsync(WorkGridUserRemoveRequest request) + { + await _workGridService.RemoveAsync(request); + } + + /// + /// 保存网格人员排班 + /// + /// + [HttpPost("user/schedule/save")] + public async Task SaveScheduleAsync(WorkGridScheduleSaveRequest request) + { + await _workGridScheduleService.SaveAsync(request); + } + + /// + /// 获取人网格员排班列表 + /// + /// 网格code + /// + /// + [HttpGet("user/schedule/list")] + public async Task> GetListAsync(Guid workGridCode, DateOnly date) + { + return await _workGridScheduleService.GetListAsync(workGridCode, date); + } + + /// + /// 获取网格人员排班详情 + /// + /// 网格 + /// 开始日期 + /// 结束日期 + /// + [HttpGet("user/schedule/summary")] + public async Task> GetListSummaryAsync([FromQuery] Guid workGridCode, [FromQuery] DateOnly start, [FromQuery] DateOnly end) + { + return await _workGridScheduleService.GetListSummaryAsync(workGridCode, start, end); + } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridChangeRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridChangeRequest.cs new file mode 100644 index 00000000..568cd2f1 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridChangeRequest.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridChangeRequest +{ + [Required] + public string From { get; set; } + + [Required] + public string To { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridPageRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridPageRequest.cs new file mode 100644 index 00000000..936ee923 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridPageRequest.cs @@ -0,0 +1,8 @@ +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridPageRequest : PageDto +{ + +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridSaveRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridSaveRequest.cs new file mode 100644 index 00000000..8b5f8029 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridSaveRequest.cs @@ -0,0 +1,22 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridSaveRequest +{ + public long? Id { get; set; } + + [Required(ErrorMessage = "名称不可为空")] + public string Name { get; set; } + + /// + /// 负责人 + /// + [Required(ErrorMessage = "负责人不可为空")] + public string LeaderUserCode { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleSaveRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleSaveRequest.cs new file mode 100644 index 00000000..dcede077 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleSaveRequest.cs @@ -0,0 +1,14 @@ +using Dlhis.Entity.Basic.Enums; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridScheduleSaveRequest +{ + public Guid WorkGridCode { get; set; } + + public DateOnly Date { get; set; } + + public WorkGridTimePeriodEnumType PeriodType { get; set; } + + public List UserCodes { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridTimePeriodRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridTimePeriodRequest.cs new file mode 100644 index 00000000..0103492f --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridTimePeriodRequest.cs @@ -0,0 +1,7 @@ +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridTimePeriodPageRequest : PageDto +{ +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridTimePeriodSaveRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridTimePeriodSaveRequest.cs new file mode 100644 index 00000000..85bcc07a --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridTimePeriodSaveRequest.cs @@ -0,0 +1,36 @@ +using System.ComponentModel.DataAnnotations; +using Dlhis.Entity.Basic.Enums; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridTimePeriodSaveRequest +{ + public long? Id { get; set; } + + /// + /// 班次, eg: 禁止编辑 + /// + public WorkGridTimePeriodEnumType Type { get; set; } + + /// + /// 前(min) + /// + [Range(1, int.MaxValue)] + public int Before { get; set; } + + /// + /// 后(min) + /// + [Range(1, int.MaxValue)] + public int After { get; set; } + + /// + /// 开始时间 + /// + public TimeOnly Start { get; set; } + + /// + /// 结束时间 + /// + public TimeOnly End { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridUserAssignRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridUserAssignRequest.cs new file mode 100644 index 00000000..c13e6e7c --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridUserAssignRequest.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridUserAssignRequest +{ + public Guid? WorkGridCode { get; set; } + + /// + /// 人员 + /// + [MinLength(1, ErrorMessage = "请选择人员")] + public List UserCodes { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridUserRemoveRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridUserRemoveRequest.cs new file mode 100644 index 00000000..e5358bc5 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridUserRemoveRequest.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridUserRemoveRequest +{ + public Guid? WorkGridCode { get; set; } + + /// + /// 人员 + /// + [MinLength(1, ErrorMessage = "请选择人员")] + public List UserCodes { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridPageResponse.cs b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridPageResponse.cs new file mode 100644 index 00000000..3494011a --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridPageResponse.cs @@ -0,0 +1,31 @@ +namespace Dlhis.Basic.WorkGrids.Response; + +public class WorkGridPageResponse +{ + public long Id { get; set; } + + /// + /// 网格code + /// + public Guid Code { get; set; } + + /// + /// 网格名称 + /// + public string Name { get; set; } + + /// + /// 负责人工号 + /// + public string LeaderUserCode { get; set; } + + /// + /// 负责人姓名 + /// + public string UserName { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleResponse.cs b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleResponse.cs new file mode 100644 index 00000000..eddfad3e --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleResponse.cs @@ -0,0 +1,12 @@ +using Dlhis.Entity.Basic.Enums; + +namespace Dlhis.Basic.WorkGrids.Response; + +public class WorkGridScheduleResponse +{ + public DateOnly Date { get; set; } + + public WorkGridTimePeriodEnumType PeriodType { get; set; } + + public string UserCode { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleSummaryResponse.cs b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleSummaryResponse.cs new file mode 100644 index 00000000..b55d9606 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleSummaryResponse.cs @@ -0,0 +1,16 @@ +using Dlhis.Entity.Basic.Enums; + +namespace Dlhis.Basic.WorkGrids.Response; + +public class WorkGridScheduleSummaryResponse +{ + public DateOnly Date { get; set; } + public IEnumerable Details { get; set; } +} + +public class WorkGridScheduleSummaryDetailResponse +{ + public WorkGridTimePeriodEnumType PeriodType { get; set; } + + public int Count { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridTimePeriodPageResponse.cs b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridTimePeriodPageResponse.cs new file mode 100644 index 00000000..03c23873 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridTimePeriodPageResponse.cs @@ -0,0 +1,72 @@ +using Dlhis.Entity.Basic.Enums; +using Kurisu.AspNetCore.Utils.Extensions; + +namespace Dlhis.Basic.WorkGrids.Response; + +public class WorkGridTimePeriodPageResponse +{ + public long Id { get; set; } + + /// + /// 班次 + /// + public WorkGridTimePeriodEnumType Type { get; set; } + + /// + /// 班次描述 + /// + public string TypeDesc => Type.GetDescription(); + + /// + /// 前 + /// + public int Before { get; set; } + + /// + /// 后 + /// + public int After { get; set; } + + /// + /// 开始时间 + /// + public TimeOnly Start { get; set; } + + /// + /// 结束时间 + /// + public TimeOnly End { get; set; } + + /// + /// 配置描述 + /// + public string Description + { + get { return Type.GetDescription() + "打卡时间从" + Start + "到" + End + "\r\n" + "上班允许提前" + GetTimeDescription(Before) + "\r\n" + "下班允许延迟" + GetTimeDescription(After); } + } + + + private string GetTimeDescription(int minutes) + { + string d; + + if (minutes >= 60) + { + var remaining = minutes % 60; + + d = $"{minutes / 60}小时"; + + if (remaining > 0) + { + d += $"{remaining}分钟"; + } + } + else + { + d = $"{minutes}分钟"; + } + + + return d; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridUserPageResponse.cs b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridUserPageResponse.cs new file mode 100644 index 00000000..bd601ea0 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridUserPageResponse.cs @@ -0,0 +1,57 @@ +namespace Dlhis.Basic.WorkGrids.Response; + +public class WorkGridUserPageResponse +{ + public long Id { get; set; } + + /// + /// 网格code + /// + public Guid Code { get; set; } + + /// + /// 网格名称 + /// + public string Name { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + + /// + /// 员工明细 + /// + public List UserInfos { get; set; } +} + +public class WorkGridUserPageDetailResponse +{ + /// + /// 人员工号 + /// + public string Code { get; set; } + + /// + /// 人员姓名 + /// + public string Name { get; set; } + + // /// + // /// 排班值 + // /// + // public WorkGridTimePeriodEnumType? ScheduleType { get; set; } + // + // /// + // /// 排班描述 + // /// + // public string ScheduleTypeDesc + // { + // get + // { + // return !ScheduleType.HasValue + // ? "未排班" + // : ScheduleType.Value.GetDescription(); + // } + // } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs new file mode 100644 index 00000000..2b6783d9 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs @@ -0,0 +1,16 @@ +using Dlhis.Basic.WorkGrids.Request; +using Dlhis.Basic.WorkGrids.Response; + +namespace Dlhis.Basic.WorkGrids.Services; + +/// +/// 网格排班 +/// +public interface IWorkGridScheduleService : IScopeDependency +{ + Task SaveAsync(WorkGridScheduleSaveRequest request); + + Task> GetListAsync(Guid workGridCode, DateOnly date); + + Task> GetListSummaryAsync(Guid workGridCode, DateOnly start, DateOnly end); +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridService.cs b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridService.cs new file mode 100644 index 00000000..0270987f --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridService.cs @@ -0,0 +1,52 @@ +using Dlhis.Basic.WorkGrids.Request; +using Dlhis.Basic.WorkGrids.Response; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Basic.WorkGrids.Services; + +/// +/// 工作网格 +/// +public interface IWorkGridService : IScopeDependency +{ + /// + /// 保存 + /// + /// + /// + Task SaveAsync(List requests); + + /// + /// /网格分页 + /// + /// + /// + Task> GetPageAsync(WorkGridPageRequest request); + + /// + /// 修改管理者 + /// + /// + Task ChangeAsync(string from, string to); + + /// + /// 获取 + /// + /// + /// + Task GetMyWorkGridAsync(WorkGridPageRequest request); + + /// + /// 分配人员 + /// + /// + /// + Task AssignAsync(WorkGridUserAssignRequest request); + + /// + /// 移除人员 + /// + /// + /// + Task RemoveAsync(WorkGridUserRemoveRequest request); +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridTimePeriodService.cs b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridTimePeriodService.cs new file mode 100644 index 00000000..f2f848da --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridTimePeriodService.cs @@ -0,0 +1,25 @@ +using Dlhis.Basic.WorkGrids.Request; +using Dlhis.Basic.WorkGrids.Response; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Basic.WorkGrids.Services; + +/// +/// 工作网格班次时段配置 +/// +public interface IWorkGridTimePeriodService : IScopeDependency +{ + /// + /// 保存 + /// + /// + /// + Task SaveAsync(WorkGridTimePeriodSaveRequest request); + + /// + /// 获取分页 + /// + /// + /// + Task> GetPageAsync(WorkGridTimePeriodPageRequest request); +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs new file mode 100644 index 00000000..1e2f25c7 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs @@ -0,0 +1,81 @@ +using Dlhis.Basic.WorkGrids.Request; +using Dlhis.Basic.WorkGrids.Response; +using Dlhis.Entity.Basic.Entity; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.Utils.Extensions; + +namespace Dlhis.Basic.WorkGrids.Services.Implements; + +public class WorkGridScheduleService : IWorkGridScheduleService +{ + private readonly IDbContext _dbContext; + + public WorkGridScheduleService(IDbContext dbContext) + { + _dbContext = dbContext; + } + + public async Task SaveAsync(WorkGridScheduleSaveRequest request) + { + var exists = await _dbContext.Queryable() + .Where(x => x.Date == request.Date) + .Where(x => x.PeriodType != request.PeriodType) + .Where(x => request.UserCodes.Contains(x.UserCode)) + .AnyAsync(); + + exists.ThrowIfTrue($"存在已经分配的人员"); + + var data = await _dbContext.Queryable() + .Where(x => x.WorkGridCode == request.WorkGridCode) + .Where(x => x.Date == request.Date) + .Where(x => x.PeriodType == request.PeriodType) + .ToListAsync(); + + await _dbContext.DeleteReallyAsync(data); + + var toInserts = request.UserCodes.Select(x => new WorkGridScheduleEntity + { + WorkGridCode = request.WorkGridCode, + Date = request.Date, + PeriodType = request.PeriodType, + UserCode = x + }).ToList(); + + await _dbContext.InsertAsync(toInserts); + } + + /// + public async Task> GetListAsync(Guid workGridCode, DateOnly date) + { + return await _dbContext.Queryable() + .Where(x => x.WorkGridCode == workGridCode && x.Date == date) + .Select(x => new WorkGridScheduleResponse + { + Date = x.Date, + PeriodType = x.PeriodType, + UserCode = x.UserCode + }) + .ToListAsync(); + } + + /// + public async Task> GetListSummaryAsync(Guid workGridCode, DateOnly start, DateOnly end) + { + var workGridSchedules = await _dbContext.Queryable() + .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() + }) + }; + }); + } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs new file mode 100644 index 00000000..f087dd94 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs @@ -0,0 +1,154 @@ +using Dlhis.Basic.WorkGrids.Request; +using Dlhis.Basic.WorkGrids.Response; +using Dlhis.Entity.Basic.Entity; +using Kurisu.AspNetCore.Authentication.Abstractions; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.Utils.Extensions; +using Mapster; +using SqlSugar; + +namespace Dlhis.Basic.WorkGrids.Services.Implements; + +public class WorkGridService : IWorkGridService +{ + private readonly IDbContext _dbContext; + private readonly ICurrentUser _currentUser; + + public WorkGridService(IDbContext dbContext, ICurrentUser currentUser) + { + _dbContext = dbContext; + _currentUser = currentUser; + } + + /// + public async Task SaveAsync(List requests) + { + foreach (var request in requests) + { + var exists = await _dbContext.Queryable() + .Where(x => x.LeaderUserCode == request.LeaderUserCode) + .WhereIF(request.Id.HasValue, x => x.Id != request.Id) + .AnyAsync(); + + exists.ThrowIfTrue($"{request.LeaderUserCode}已存在管理的网格"); + + if (!request.Id.HasValue) + { + var entity = request.Adapt(); + entity.Code = Guid.NewGuid(); + + await _dbContext.InsertAsync(entity); + } + else + { + var entity = await _dbContext.Queryable().Where(x => x.Id == request.Id).SingleAsync(); + request.Adapt(entity); + + await _dbContext.UpdateAsync(entity); + } + } + } + + /// + public async Task> GetPageAsync(WorkGridPageRequest request) + { + return await _dbContext.Queryable() + .LeftJoin((x, ga) => x.LeaderUserCode == ga.Code) + .Select((x, ga) => new WorkGridPageResponse + { + Id = x.Id, + Code = x.Code, + Name = x.Name, + LeaderUserCode = x.LeaderUserCode, + UserName = ga.Name, + Remark = x.Remark + }) + .ToPageListAsync(request); + } + + /// + public async Task ChangeAsync(string from, string to) + { + var workGrid = await _dbContext.Queryable().Where(x => x.LeaderUserCode == from).SingleAsync(); + workGrid.ThrowIfNull("网格不存在"); + + var gainfo = await _dbContext.Queryable().Where(x => x.Code == to).SingleAsync(); + gainfo.ThrowIfNull($"{to}人员不存在"); + + workGrid.LeaderUserCode = to; + await _dbContext.UpdateAsync(workGrid); + } + + /// + public async Task GetMyWorkGridAsync(WorkGridPageRequest request) + { + var currentUserCode = _currentUser.GetUserClaim("jinko-code"); + var myWorkGrid = await _dbContext.Queryable() + .Where(x => x.LeaderUserCode == currentUserCode) + .Select(x => new WorkGridUserPageResponse + { + Id = x.Id, + Code = x.Code, + Name = x.Name, + Remark = x.Remark, + UserInfos = SqlFunc.Subqueryable() + .LeftJoin((p, ga) => p.UserCode == ga.Code) + .Where((p, ga) => p.WorkGridCode == x.Code) + .ToList((p, ga) => new WorkGridUserPageDetailResponse + { + Code = p.UserCode, + Name = ga.Name + }) + }) + .SingleAsync(); + + return myWorkGrid; + } + + /// + public async Task AssignAsync(WorkGridUserAssignRequest request) + { + var currentFactory = _currentUser.GetStringTenantId(); + var currentUserCode = _currentUser.GetUserClaim("jinko-code"); + + var myWorkGrid = await _dbContext.Queryable().Where(x => x.LeaderUserCode == currentUserCode).SingleAsync(); + myWorkGrid.ThrowIfNull("工作网格尚未配置,请联系管理员"); + + //检查配置的人员 + var count = await _dbContext.Queryable() + .Where(x => x.Factory == currentFactory) + .Where(x => request.UserCodes.Contains(x.Code)) + .CountAsync(); + + (count != request.UserCodes.Count).ThrowIfTrue("存在非当前厂区人员,请检查"); + + var existsAssigned = await _dbContext.Queryable().Where(x => x.WorkGridCode == myWorkGrid.Code) + .Where(x => request.UserCodes.Contains(x.UserCode)) + .AnyAsync(); + existsAssigned.ThrowIfTrue("存在已经分配人员,请勿重复分配"); + + var dataToInserts = request.UserCodes.Select(x => new WorkGridUserEntity + { + WorkGridCode = myWorkGrid.Code, + UserCode = x + }).ToList(); + + await _dbContext.InsertAsync(dataToInserts); + } + + /// + public async Task RemoveAsync(WorkGridUserRemoveRequest request) + { + var currentUserCode = _currentUser.GetUserClaim("jinko-code"); + var myWorkGrid = await _dbContext.Queryable().Where(x => x.LeaderUserCode == currentUserCode).SingleAsync(); + myWorkGrid.ThrowIfNull("工作网格尚未配置,请联系管理员"); + + var workGridUsers = await _dbContext.Queryable().Where(x => x.WorkGridCode == myWorkGrid.Code) + .Where(x => request.UserCodes.Contains(x.UserCode)) + .ToListAsync(); + + await _dbContext.DeleteReallyAsync(workGridUsers); + } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs new file mode 100644 index 00000000..b07b4396 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs @@ -0,0 +1,93 @@ +using Dlhis.Basic.WorkGrids.Request; +using Dlhis.Basic.WorkGrids.Response; +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Basic.Enums; +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 Mapster; + +namespace Dlhis.Basic.WorkGrids.Services.Implements; + +public class WorkGridTimePeriodService : IWorkGridTimePeriodService +{ + private readonly IDbContext _dbContext; + + public WorkGridTimePeriodService(IDbContext dbContext) + { + _dbContext = dbContext; + } + + /// + public async Task SaveAsync(WorkGridTimePeriodSaveRequest request) + { + //await CheckDuplicateTimePeriodAsync(request); + + if (!request.Id.HasValue) + { + //判断重复配置 + var existsSameType = await _dbContext.Queryable() + .Where(x => x.Type == request.Type) + .AnyAsync(); + + existsSameType.ThrowIfTrue($"已存在{request.Type}配置"); + + var data = request.Adapt(); + data.Type = request.Type; + await _dbContext.InsertAsync(data); + } + else + { + var entity = await _dbContext.Queryable().Where(x => x.Id == request.Id).SingleAsync(); + request.Adapt(entity); + + await _dbContext.UpdateAsync(entity); + } + } + + /// + public async Task> GetPageAsync(WorkGridTimePeriodPageRequest request) + { + return await _dbContext.Queryable() + .Select() + .ToPageListAsync(request); + } + + //************************************************************************************************************************************************* + + /// + /// 根据类型获取配置 + /// + /// + /// + private async Task GetSettingAsync(WorkGridTimePeriodEnumType timePeriodType) + { + return await _dbContext.Queryable() + .Where(x => x.Type == timePeriodType) + .SingleAsync(); + } + + /// + /// 检查时间段重合检查 + /// + /// + /// + private async Task CheckDuplicateTimePeriodAsync(WorkGridTimePeriodSaveRequest request) + { + var periods = await _dbContext.Queryable() + .Where(x => x.Type != request.Type) + .Select(x => new TimePeriod + { + Start = x.Start, + End = x.End + }) + .ToListAsync(); + + foreach (var period in periods) + { + period.IsDuplicate(request.Adapt()).ThrowIfTrue($"存在时间段重合[{period.Start}-{period.End}]"); + } + } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Basic/Entity/WorkGridEntity.cs b/Src/Dlhis.Entity/Basic/Entity/WorkGridEntity.cs new file mode 100644 index 00000000..f616edcf --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Entity/WorkGridEntity.cs @@ -0,0 +1,37 @@ +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using Mapster; +using SqlSugar; + +namespace Dlhis.Entity.Basic.Entity; + +/// +/// 工作网格 +/// +[SugarTable(TableName = "WorkGrid")] +public class WorkGridEntity : SugarBaseEntity +{ + /// + /// 网格code + /// + [AdaptIgnore(MemberSide.Destination)] + [SugarColumn(IsNullable = false, ColumnDescription = "网格code")] + public Guid Code { get; set; } + + /// + /// 网格名称 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "网格名称")] + public string Name { get; set; } + + /// + /// 负责人工号 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "负责人工号", UniqueGroupNameList = new[] { "idx_WorkGrid_LeaderUserCode" })] + public string LeaderUserCode { get; set; } + + /// + /// 备注 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "备注")] + public string Remark { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs b/Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs new file mode 100644 index 00000000..22e58f7d --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs @@ -0,0 +1,42 @@ +using Dlhis.Entity.Basic.Enums; +using Kurisu.AspNetCore.DataAccess.Entity; +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using SqlSugar; +using SqlSugar.DbConvert; + +namespace Dlhis.Entity.Basic.Entity; + +/// +/// +/// +[SugarTable(TableName = "WorkGridSchedule")] +public class WorkGridScheduleEntity : SugarBaseEntity, ITenantId +{ + /// + /// 网格code + /// + [SugarColumn(IsNullable = false, ColumnDescription = "网格code")] + public Guid WorkGridCode { get; set; } + + /// + /// 排班日期 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "排班日期")] + public DateOnly Date { get; set; } + + /// + /// 排班类型 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "排班类型", SqlParameterDbType = typeof(EnumToStringConvert))] + public WorkGridTimePeriodEnumType PeriodType { get; set; } + + /// + /// 工号 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "工号")] + public string UserCode { get; set; } + + + /// + public string TenantId { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs b/Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs new file mode 100644 index 00000000..1d842130 --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs @@ -0,0 +1,44 @@ +using Dlhis.Entity.Basic.Enums; +using Kurisu.AspNetCore.DataAccess.Entity; +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using Mapster; +using SqlSugar; + +namespace Dlhis.Entity.Basic.Entity; + +/// +/// 工作网格 +/// +[SugarTable(TableName = "WorkGridTimePeriod")] +public class WorkGridTimePeriodEntity : SugarBaseEntity, ITenantId +{ + /// + /// 班次 + /// + [AdaptIgnore(MemberSide.Destination)] + public WorkGridTimePeriodEnumType Type { get; set; } + + /// + /// 前 + /// + public int Before { get; set; } + + /// + /// 后 + /// + public int After { get; set; } + + /// + /// 开始时间 + /// + public TimeOnly Start { get; set; } + + /// + /// 结束时间 + /// + public TimeOnly End { get; set; } + + + [SugarColumn(UniqueGroupNameList = new[] { "idx_workGridTimePeriod_type_tenantId" })] + public string TenantId { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs b/Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs new file mode 100644 index 00000000..7685a578 --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs @@ -0,0 +1,35 @@ +using Dlhis.Entity.Basic.Enums; +using Kurisu.AspNetCore.DataAccess.Entity; +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using SqlSugar; +using SqlSugar.DbConvert; + +namespace Dlhis.Entity.Basic.Entity; + +/// +/// 网格人员 +/// +[SugarTable(TableName = "WorkGridUsers")] +public class WorkGridUserEntity : SugarBaseEntity, ITenantId +{ + /// + /// 网格code + /// + [SugarColumn(IsNullable = false, ColumnDescription = "网格code")] + public Guid WorkGridCode { get; set; } + + /// + /// 网格人员 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "网格人员")] + public string UserCode { get; set; } + + /// + /// 排班类型 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "排班类型", SqlParameterDbType = typeof(EnumToStringConvert))] + public WorkGridTimePeriodEnumType? ScheduleType { get; set; } + + /// + public string TenantId { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Basic/Enums/WorkGridTimePeriodEnumType.cs b/Src/Dlhis.Entity/Basic/Enums/WorkGridTimePeriodEnumType.cs new file mode 100644 index 00000000..e666372a --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Enums/WorkGridTimePeriodEnumType.cs @@ -0,0 +1,22 @@ +using System.ComponentModel; + +namespace Dlhis.Entity.Basic.Enums; + +/// +/// 网格班次 +/// +[Description("网格班次")] +public enum WorkGridTimePeriodEnumType +{ + /// + /// 白班 + /// + [Description("白班")] + Day = 1, + + /// + /// 晚班 + /// + [Description("晚班")] + Night = 2, +} \ No newline at end of file From f7b5f7169dd3771b9bc782ec5188a8c34c55a97d Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 11 Feb 2025 16:33:21 +0800 Subject: [PATCH 06/25] feat tickets --- Dlhis.Jinko.Face.sln | 13 ++++ .../Services/Implements/DishesService.cs | 5 +- Src/Dlhis.Basic/Dlhis.Basic.csproj | 1 + .../Implements/GainfoQrCodeService.cs | 6 +- .../Services/Implements/GainfoService.cs | 3 +- .../Implements/IdentityUserSyncService.cs | 3 +- .../Dlhis.Canteen.Api.csproj | 13 ++++ Src/Dlhis.Canteen.Api/ITicketApi.cs | 16 +++++ Src/Dlhis.Canteen/Dlhis.Canteen.csproj | 1 + .../Implements/EMealVoucherService.cs | 5 +- .../Implements/MealSupplementRecordService.cs | 3 +- .../Services/Implements/BalanceService.cs | 3 +- .../Order/Services/Implements/OrderService.cs | 21 ++++-- .../Services/Implements/WalletService.cs | 3 +- .../Tickets/Controllers/TicketsController.cs | 50 ++++++++++++++ .../Tickets/Request/TicketPageRequest.cs | 19 ++++++ .../Tickets/Response/TicketPageResponse.cs | 41 ++++++++++++ .../Services/IBirthdayTicketService.cs | 6 ++ .../Tickets/Services/ITicketService.cs | 24 +++++++ .../Implements/BirthdayTicketService.cs | 65 +++++++++++++++++++ .../Services/Implements/TicketService.cs | 32 +++++++++ Src/Dlhis.Constants/Dlhis.Constants.csproj | 9 +++ Src/Dlhis.Constants/QrCodeConstants.cs | 19 ++++++ Src/Dlhis.Constants/TickConstants.cs | 6 ++ Src/Dlhis.Constants/UserClaimConstants.cs | 9 +++ .../Canteen/Entities/TicketEntity.cs | 52 +++++++++++++++ .../Canteen/Enums/TicketEnumType.cs | 16 +++++ .../Implements/DeviceUploadLogService.cs | 5 +- .../Dlhis.ScheduledTask.csproj | 3 + Src/Dlhis.ScheduledTask/Dockerfile | 13 +++- .../Jobs/CreateBirthdayTicketJob.cs | 22 +++++++ .../appsettings.Development.json | 19 +++--- Src/Dlhis.ScheduledTask/appsettings.json | 3 +- 33 files changed, 479 insertions(+), 30 deletions(-) create mode 100644 Src/Dlhis.Canteen.Api/Dlhis.Canteen.Api.csproj create mode 100644 Src/Dlhis.Canteen.Api/ITicketApi.cs create mode 100644 Src/Dlhis.Canteen/Tickets/Controllers/TicketsController.cs create mode 100644 Src/Dlhis.Canteen/Tickets/Request/TicketPageRequest.cs create mode 100644 Src/Dlhis.Canteen/Tickets/Response/TicketPageResponse.cs create mode 100644 Src/Dlhis.Canteen/Tickets/Services/IBirthdayTicketService.cs create mode 100644 Src/Dlhis.Canteen/Tickets/Services/ITicketService.cs create mode 100644 Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs create mode 100644 Src/Dlhis.Canteen/Tickets/Services/Implements/TicketService.cs create mode 100644 Src/Dlhis.Constants/Dlhis.Constants.csproj create mode 100644 Src/Dlhis.Constants/QrCodeConstants.cs create mode 100644 Src/Dlhis.Constants/TickConstants.cs create mode 100644 Src/Dlhis.Constants/UserClaimConstants.cs create mode 100644 Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs create mode 100644 Src/Dlhis.Entity/Canteen/Enums/TicketEnumType.cs create mode 100644 Src/Dlhis.ScheduledTask/Jobs/CreateBirthdayTicketJob.cs diff --git a/Dlhis.Jinko.Face.sln b/Dlhis.Jinko.Face.sln index 8ab23f97..0cf2b39a 100644 --- a/Dlhis.Jinko.Face.sln +++ b/Dlhis.Jinko.Face.sln @@ -47,6 +47,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dlhis.Jip.Api", "Src\Dlhis. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dlhis.Dh.Api", "Src\Dlhis.Dh.Api\Dlhis.Dh.Api.csproj", "{E673CA04-3567-4E03-9A86-994F50291ACC}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dlhis.Constants", "Src\Dlhis.Constants\Dlhis.Constants.csproj", "{F98329D8-F8CA-4794-B1BF-8659112119F7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dlhis.Canteen.Api", "Src\Dlhis.Canteen.Api\Dlhis.Canteen.Api.csproj", "{7934BE46-9409-4D28-8B35-82A0F900DD01}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -117,6 +121,14 @@ Global {E673CA04-3567-4E03-9A86-994F50291ACC}.Debug|Any CPU.Build.0 = Debug|Any CPU {E673CA04-3567-4E03-9A86-994F50291ACC}.Release|Any CPU.ActiveCfg = Release|Any CPU {E673CA04-3567-4E03-9A86-994F50291ACC}.Release|Any CPU.Build.0 = Release|Any CPU + {F98329D8-F8CA-4794-B1BF-8659112119F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F98329D8-F8CA-4794-B1BF-8659112119F7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F98329D8-F8CA-4794-B1BF-8659112119F7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F98329D8-F8CA-4794-B1BF-8659112119F7}.Release|Any CPU.Build.0 = Release|Any CPU + {7934BE46-9409-4D28-8B35-82A0F900DD01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7934BE46-9409-4D28-8B35-82A0F900DD01}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7934BE46-9409-4D28-8B35-82A0F900DD01}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7934BE46-9409-4D28-8B35-82A0F900DD01}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -134,6 +146,7 @@ Global {A501D16E-638F-4156-989C-2BACCC2FAC2B} = {4EBCE46B-CE3A-4A47-9432-82A1854CA58A} {841B7B43-5394-413F-9D68-A07EBDD6D4CD} = {4EBCE46B-CE3A-4A47-9432-82A1854CA58A} {E673CA04-3567-4E03-9A86-994F50291ACC} = {4EBCE46B-CE3A-4A47-9432-82A1854CA58A} + {7934BE46-9409-4D28-8B35-82A0F900DD01} = {3D8A98C1-83C9-4375-AEAB-4F72AFAF365B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7439494A-E2FD-4FEA-8ABF-74AE57A4A5A0} diff --git a/Src/Dlhis.Basic/Dishes/Services/Implements/DishesService.cs b/Src/Dlhis.Basic/Dishes/Services/Implements/DishesService.cs index 17d54967..4e738197 100644 --- a/Src/Dlhis.Basic/Dishes/Services/Implements/DishesService.cs +++ b/Src/Dlhis.Basic/Dishes/Services/Implements/DishesService.cs @@ -1,6 +1,7 @@ using Dlhis.Basic.Dishes.Request; using Dlhis.Basic.Dishes.Response; using Dlhis.Basic.Places.Services; +using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; @@ -45,7 +46,7 @@ public class DishesService : IDishesService .ToPageListAsync(request); } - + public async Task SaveDishesAsync(DishesSaveRequest request) { if (!request.Id.HasValue) @@ -68,7 +69,7 @@ public class DishesService : IDishesService { var subjectId = _currentUser.GetIntSubjectId(); var gainfo = await _dbContext.Queryable().Where(x => x.IdentityUserId == subjectId).FirstAsync(); - var jinkoCode = _currentUser.GetUserClaim("jinko-code") ?? string.Empty; + var jinkoCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode) ?? string.Empty; if (jinkoCode.IsPresent()) { gainfo = await _dbContext.Queryable().Where(x => x.Code == jinkoCode).FirstAsync(); diff --git a/Src/Dlhis.Basic/Dlhis.Basic.csproj b/Src/Dlhis.Basic/Dlhis.Basic.csproj index eb9f5b54..7b161cb8 100644 --- a/Src/Dlhis.Basic/Dlhis.Basic.csproj +++ b/Src/Dlhis.Basic/Dlhis.Basic.csproj @@ -26,6 +26,7 @@ + diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoQrCodeService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoQrCodeService.cs index ab6564d7..fac551b2 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoQrCodeService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoQrCodeService.cs @@ -1,4 +1,5 @@ using System.Text; +using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Kurisu.AspNetCore.Authentication.Abstractions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; @@ -21,7 +22,7 @@ public class GainfoQrCodeService : IGainfoQrCodeService public async Task GetMyQrCodeAsync(bool isNeedRefresh = false) { - var jinkoCode = _currentUser.GetUserClaim("jinko-code"); + var jinkoCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode); if (jinkoCode.IsEmpty()) { return null; @@ -63,11 +64,12 @@ public class GainfoQrCodeService : IGainfoQrCodeService var ts = DateTimeOffset.Now.ToUnixTimeMilliseconds(); var qrCode = string.Concat("consumer", ":", code, ":"); - return "01" + qrCode.ToArray().Select(x => + return QrCodeConstants.User + qrCode.ToArray().Select(x => { var b = Encoding.ASCII.GetBytes(x.ToString()); int i = b[0]; return Convert.ToString(i); + }).Join(string.Empty) + ts; } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs index f6b88f2f..198382e6 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs @@ -2,6 +2,7 @@ using Dlhis.Basic.Device.Services; using Dlhis.Basic.Organization.Request; using Dlhis.Basic.Organization.Response; +using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Basic.Enums; using Dlhis.Entity.Device.Entities; @@ -195,7 +196,7 @@ public class GainfoService : IGainfoService public async Task CurrentUserInfoAsync() { - var code = _currentUser.GetUserClaim("jinko-code"); + var code = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode); if (code.IsEmpty()) { _logger.LogWarning("工号为空尝试获取人员信息"); diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/IdentityUserSyncService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/IdentityUserSyncService.cs index 5bde9773..a68e296d 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/IdentityUserSyncService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/IdentityUserSyncService.cs @@ -1,3 +1,4 @@ +using Dlhis.Constants; using Dlhis.Entity.Sys.Entities; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using Kurisu.AspNetCore.Utils.Extensions; @@ -41,7 +42,7 @@ public class IdentityUserSyncService : IIdentityUserSyncService var id = (int)await _identityDbContext.InsertReturnIdentityAsync(user); user.Id = id; - await AddUserClaim(_identityDbContext, id, "jinko-code", userName); + await AddUserClaim(_identityDbContext, id, UserClaimConstants.JinkoCode, userName); await AddUserClaim(_identityDbContext, id, "name", name); } diff --git a/Src/Dlhis.Canteen.Api/Dlhis.Canteen.Api.csproj b/Src/Dlhis.Canteen.Api/Dlhis.Canteen.Api.csproj new file mode 100644 index 00000000..dba64aca --- /dev/null +++ b/Src/Dlhis.Canteen.Api/Dlhis.Canteen.Api.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + disable + + + + + + + diff --git a/Src/Dlhis.Canteen.Api/ITicketApi.cs b/Src/Dlhis.Canteen.Api/ITicketApi.cs new file mode 100644 index 00000000..149b9826 --- /dev/null +++ b/Src/Dlhis.Canteen.Api/ITicketApi.cs @@ -0,0 +1,16 @@ +using Kurisu.RemoteCall.Attributes; + +namespace Dlhis.Canteen.Api; + +[RequestResultHandler] +[EnableRemoteClient(Name = "canteen-service", BaseUrl = "${InternalRequest:CanteenRequestUrl}")] +public interface ITicketApi +{ + /// + /// 创建券 + /// + /// + /// + [Post("/api/tickets/{type}/create")] + Task CreateAsync(string type); +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Dlhis.Canteen.csproj b/Src/Dlhis.Canteen/Dlhis.Canteen.csproj index f893a588..b3030c28 100644 --- a/Src/Dlhis.Canteen/Dlhis.Canteen.csproj +++ b/Src/Dlhis.Canteen/Dlhis.Canteen.csproj @@ -22,6 +22,7 @@ + diff --git a/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs b/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs index 466e2e5d..9bb4b838 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs +++ b/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs @@ -3,6 +3,7 @@ using Dlhis.Canteen.EMealVoucher.Request; using Dlhis.Canteen.EMealVoucher.Response; using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Response; +using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; @@ -65,7 +66,7 @@ public class EMealVoucherService : IEMealVoucherService public async Task> GetMyEMealVoucherPageAsync(EMealVoucherPageRequest request) { - var code = _currentUser.GetUserClaim("jinko-code"); + var code = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode); return await _dbContext.Queryable() .Where(x => x.Code == code) @@ -126,7 +127,7 @@ public class EMealVoucherService : IEMealVoucherService var ts = DateTimeOffset.Now.ToUnixTimeMilliseconds().ToString().Reverse().Join(string.Empty); var originData = string.Concat(eMealVoucher.No, ":", ts, ":", eMealVoucher.Code, ":", eMealVoucherDetail.IdNo); - var qrCode = "02" + originData.ToArray().Select(x => + var qrCode = QrCodeConstants.EMealVoucher + originData.ToArray().Select(x => { var b = Encoding.ASCII.GetBytes(x.ToString()); int i = b[0]; diff --git a/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs b/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs index 0e2094cf..79f03e25 100644 --- a/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs +++ b/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs @@ -1,5 +1,6 @@ using Dlhis.Canteen.MealSupplementRecord.Request; using Dlhis.Canteen.MealSupplementRecord.Response; +using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; @@ -93,7 +94,7 @@ public class MealSupplementRecordService : IMealSupplementRecordService public async Task GetMyMealSupplementRecords(MealSupplementRecordMyRequest request) { - var code = _currentUser.GetUserClaim("jinko-code") ?? string.Empty; + var code = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode) ?? string.Empty; var data = await _dbContext.Queryable() .Where(x => x.CostDateTime >= request.SearchDateTimePeriod.Start && x.CostDateTime <= request.SearchDateTimePeriod.End) diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs index 8929aed6..1e9457e5 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs @@ -3,6 +3,7 @@ using Dlhis.Canteen.Order.Repository; using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Response; using Dlhis.Canteen.Setting.Services; +using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; @@ -332,7 +333,7 @@ public class BalanceService : IBalanceService public async Task GetPageByUserAsync(BalanceRecordUserPageRequest request) { - var userCode = _currentUser.GetUserClaim("jinko-code") ?? string.Empty; + var userCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode) ?? string.Empty; var factory = await _dbContext.Queryable().Where(x => x.Code == request.WalletCode).Select(x => x.Factory).FirstAsync(); var factories = await _balanceRepository.GetWalletFactoriesAsync(factory); diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs index 6a849f72..d6284a13 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs @@ -21,6 +21,7 @@ using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using Kurisu.AspNetCore.UnifyResultAndValidation; +using Dlhis.Constants; namespace Dlhis.Canteen.Order.Services.Implements; @@ -88,7 +89,7 @@ public class OrderService : IOrderService { var subjectId = _currentUser.GetIntSubjectId(); var gainfo = await _dbContext.Queryable().Where(x => x.IdentityUserId == subjectId).FirstAsync(); - var jinkoCode = _currentUser.GetUserClaim("jinko-code") ?? string.Empty; + var jinkoCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode) ?? string.Empty; if (jinkoCode.IsPresent()) { gainfo = await _dbContext.Queryable().Where(x => x.Code == jinkoCode).SingleAsync(); @@ -153,12 +154,12 @@ public class OrderService : IOrderService if (request.Source == BalanceRecordSourceEnumType.QrCode) { - if (request.UserUniqueNo.StartsWith("01")) + if (request.UserUniqueNo.StartsWith(QrCodeConstants.User)) { gainfo = await GetUserByQrCodeAsync(request.UserUniqueNo); await CheckPermissionAsync(gainfo.Code, request.DeviceUniqueNo); } - else if (request.UserUniqueNo.StartsWith("02")) + else if (request.UserUniqueNo.StartsWith(QrCodeConstants.EMealVoucher)) { request.Source = BalanceRecordSourceEnumType.EMealVoucher; var eMealVoucherQrCode = await _dbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); @@ -166,6 +167,12 @@ public class OrderService : IOrderService var code = eMealVoucherQrCode.OriginData.Split(':')[2]; gainfo = await _dbContext.Queryable().Where(x => x.Code == code).SingleAsync(); } + else if (request.UserUniqueNo.StartsWith(QrCodeConstants.Birthday)) + { + var ticket = await _dbContext.Queryable().Where(x => x.Type == TicketEnumType.Birthday).Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); + ticket.ThrowIfNull("无法识别"); + gainfo = await _dbContext.Queryable().Where(x => x.Code == ticket.UserCode).SingleAsync(); + } else { throw new UserFriendlyException($"无法识别{request.UserUniqueNo}"); @@ -276,7 +283,9 @@ public class OrderService : IOrderService .Where(x => x.DeviceUniqueNo == request.DeviceUniqueNo && x.BusinessPlaceCode.HasValue) .Select((x, b, bs) => new { - b.Code, bs.ShiftCode, Factory = x.TenantId + b.Code, + bs.ShiftCode, + Factory = x.TenantId }) .SingleAsync(); @@ -615,7 +624,9 @@ public class OrderService : IOrderService .Where(x => x.DeviceUniqueNo == deviceUniqueNo && x.BusinessPlaceCode.HasValue) .Select((x, b, bs) => new { - b.Code, bs.ShiftCode, Factory = x.TenantId + b.Code, + bs.ShiftCode, + Factory = x.TenantId }) .SingleAsync(); diff --git a/Src/Dlhis.Canteen/Setting/Services/Implements/WalletService.cs b/Src/Dlhis.Canteen/Setting/Services/Implements/WalletService.cs index 42f3a8fc..ffe3dd45 100644 --- a/Src/Dlhis.Canteen/Setting/Services/Implements/WalletService.cs +++ b/Src/Dlhis.Canteen/Setting/Services/Implements/WalletService.cs @@ -1,5 +1,6 @@ using Dlhis.Canteen.Order.Repository; using Dlhis.Canteen.Setting.Response; +using Dlhis.Constants; using Dlhis.Entity.Canteen.Entities; using Kurisu.AspNetCore.Authentication.Abstractions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; @@ -37,7 +38,7 @@ public class WalletService : IWalletService /// public async Task GetBalanceAsync(string walletCode) { - var userCode = _currentUser.GetUserClaim("jinko-code"); + var userCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode); if (!await _dbContext.Queryable().Where(x => x.UserCode == userCode).AnyAsync()) { diff --git a/Src/Dlhis.Canteen/Tickets/Controllers/TicketsController.cs b/Src/Dlhis.Canteen/Tickets/Controllers/TicketsController.cs new file mode 100644 index 00000000..9dfb8ae1 --- /dev/null +++ b/Src/Dlhis.Canteen/Tickets/Controllers/TicketsController.cs @@ -0,0 +1,50 @@ +using Dlhis.Canteen.Tickets.Request; +using Dlhis.Canteen.Tickets.Response; +using Dlhis.Canteen.Tickets.Services; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.Utils.Extensions; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Dlhis.Canteen.Tickets.Controllers; + +/// +/// 券 +/// +[Authorize] +[Route("api/[controller]")] +[ApiController] +public class TicketsController : ControllerBase +{ + private readonly INamedResolver _namedResolver; + + public TicketsController(INamedResolver namedResolver) + { + _namedResolver = namedResolver; + } + + /// + /// 获取分页数据(按券类型) + /// + /// + /// + [HttpGet("page")] + public async Task> GetPageAsync(TicketPageRequest request) + { + return await _namedResolver.GetService(request.Type.ToString()).GetPageAsync(request); + } + + /// + /// 创建券 + /// + /// 券类型,需要后端支持 + [AllowAnonymous] + [HttpPost("{type:required}/create")] + public async Task CreateAsync(string type) + { + var srv = _namedResolver.GetService(type); + srv.ThrowIfNull("不支持的券类型"); + + await srv.CreateAsync(); + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Request/TicketPageRequest.cs b/Src/Dlhis.Canteen/Tickets/Request/TicketPageRequest.cs new file mode 100644 index 00000000..02620a43 --- /dev/null +++ b/Src/Dlhis.Canteen/Tickets/Request/TicketPageRequest.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; +using Dlhis.Entity.Canteen.Enums; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Canteen.Tickets.Request; + +public class TicketPageRequest : PageDto +{ + /// + /// 类型 + /// + [EnumDataType(typeof(TicketEnumType))] + public TicketEnumType Type { get; set; } + + /// + /// 工号 + /// + public string UserCode { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Response/TicketPageResponse.cs b/Src/Dlhis.Canteen/Tickets/Response/TicketPageResponse.cs new file mode 100644 index 00000000..b7be7bc6 --- /dev/null +++ b/Src/Dlhis.Canteen/Tickets/Response/TicketPageResponse.cs @@ -0,0 +1,41 @@ +using Dlhis.Entity.Canteen.Enums; + +namespace Dlhis.Canteen.Tickets.Response; + +public class TicketPageResponse +{ + /// + /// 券类型 + /// + public TicketEnumType Type { get; set; } + + /// + /// 工号 + /// + public string UserCode { get; set; } + + /// + /// 用户名称 + /// + public string UserName { get; set; } + + /// + /// 初始余额 + /// + public decimal OriginalAmount { get; set; } + + /// + /// 当前余额 + /// + public decimal Amount { get; set; } + + /// + /// 消费码 + /// + public string QrCode { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Services/IBirthdayTicketService.cs b/Src/Dlhis.Canteen/Tickets/Services/IBirthdayTicketService.cs new file mode 100644 index 00000000..1b67cc3a --- /dev/null +++ b/Src/Dlhis.Canteen/Tickets/Services/IBirthdayTicketService.cs @@ -0,0 +1,6 @@ +namespace Dlhis.Canteen.Tickets.Services; + +public interface IBirthdayTicketService : ITicketService +{ + +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Services/ITicketService.cs b/Src/Dlhis.Canteen/Tickets/Services/ITicketService.cs new file mode 100644 index 00000000..bc8731f2 --- /dev/null +++ b/Src/Dlhis.Canteen/Tickets/Services/ITicketService.cs @@ -0,0 +1,24 @@ +using Dlhis.Canteen.Tickets.Request; +using Dlhis.Canteen.Tickets.Response; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Canteen.Tickets.Services; + +/// +/// 券 +/// +public interface ITicketService : IScopeDependency +{ + /// + /// 分页数据 + /// + /// + /// + Task> GetPageAsync(TicketPageRequest request); + + /// + /// 创建 + /// + /// + Task CreateAsync(); +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs b/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs new file mode 100644 index 00000000..ba75b0e9 --- /dev/null +++ b/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs @@ -0,0 +1,65 @@ +using System.Text; +using Dlhis.Constants; +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Canteen.Entities; +using Dlhis.Entity.Canteen.Enums; +using Kurisu.AspNetCore.DataAccess.Entity; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.Utils.Extensions; +using SqlSugar; + +namespace Dlhis.Canteen.Tickets.Services.Implements; + +[Service(nameof(TicketEnumType.Birthday))] +public class BirthdayTicketService : BaseTicketService, IBirthdayTicketService +{ + /// + public BirthdayTicketService(IDbContext dbContext) : base(dbContext) + { + } + + /// + public override async Task CreateAsync() + { + await DbContext.IgnoreAsync(async () => + { + var today = DateTime.Today; + var userCodes = await DbContext.Queryable() + .Where(x => SqlFunc.DateIsSame(SqlFunc.ToDate(x.Birthday), today, DateType.Day)) + .Select(x => new { x.Code, x.Factory }) + .ToListAsync(); + + const decimal amount = 30; + var todayStr = today.ToString("yyyy-MM-dd"); + foreach (var item in userCodes) + { + var qrCode = GetQrCode(item.Code + todayStr); + if (!await DbContext.Queryable().Where(x => x.Type == TicketEnumType.Birthday && x.UserCode == item.Code && x.QrCode == qrCode).AnyAsync()) + { + await DbContext.InsertAsync(new TicketEntity + { + Type = TicketEnumType.Birthday, + UserCode = item.Code, + OriginalAmount = amount, + Amount = amount, + QrCode = qrCode, + Remark = todayStr + "生日券", + TenantId = item.Factory + }); + } + } + }); + } + + private static string GetQrCode(string data) + { + var qrCode = QrCodeConstants.Birthday + data.ToArray().Select(x => + { + var b = Encoding.ASCII.GetBytes(x.ToString()); + int i = b[0]; + return Convert.ToString(i); + }).Join(string.Empty); + + return qrCode; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Services/Implements/TicketService.cs b/Src/Dlhis.Canteen/Tickets/Services/Implements/TicketService.cs new file mode 100644 index 00000000..8af5da71 --- /dev/null +++ b/Src/Dlhis.Canteen/Tickets/Services/Implements/TicketService.cs @@ -0,0 +1,32 @@ +using Dlhis.Canteen.Tickets.Request; +using Dlhis.Canteen.Tickets.Response; +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Canteen.Entities; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.Utils.Extensions; + +namespace Dlhis.Canteen.Tickets.Services.Implements; + +public abstract class BaseTicketService : ITicketService +{ + protected IDbContext DbContext { get; set; } + + protected BaseTicketService(IDbContext dbContext) + { + DbContext = dbContext; + } + + public async Task> GetPageAsync(TicketPageRequest request) + { + return await DbContext.Queryable() + .LeftJoin((x, ga) => x.UserCode == ga.Code) + .Where(x => x.Type == request.Type) + .WhereIF(request.UserCode.IsPresent(), x => x.UserCode == request.UserCode) + .Select((x, ga) => new TicketPageResponse { UserName = ga.Name }, true) + .ToPageListAsync(request); + } + + public abstract Task CreateAsync(); +} \ No newline at end of file diff --git a/Src/Dlhis.Constants/Dlhis.Constants.csproj b/Src/Dlhis.Constants/Dlhis.Constants.csproj new file mode 100644 index 00000000..132c02c5 --- /dev/null +++ b/Src/Dlhis.Constants/Dlhis.Constants.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/Src/Dlhis.Constants/QrCodeConstants.cs b/Src/Dlhis.Constants/QrCodeConstants.cs new file mode 100644 index 00000000..ed15fccc --- /dev/null +++ b/Src/Dlhis.Constants/QrCodeConstants.cs @@ -0,0 +1,19 @@ +namespace Dlhis.Constants; + +public class QrCodeConstants +{ + /// + /// 个人码 + /// + public const string User = "01"; + + /// + /// 电子餐券 + /// + public const string EMealVoucher = "02"; + + /// + /// 生日券 + /// + public const string Birthday = "03"; +} diff --git a/Src/Dlhis.Constants/TickConstants.cs b/Src/Dlhis.Constants/TickConstants.cs new file mode 100644 index 00000000..b24c0775 --- /dev/null +++ b/Src/Dlhis.Constants/TickConstants.cs @@ -0,0 +1,6 @@ +// namespace Dlhis.Constants; +// +// public class TickConstants +// { +// public const string { get; set; } +// } diff --git a/Src/Dlhis.Constants/UserClaimConstants.cs b/Src/Dlhis.Constants/UserClaimConstants.cs new file mode 100644 index 00000000..635fdf0f --- /dev/null +++ b/Src/Dlhis.Constants/UserClaimConstants.cs @@ -0,0 +1,9 @@ +namespace Dlhis.Constants; + +public class UserClaimConstants +{ + /// + /// 晶科工号 + /// + public const string JinkoCode = "jinko-code"; +} diff --git a/Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs new file mode 100644 index 00000000..d3ca3c05 --- /dev/null +++ b/Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs @@ -0,0 +1,52 @@ +using Dlhis.Entity.Canteen.Enums; +using Kurisu.AspNetCore.DataAccess.Entity; +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using SqlSugar; +using SqlSugar.DbConvert; + +namespace Dlhis.Entity.Canteen.Entities; + +/// +/// 券 +/// +[SugarTable("Tickets", TableDescription = "券")] +public class TicketEntity : SugarBaseEntity, ITenantId +{ + /// + /// 类型 + /// + [SugarColumn(IsNullable = false, ColumnDataType = "varchar(50)", ColumnDescription = "券类型", SqlParameterDbType = typeof(EnumToStringConvert))] + public TicketEnumType Type { get; set; } + + /// + /// 工号 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "工号")] + public string UserCode { get; set; } + + /// + /// 初始余额 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "初始余额")] + public decimal OriginalAmount { get; set; } + + /// + /// 当前余额 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "当前余额")] + public decimal Amount { get; set; } + + /// + /// 消费码 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "消费码")] + public string QrCode { get; set; } + + /// + /// 备注 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "备注")] + public string Remark { get; set; } + + public string TenantId { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Enums/TicketEnumType.cs b/Src/Dlhis.Entity/Canteen/Enums/TicketEnumType.cs new file mode 100644 index 00000000..3df284e2 --- /dev/null +++ b/Src/Dlhis.Entity/Canteen/Enums/TicketEnumType.cs @@ -0,0 +1,16 @@ +using System.ComponentModel; + +namespace Dlhis.Entity.Canteen.Enums; + +/// +/// 券类型 +/// +[Description("券类型")] +public enum TicketEnumType +{ + /// + /// 生日券 + /// + [Description("生日券")] + Birthday = 1 +} \ No newline at end of file diff --git a/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs b/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs index da1be9e3..6336d998 100644 --- a/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs +++ b/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs @@ -1,4 +1,5 @@ -using Dlhis.Entity.Basic.Entity; +using Dlhis.Constants; +using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Basic.Enums; using Dlhis.Entity.Device.Entities; using Dlhis.Entity.Device.Enums; @@ -95,7 +96,7 @@ public class DeviceUploadLogService : IDeviceUploadLogService public async Task> GetMyRecordsAsync(DeviceUploadLogMyRecordRequest request) { - var jinkoCode = _currentUser.GetUserClaim("jinko-code") ?? string.Empty; + var jinkoCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode) ?? string.Empty; return await _dbContext.Queryable() .LeftJoin((log, d) => log.DeviceUniqueNo == d.UniqueNo) diff --git a/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj b/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj index 0376df7c..0429e8ce 100644 --- a/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj +++ b/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj @@ -20,10 +20,13 @@ + + + diff --git a/Src/Dlhis.ScheduledTask/Dockerfile b/Src/Dlhis.ScheduledTask/Dockerfile index babe2308..dadbd4fe 100644 --- a/Src/Dlhis.ScheduledTask/Dockerfile +++ b/Src/Dlhis.ScheduledTask/Dockerfile @@ -1,25 +1,34 @@ -#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. +# 请参阅 https://aka.ms/customizecontainer 以了解如何自定义调试容器,以及 Visual Studio 如何使用此 Dockerfile 生成映像以更快地进行调试。 +# 此阶段用于在快速模式(默认为调试配置)下从 VS 运行时 FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 80 + +# 此阶段用于生成服务项目 FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build ARG BUILD_CONFIGURATION=Release WORKDIR /src COPY ["Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj", "Src/Dlhis.ScheduledTask/"] COPY ["Src/Dlhis.Basic.Api/Dlhis.Basic.Api.csproj", "Src/Dlhis.Basic.Api/"] +COPY ["Src/Dlhis.Canteen.Api/Dlhis.Canteen.Api.csproj", "Src/Dlhis.Canteen.Api/"] +COPY ["Src/Dlhis.Constants/Dlhis.Constants.csproj", "Src/Dlhis.Constants/"] COPY ["Src/Dlhis.Entity/Dlhis.Entity.csproj", "Src/Dlhis.Entity/"] +COPY ["Src/Dlhis.DataPermission.Model/Dlhis.DataPermission.Model.csproj", "Src/Dlhis.DataPermission.Model/"] +COPY ["Src/Dlhis.Jip.Api/Dlhis.Jip.Api.csproj", "Src/Dlhis.Jip.Api/"] COPY ["Src/Dlhis.Sys.Api/Dlhis.Sys.Api.csproj", "Src/Dlhis.Sys.Api/"] -RUN dotnet restore "./Src/Dlhis.ScheduledTask/./Dlhis.ScheduledTask.csproj" +RUN dotnet restore "./Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj" COPY . . WORKDIR "/src/Src/Dlhis.ScheduledTask" RUN dotnet build "./Dlhis.ScheduledTask.csproj" -c $BUILD_CONFIGURATION -o /app/build +# 此阶段用于发布要复制到最终阶段的服务项目 FROM build AS publish ARG BUILD_CONFIGURATION=Release RUN dotnet publish "./Dlhis.ScheduledTask.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false +# 此阶段在生产中使用,或在常规模式下从 VS 运行时使用(在不使用调试配置时为默认值) FROM base AS final WORKDIR /app COPY --from=publish /app/publish . diff --git a/Src/Dlhis.ScheduledTask/Jobs/CreateBirthdayTicketJob.cs b/Src/Dlhis.ScheduledTask/Jobs/CreateBirthdayTicketJob.cs new file mode 100644 index 00000000..75058d75 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/Jobs/CreateBirthdayTicketJob.cs @@ -0,0 +1,22 @@ +using Dlhis.Canteen.Api; +using Dlhis.Entity.Canteen.Enums; +using Dlhis.ScheduledTask.Attributes; + +namespace Dlhis.ScheduledTask.Jobs; + +/// +/// +/// +[RecurringJob(nameof(CreateBirthdayTicketJob), "0 0 1 * * ?", Name = "生日券发放")] +public class CreateBirthdayTicketJob : BaseJob +{ + public CreateBirthdayTicketJob(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + + /// + protected override async Task RunAsync(IServiceProvider serviceProvider) + { + await serviceProvider.GetService().CreateAsync(TicketEnumType.Birthday.ToString()); + } +} \ No newline at end of file diff --git a/Src/Dlhis.ScheduledTask/appsettings.Development.json b/Src/Dlhis.ScheduledTask/appsettings.Development.json index da038ced..143db3b6 100644 --- a/Src/Dlhis.ScheduledTask/appsettings.Development.json +++ b/Src/Dlhis.ScheduledTask/appsettings.Development.json @@ -7,7 +7,8 @@ }, "InternalRequest": { "SysRequestUrl": "http://localhost:5003", - "BasicRequestUrl": "http://localhost:5002" + "BasicRequestUrl": "http://localhost:5002", + "CanteenRequestUrl": "http://localhost:5008" }, "FaceUrlOptions": { "Url": "http://192.168.199.115:5002/api/gainfos/face?token=", @@ -36,18 +37,18 @@ "ClientSecret": "123456" } }, -// "JinkoOptions": { -// "Jip": { -// "BaseUrl": "http://172.16.202.34:8000", -// "Key": "FACE-7409WIBX", -// "Secret": "be0a4b88-cd80-4509-b9b9-865205d0d3d8" -// } -// }, + // "JinkoOptions": { + // "Jip": { + // "BaseUrl": "http://172.16.202.34:8000", + // "Key": "FACE-7409WIBX", + // "Secret": "be0a4b88-cd80-4509-b9b9-865205d0d3d8" + // } + // }, "JinkoOptions": { "Jip": { "BaseUrl": "http://jip.jinkosolar.com", "Key": "FACE-CUOJG9N7", "Secret": "130c2f2d-03a0-4720-8e25-538ffac7a7cb" } - }, + } } diff --git a/Src/Dlhis.ScheduledTask/appsettings.json b/Src/Dlhis.ScheduledTask/appsettings.json index b2bd19b9..d3bba67c 100644 --- a/Src/Dlhis.ScheduledTask/appsettings.json +++ b/Src/Dlhis.ScheduledTask/appsettings.json @@ -7,7 +7,8 @@ }, "InternalRequest": { "SysRequestUrl": "http://sys", - "BasicRequestUrl": "http://basic" + "BasicRequestUrl": "http://basic", + "CanteenRequestUrl": "http://canteen" }, "DataProtectionOptions": { "Enable": true, From a06dcbef61d2aee9cf80d49928f31b30010c8ac8 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Thu, 13 Feb 2025 17:37:47 +0800 Subject: [PATCH 07/25] =?UTF-8?q?feat=20=E4=BC=98=E5=8C=96=E6=B6=88?= =?UTF-8?q?=E8=B4=B9=E8=BF=87=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Order/Dto/OrderCheckResultDto.cs | 31 ++ .../Order/Dto/OrderPreCheckDto.cs | 16 - .../Order/Repository/IOrderRepository.cs | 2 +- .../Repository/Implements/OrderRepository.cs | 2 +- .../ConsumeHandlers/BirthdayConsumeHandler.cs | 110 ++++++ .../ConsumeHandlers/EMealVoucherHandler.cs | 166 +++++++++ .../ConsumeHandlers/OrderCommonHandler.cs | 144 ++++++++ .../Order/Services/IConsumeHandler.cs | 20 ++ .../Order/Services/IOrderCommonHandler.cs | 29 ++ .../Order/Services/Implements/OrderService.cs | 340 ++++-------------- .../Implements/BirthdayTicketService.cs | 4 +- .../Canteen/Entities/TicketEntity.cs | 9 +- .../Enums/BalanceRecordSourceEnumType.cs | 10 +- 13 files changed, 579 insertions(+), 304 deletions(-) create mode 100644 Src/Dlhis.Canteen/Order/Dto/OrderCheckResultDto.cs delete mode 100644 Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs create mode 100644 Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/BirthdayConsumeHandler.cs create mode 100644 Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/EMealVoucherHandler.cs create mode 100644 Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/OrderCommonHandler.cs create mode 100644 Src/Dlhis.Canteen/Order/Services/IConsumeHandler.cs create mode 100644 Src/Dlhis.Canteen/Order/Services/IOrderCommonHandler.cs diff --git a/Src/Dlhis.Canteen/Order/Dto/OrderCheckResultDto.cs b/Src/Dlhis.Canteen/Order/Dto/OrderCheckResultDto.cs new file mode 100644 index 00000000..8d0af378 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Dto/OrderCheckResultDto.cs @@ -0,0 +1,31 @@ +using Dlhis.Entity.Canteen.Enums; + +namespace Dlhis.Canteen.Order.Dto; + +public class OrderCheckResultDto +{ + /// + /// 消费厂区 + /// + public string Factory { get; set; } + + /// + /// 消费日期 + /// + public DateTime CostDate { get; set; } + + /// + /// 消费餐次 + /// + public ShiftEnumType ShiftType { get; set; } + + /// + /// 消费营业点 + /// + public Guid BusinessPlaceCode { get; set; } + + /// + /// 消费餐别 + /// + public Guid BusinessShiftCode { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs b/Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs deleted file mode 100644 index c4f9c9dc..00000000 --- a/Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Dlhis.Entity.Canteen.Enums; - -namespace Dlhis.Canteen.Order.Dto; - -public class OrderPreCheckDto -{ - public string Factory { get; set; } - - public DateTime CostDate { get; set; } - - public ShiftEnumType ShiftType { get; set; } - - public Guid BusinessPlaceCode { get; set; } - - public Guid BusinessShiftCode { get; set; } -} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Repository/IOrderRepository.cs b/Src/Dlhis.Canteen/Order/Repository/IOrderRepository.cs index d9e904c4..f108f713 100644 --- a/Src/Dlhis.Canteen/Order/Repository/IOrderRepository.cs +++ b/Src/Dlhis.Canteen/Order/Repository/IOrderRepository.cs @@ -7,5 +7,5 @@ namespace Dlhis.Canteen.Order.Repository; public interface IOrderRepository : IScopeDependency { - Task CreateDeviceConsumeOrderAsync(OrderPreCheckDto checkData, ConsumeRequest request, GainfoEntity gainfo); + Task CreateDeviceConsumeOrderAsync(OrderCheckResultDto checkData, ConsumeRequest request, GainfoEntity gainfo); } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Repository/Implements/OrderRepository.cs b/Src/Dlhis.Canteen/Order/Repository/Implements/OrderRepository.cs index a9e31997..23402c47 100644 --- a/Src/Dlhis.Canteen/Order/Repository/Implements/OrderRepository.cs +++ b/Src/Dlhis.Canteen/Order/Repository/Implements/OrderRepository.cs @@ -19,7 +19,7 @@ public class OrderRepository : IOrderRepository } /// - public async Task CreateDeviceConsumeOrderAsync(OrderPreCheckDto checkData, ConsumeRequest request, GainfoEntity gainfo) + public async Task CreateDeviceConsumeOrderAsync(OrderCheckResultDto checkData, ConsumeRequest request, GainfoEntity gainfo) { var order = new CanteenOrderEntity { diff --git a/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/BirthdayConsumeHandler.cs b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/BirthdayConsumeHandler.cs new file mode 100644 index 00000000..dafafc7d --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/BirthdayConsumeHandler.cs @@ -0,0 +1,110 @@ +using Dlhis.Canteen.Order.Repository; +using Dlhis.Canteen.Order.Request; +using Dlhis.Canteen.Order.Response; +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Canteen.Entities; +using Dlhis.Entity.Canteen.Enums; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.UnifyResultAndValidation; +using Kurisu.AspNetCore.Utils; +using Kurisu.AspNetCore.Utils.Extensions; +using Mapster; + +namespace Dlhis.Canteen.Order.Services.ConsumeHandlers; + +/// +/// 生日券消费处理 +/// +[Service(nameof(BalanceRecordSourceEnumType.Birthday))] +public class BirthdayConsumeHandler : IConsumeHandler +{ + private readonly IDbContext _dbContext; + private readonly IOrderCommonHandler _orderCommonHandler; + private readonly IOrderRepository _orderRepository; + + public BirthdayConsumeHandler(IDbContext dbContext, + IOrderCommonHandler orderCommonHandler, + IOrderRepository orderRepository) + { + _dbContext = dbContext; + _orderCommonHandler = orderCommonHandler; + _orderRepository = orderRepository; + } + + public async Task> ConsumeAsync(OrderAddRequest request, GainfoEntity gainfo) + { + var msg = string.Empty; + var ticketNo = request.UserUniqueNo; + + var exists = await _dbContext.Queryable() + .Where(x => x.Type == TicketEnumType.Birthday) + .Where(x => x.QrCode == ticketNo) + .AnyAsync(); + + exists.ThrowIfFalse("生日券无效"); + + try + { + var checkData = await _orderCommonHandler.PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime!.Value); + var isSupermarket = await _dbContext.Queryable() + .Where(x => x.Code == checkData.BusinessPlaceCode) + .Select(x => x.Catalog == CanteenBusinessPlaceCatalogEnumType.Supermarket) + .SingleAsync(); + + isSupermarket.ThrowIfFalse("请在超市消费"); + + var order = await _orderRepository.CreateDeviceConsumeOrderAsync(checkData, request.Adapt(), gainfo); + + await _orderCommonHandler.TryConsumeAsync(order.Id, async () => + { + await CommonHelper.RetryAsync(async () => + { + var ticket = await _dbContext.Queryable() + .Where(x => x.Type == TicketEnumType.Birthday) + .Where(x => x.QrCode == ticketNo) + .SingleAsync(); + + //金额+- + ticket.Balance += order.Amount; + (ticket.Balance < 0).ThrowIfTrue("余额不足,无法消费"); + + await _dbContext.Updateable() + .SetColumns(x => x.Balance == ticket.Balance) + .SetColumns(x => x.Version == x.Version + 1) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.QrCode == ticketNo && x.Version == ticket.Version) //必须与查询时的version一致 + .ExecuteCommandThrowVersionAsync(); + + //写入记录 + var balanceRecord = order.Adapt(); + balanceRecord.Remark = $"{ticket.QrCode}(生日券消费)"; + await _dbContext.InsertAsync(balanceRecord); + }, 5); + }); + } + catch (Exception ex) + { + msg = ex.Message; + } + + //获取餐券余额 + var data = await _dbContext.Queryable() + .LeftJoin((x, ga) => x.UserCode == ga.Code) + .Where(x => x.Type == TicketEnumType.Birthday && x.QrCode == ticketNo) + .Select((x, ga) => new OrderResultResponse + { + UserCode = x.UserCode, + UserName = ga.Name, + CurrentBalance = x.Balance + }) + .SingleAsync(); + + return new DefaultApiResult + { + Code = msg.IsPresent() ? ApiStateCode.Error : ApiStateCode.Success, + Data = data, + Msg = msg + }; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/EMealVoucherHandler.cs b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/EMealVoucherHandler.cs new file mode 100644 index 00000000..86140edf --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/EMealVoucherHandler.cs @@ -0,0 +1,166 @@ +using Dlhis.Canteen.Order.Repository; +using Dlhis.Canteen.Order.Request; +using Dlhis.Canteen.Order.Response; +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Canteen.Entities; +using Dlhis.Entity.Canteen.Enums; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.UnifyResultAndValidation; +using Kurisu.AspNetCore.Utils; +using Kurisu.AspNetCore.Utils.Extensions; +using Mapster; + +namespace Dlhis.Canteen.Order.Services.ConsumeHandlers; + +/// +/// 电子餐券处理 +/// +[Service(nameof(BalanceRecordSourceEnumType.EMealVoucher))] +public class EMealVoucherHandler : IConsumeHandler +{ + private readonly IDbContext _dbContext; + private readonly IOrderRepository _orderRepository; + private readonly IOrderCommonHandler _orderCommonHandler; + + public EMealVoucherHandler(IDbContext dbContext, + IOrderRepository orderRepository, + IOrderCommonHandler orderCommonHandler) + { + _dbContext = dbContext; + _orderRepository = orderRepository; + _orderCommonHandler = orderCommonHandler; + } + + public async Task> ConsumeAsync(OrderAddRequest request, GainfoEntity gainfo) + { + var msg = string.Empty; + var originData = await _dbContext.Queryable() + .Where(x => x.QrCode == request.UserUniqueNo) + .Select(x => x.OriginData) + .SingleAsync(); + + if (originData.IsEmpty()) + { + msg = "无法识别"; + return new DefaultApiResult + { + Code = ApiStateCode.Error, + Data = null, + Msg = msg + }; + } + + var originDataItems = originData.Split(":"); + var no = originDataItems[0]; + var idNo = originDataItems[3]; + + try + { + await EMealVoucherConsumeAsync(request.Adapt(), gainfo, originData, no, idNo); + } + catch (Exception ex) + { + msg = ex.Message; + } + + //获取餐券余额 + var data = await _dbContext.Queryable() + .LeftJoin((x, d) => x.No == d.No) + .Where((x, d) => x.No == no && d.IdNo == idNo) + .Select((x, d) => new OrderResultResponse + { + UserCode = d.IdNo, + UserName = d.Name, + CurrentBalance = d.Balance + }) + .SingleAsync(); + + try + { + var v = data.UserCode ?? string.Empty; + var vc = v.ToCharArray().Reverse().ToList(); + + for (int i = 0; i < vc.Count; i++) + { + if (i + 1 > 4) + { + vc[i] = '*'; + } + } + + vc.Reverse(); + data.UserCode = string.Join("", vc); + } + catch (Exception) + { + //ignore + } + + return new DefaultApiResult + { + Code = msg.IsPresent() ? ApiStateCode.Error : ApiStateCode.Success, + Data = data, + Msg = msg + }; + } + + + /// + /// 电子餐券消费 + /// + /// + /// + /// + /// + /// + private async Task EMealVoucherConsumeAsync(ConsumeRequest request, GainfoEntity gainfo, string originData, string no, string idNo) + { + var now = DateTime.Now; + + var current = await _dbContext.Queryable() + .Where(x => x.No == no && x.IdNo == idNo) + .Select(x => new { x.Name, x.Start, x.End }) + .SingleAsync(); + + (now >= current.Start && now <= current.End).ThrowIfFalse("餐券已过期"); + + var eMealVoucher = await _dbContext.Queryable().Where(x => x.No == no).SingleAsync(); + + var checkData = await _orderCommonHandler.PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime); + var isSupermarket = await _dbContext.Queryable() + .Where(x => x.Code == checkData.BusinessPlaceCode) + .Select(x => x.Catalog == CanteenBusinessPlaceCatalogEnumType.Supermarket) + .SingleAsync(); + + isSupermarket.ThrowIfTrue("禁止在超市消费"); + + eMealVoucher.Factories.Contains(checkData.Factory).ThrowIfFalse("禁止在当前厂区消费"); + + gainfo.No = originData; + var order = await _orderRepository.CreateDeviceConsumeOrderAsync(checkData, request, gainfo); + + await _orderCommonHandler.TryConsumeAsync(order.Id, async () => + { + await CommonHelper.RetryAsync(async () => + { + var detail = await _dbContext.Queryable().Where(x => x.No == no && x.IdNo == idNo).SingleAsync(); + //金额+- + detail.Balance += order.Amount; + (detail.Balance < 0).ThrowIfTrue("余额不足,无法消费"); + + await _dbContext.Updateable() + .SetColumns(x => x.Balance == detail.Balance) + .SetColumns(x => x.Version == x.Version + 1) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.No == no && x.IdNo == idNo && x.Version == detail.Version) //必须与查询时的version一致 + .ExecuteCommandThrowVersionAsync(); + + //写入记录 + var balanceRecord = order.Adapt(); + balanceRecord.Remark = $"({no})" + current.Name; + await _dbContext.InsertAsync(balanceRecord); + }, 5); + }); + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/OrderCommonHandler.cs b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/OrderCommonHandler.cs new file mode 100644 index 00000000..21ac6801 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/OrderCommonHandler.cs @@ -0,0 +1,144 @@ +using Dlhis.Canteen.Order.Dto; +using Dlhis.Canteen.Setting.Services; +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.CustomClass; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.Utils.Extensions; + +namespace Dlhis.Canteen.Order.Services.ConsumeHandlers; + +/// +/// 订单通用处理 +/// +public class OrderCommonHandler : IOrderCommonHandler +{ + private readonly IDbContext _dbContext; + private readonly ICanteenSettingService _canteenSettingService; + private readonly ILogger _logger; + private readonly IHttpContextAccessor _httpContextAccessor; + + public OrderCommonHandler(IDbContext dbContext, + IHttpContextAccessor httpContextAccessor, + ICanteenSettingService canteenSettingService, + ILogger logger) + { + _dbContext = dbContext; + _canteenSettingService = canteenSettingService; + _httpContextAccessor = httpContextAccessor; + _logger = logger; + } + + /// + /// 设置设备ip + /// + /// + public async Task SetDeviceIpInfoAsync(string deviceNo) + { + try + { + if (_httpContextAccessor.HttpContext!.Request.Headers.TryGetValue("X-Requested-DeviceIp", out var ip)) + { + var device = await _dbContext.Queryable().Where(x => x.UniqueNo == deviceNo).SingleAsync(); + device.ConnectionInfo = new + { + ip = ip.ToString() + }.ToJson(); + + await _dbContext.UpdateAsync(device); + } + + _logger.LogInformation("设备ip获取:{deviceNo} {ip}", deviceNo, ip); + } + catch (Exception) + { + //ignore + } + } + + /// + /// 消费前预检 + /// + /// 设备号 + /// 消费时间 + /// + public async Task PreCheckAsync(string deviceUniqueNo, DateTime costDateTime) + { + var device = await _dbContext.Queryable().Where(x => x.UniqueNo == deviceUniqueNo).SingleAsync(); + device.ThrowIfNull("设备尚未登记"); + device.Enable.ThrowIfFalse("设备已被停用"); + (device.Type != DeviceTypeEnumType.Meal).ThrowIfTrue("设备类型有误"); + + var bindingInfo = await _dbContext.Queryable() + .LeftJoin((x, b) => x.BusinessPlaceCode == b.Code) + .LeftJoin((x, b, bs) => bs.PlaceCode == b.Code) + .Where(x => x.DeviceUniqueNo == deviceUniqueNo && x.BusinessPlaceCode.HasValue) + .Select((x, b, bs) => new + { + b.Code, + bs.ShiftCode, + Factory = x.TenantId + }) + .SingleAsync(); + + bindingInfo.ThrowIfNull("设备尚未登记营业点"); + + //获取当前消费餐次 + var shifts = await _dbContext.Queryable() + .Where(x => x.ShiftCode == bindingInfo.ShiftCode) + .Select(x => new { x.ShiftType, x.Start, x.End }) + .ToListAsync(); + shifts.ThrowIfEmpty("营业点餐次尚未设置"); + + var shift = shifts.FirstOrDefault(x => new TimePeriod + { + Start = x.Start, + End = x.End + }.IsPresent(costDateTime)); + shift.ThrowIfNull("非就餐时间"); + + var costDate = await _canteenSettingService.GetCostDateAsync(bindingInfo.Factory, costDateTime); + + return new OrderCheckResultDto + { + Factory = bindingInfo.Factory, + CostDate = costDate, + ShiftType = shift!.ShiftType, + BusinessPlaceCode = bindingInfo.Code, + BusinessShiftCode = bindingInfo.ShiftCode + }; + } + + /// + /// 消费更新处理 + /// + /// + /// + public async Task TryConsumeAsync(long orderId, Func action) + { + try + { + await action(); + + await _dbContext.Updateable() + .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Success) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.Id == orderId) + .ExecuteCommandAsync(); + } + catch (Exception ex) + { + await _dbContext.Updateable() + .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Failure) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .SetColumns(x => x.Result == ex.Message) + .Where(x => x.Id == orderId) + .ExecuteCommandAsync(); + + throw; + } + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/IConsumeHandler.cs b/Src/Dlhis.Canteen/Order/Services/IConsumeHandler.cs new file mode 100644 index 00000000..4de14676 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Services/IConsumeHandler.cs @@ -0,0 +1,20 @@ +using Dlhis.Canteen.Order.Request; +using Dlhis.Canteen.Order.Response; +using Dlhis.Entity.Basic.Entity; +using Kurisu.AspNetCore.UnifyResultAndValidation; + +namespace Dlhis.Canteen.Order.Services; + +/// +/// 消费处理器 +/// +public interface IConsumeHandler : IScopeDependency +{ + /// + /// 消费 + /// + /// + /// + /// + Task> ConsumeAsync(OrderAddRequest request, GainfoEntity gainfo); +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/IOrderCommonHandler.cs b/Src/Dlhis.Canteen/Order/Services/IOrderCommonHandler.cs new file mode 100644 index 00000000..c1762121 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Services/IOrderCommonHandler.cs @@ -0,0 +1,29 @@ +using Dlhis.Canteen.Order.Dto; + +namespace Dlhis.Canteen.Order.Services; + +public interface IOrderCommonHandler : IScopeDependency +{ + /// + /// 消费更新处理 + /// + /// + /// + /// + Task TryConsumeAsync(long orderId, Func action); + + /// + /// 设置设备ip + /// + /// + /// + Task SetDeviceIpInfoAsync(string deviceNo); + + /// + /// 消费前预检 + /// + /// 设备号 + /// 消费时间 + /// + Task PreCheckAsync(string deviceUniqueNo, DateTime costDateTime); +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs index d6284a13..22203026 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs @@ -1,19 +1,14 @@ using Dlhis.Basic.Api; -using Dlhis.Canteen.Order.Dto; using Dlhis.Canteen.Order.Repository; +using Dlhis.Canteen.Order.Request; +using Dlhis.Canteen.Order.Response; using Dlhis.Canteen.Setting.Services; +using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; -using Dlhis.Entity.Device.Entities; -using Kurisu.AspNetCore.Utils; -using Kurisu.AspNetCore.Utils.Extensions; -using Mapster; -using SqlSugar; -using Dlhis.Canteen.Order.Response; -using Dlhis.Canteen.Order.Request; using Dlhis.Entity.Device; -using Dlhis.Entity.Device.Enums; +using Dlhis.Entity.Device.Entities; using Kurisu.AspNetCore.Authentication.Abstractions; using Kurisu.AspNetCore.Cache; using Kurisu.AspNetCore.CustomClass; @@ -21,7 +16,10 @@ using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using Kurisu.AspNetCore.UnifyResultAndValidation; -using Dlhis.Constants; +using Kurisu.AspNetCore.Utils; +using Kurisu.AspNetCore.Utils.Extensions; +using Mapster; +using SqlSugar; namespace Dlhis.Canteen.Order.Services.Implements; @@ -30,31 +28,34 @@ public class OrderService : IOrderService private readonly ICanteenSettingService _canteenSettingService; private readonly IDbContext _dbContext; private readonly ICurrentUser _currentUser; - private readonly IHttpContextAccessor _httpContextAccessor; private readonly IBalanceRepository _balanceRepository; private readonly IOrderRepository _orderRepository; private readonly RedisCache _redisCache; private readonly IGainfoPermissionApi _gainfoPermissionApi; + private readonly IOrderCommonHandler _orderCommonHandler; + private readonly INamedResolver _namedResolver; private readonly ILogger _logger; public OrderService(ICanteenSettingService canteenSettingService, IDbContext dbContext, ICurrentUser currentUser, - IHttpContextAccessor httpContextAccessor, IBalanceRepository balanceRepository, IOrderRepository orderRepository, RedisCache redisCache, IGainfoPermissionApi gainfoPermissionApi, + IOrderCommonHandler orderCommonHandler, + INamedResolver namedResolver, ILogger logger) { _canteenSettingService = canteenSettingService; _dbContext = dbContext; _currentUser = currentUser; - _httpContextAccessor = httpContextAccessor; _balanceRepository = balanceRepository; _orderRepository = orderRepository; _redisCache = redisCache; _gainfoPermissionApi = gainfoPermissionApi; + _orderCommonHandler = orderCommonHandler; + _namedResolver = namedResolver; _logger = logger; } @@ -75,7 +76,7 @@ public class OrderService : IOrderService /// public async Task> AddAsync(OrderAddRequest request) { - await SetDeviceIpInfoAsync(request.DeviceUniqueNo); + await _orderCommonHandler.SetDeviceIpInfoAsync(request.DeviceUniqueNo); await using var handler = await _redisCache.LockAsync($"consume:device:{request.UserUniqueNo}"); handler.Acquired.ThrowIfFalse("请勿频繁消费"); @@ -152,39 +153,47 @@ public class OrderService : IOrderService var s = long.TryParse(request.UserUniqueNo, out var userId); GainfoEntity gainfo; + //条码消费 if (request.Source == BalanceRecordSourceEnumType.QrCode) { - if (request.UserUniqueNo.StartsWith(QrCodeConstants.User)) + var flag = request.UserUniqueNo.Substring(0, 2); + switch (flag) { - gainfo = await GetUserByQrCodeAsync(request.UserUniqueNo); - await CheckPermissionAsync(gainfo.Code, request.DeviceUniqueNo); - } - else if (request.UserUniqueNo.StartsWith(QrCodeConstants.EMealVoucher)) - { - request.Source = BalanceRecordSourceEnumType.EMealVoucher; - var eMealVoucherQrCode = await _dbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); - eMealVoucherQrCode.ThrowIfNull("无法识别"); - var code = eMealVoucherQrCode.OriginData.Split(':')[2]; - gainfo = await _dbContext.Queryable().Where(x => x.Code == code).SingleAsync(); - } - else if (request.UserUniqueNo.StartsWith(QrCodeConstants.Birthday)) - { - var ticket = await _dbContext.Queryable().Where(x => x.Type == TicketEnumType.Birthday).Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); - ticket.ThrowIfNull("无法识别"); - gainfo = await _dbContext.Queryable().Where(x => x.Code == ticket.UserCode).SingleAsync(); - } - else - { - throw new UserFriendlyException($"无法识别{request.UserUniqueNo}"); + case QrCodeConstants.User: + { + gainfo = await GetUserByQrCodeAsync(request.UserUniqueNo); + await CheckPermissionAsync(gainfo.Code, request.DeviceUniqueNo); + } + break; + case QrCodeConstants.EMealVoucher: + { + request.Source = BalanceRecordSourceEnumType.EMealVoucher; + var eMealVoucherQrCode = await _dbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); + eMealVoucherQrCode.ThrowIfNull("无法识别"); + var code = eMealVoucherQrCode.OriginData.Split(':')[2]; + gainfo = await _dbContext.Queryable().Where(x => x.Code == code).SingleAsync(); + } + break; + case QrCodeConstants.Birthday: + { + request.Source = BalanceRecordSourceEnumType.Birthday; + var ticket = await _dbContext.Queryable().Where(x => x.Type == TicketEnumType.Birthday).Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); + ticket.ThrowIfNull("无法识别"); + gainfo = await _dbContext.Queryable().Where(x => x.Code == ticket.UserCode).SingleAsync(); + } + break; + + default: throw new UserFriendlyException($"无法识别{request.UserUniqueNo}"); } } else { //根据档案号 + //区分userId和code: 工号纯数字避免跟userId相同导致查询到的消费人错误 gainfo = await _dbContext.Queryable() - .WhereIF(request.Source == BalanceRecordSourceEnumType.Card, x => x.CardNo == request.UserUniqueNo) - .WhereIF(request.Source != BalanceRecordSourceEnumType.Card && !request.IsUserId, x => x.Code == request.UserUniqueNo) - .WhereIF(request.Source != BalanceRecordSourceEnumType.Card && request.IsUserId && s, x => x.Id == userId) + .WhereIF(request.Source == BalanceRecordSourceEnumType.Card, x => x.CardNo == request.UserUniqueNo) //卡号 + .WhereIF(request.Source != BalanceRecordSourceEnumType.Card && !request.IsUserId, x => x.Code == request.UserUniqueNo) //工号 + .WhereIF(request.Source != BalanceRecordSourceEnumType.Card && request.IsUserId && s, x => x.Id == userId) //user id .SingleAsync(); } @@ -230,7 +239,7 @@ public class OrderService : IOrderService //一天消费金额 var dayCostMax = await _canteenSettingService.GetSettingAsync(CanteenSettingItemEnumType.DayCostMax, order.TenantId, order.UserNo); - if (dayCostMax != default) + if (dayCostMax != 0) { //消费记录一定会有营业点代码!.Value是安全用法 var cost = todayAllBalanceRecords @@ -242,7 +251,7 @@ public class OrderService : IOrderService //一次消费金额 var onceCostMax = await _canteenSettingService.GetSettingAsync(CanteenSettingItemEnumType.OnceCostMax, order.TenantId, order.UserNo); - if (onceCostMax != default) + if (onceCostMax != 0) { (Math.Abs(order.Amount) > onceCostMax).ThrowIfTrue($"单次消费金额不能超出{onceCostMax}元"); } @@ -251,7 +260,7 @@ public class OrderService : IOrderService if (order.BusinessPlaceCode.HasValue && supermarketCodes.Contains(order.BusinessPlaceCode.Value)) { var dayMarketCostMax = await _canteenSettingService.GetSettingAsync(CanteenSettingItemEnumType.DayMarketCostMax, order.TenantId, order.UserNo); - if (dayMarketCostMax != default) + if (dayMarketCostMax != 0) { var cost = todayAllBalanceRecords.Where(x => x.BusinessPlaceCode.HasValue) .Where(x => supermarketCodes.Contains(x.BusinessPlaceCode.Value)) @@ -354,7 +363,7 @@ public class OrderService : IOrderService /// private async Task ConsumeAsync(ConsumeRequest request, GainfoEntity gainfo) { - var checkData = await PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime); + var checkData = await _orderCommonHandler.PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime); var order = await _orderRepository.CreateDeviceConsumeOrderAsync(checkData, request, gainfo); if (request.Image.IsPresent()) @@ -367,7 +376,7 @@ public class OrderService : IOrderService }); } - await TryConsumeAsync(order.Id, async () => + await _orderCommonHandler.TryConsumeAsync(order.Id, async () => { //校验 await Verify(order); @@ -380,78 +389,11 @@ public class OrderService : IOrderService }); } - private async Task> EMealVoucherConsumeAsync(OrderAddRequest request, GainfoEntity gainfo) - { - var msg = string.Empty; - var originData = await _dbContext.Queryable() - .Where(x => x.QrCode == request.UserUniqueNo) - .Select(x => x.OriginData) - .SingleAsync(); - if (originData.IsEmpty()) - { - msg = "无法识别"; - return new DefaultApiResult - { - Code = ApiStateCode.Error, - Data = null, - Msg = msg - }; - } - - var originDataItems = originData.Split(":"); - var no = originDataItems[0]; - var idNo = originDataItems[3]; - - try - { - await EMealVoucherConsumeAsync(request.Adapt(), gainfo, originData, no, idNo); - } - catch (Exception ex) - { - msg = ex.Message; - } - - //获取餐券余额 - var data = await _dbContext.Queryable() - .LeftJoin((x, d) => x.No == d.No) - .Where((x, d) => x.No == no && d.IdNo == idNo) - .Select((x, d) => new OrderResultResponse - { - UserCode = d.IdNo, - UserName = d.Name, - CurrentBalance = d.Balance - }) - .SingleAsync(); - - try - { - var v = data.UserCode ?? string.Empty; - var vc = v.ToCharArray().Reverse().ToList(); - - for (int i = 0; i < vc.Count; i++) - { - if (i + 1 > 4) - { - vc[i] = '*'; - } - } - - vc.Reverse(); - data.UserCode = string.Join("", vc); - } - catch (Exception) - { - //ignore - } - - return new DefaultApiResult - { - Code = msg.IsPresent() ? ApiStateCode.Error : ApiStateCode.Success, - Data = data, - Msg = msg - }; - } + // private async Task> BirthdayConsumeAsync(OrderAddRequest request, GainfoEntity gainfo) + // { + // + // } private async Task OfflineConsumeAsync(OrderAddRequest request, GainfoEntity gainfo) @@ -490,8 +432,9 @@ public class OrderService : IOrderService { var message = string.Empty; - if (request.Source == BalanceRecordSourceEnumType.EMealVoucher) - return await EMealVoucherConsumeAsync(request, gainfo); + var otherTypes = new[] { BalanceRecordSourceEnumType.EMealVoucher, BalanceRecordSourceEnumType.Birthday }; + if (otherTypes.Contains(request.Source)) + return await _namedResolver.GetService(request.Source.ToString()).ConsumeAsync(request, gainfo); if (request.IsOffline) await OfflineConsumeAsync(request, gainfo); @@ -547,144 +490,6 @@ public class OrderService : IOrderService return await _dbContext.Queryable().Where(x => x.Code == gainfoQrCode.UserCode).SingleAsync(); } - /// - /// 电子餐券消费 - /// - /// - /// - /// - /// - /// - private async Task EMealVoucherConsumeAsync(ConsumeRequest request, GainfoEntity gainfo, string originData, string no, string idNo) - { - var now = DateTime.Now; - - var current = await _dbContext.Queryable() - .Where(x => x.No == no && x.IdNo == idNo) - .Select(x => new { x.Name, x.Start, x.End }) - .SingleAsync(); - - (now >= current.Start && now <= current.End).ThrowIfFalse("餐券已过期"); - - - var eMealVoucher = await _dbContext.Queryable().Where(x => x.No == no).SingleAsync(); - - var checkData = await PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime); - var isSupermarket = await _dbContext.Queryable().Where(x => x.Code == checkData.BusinessPlaceCode) - .Select(x => x.Catalog == CanteenBusinessPlaceCatalogEnumType.Supermarket) - .SingleAsync(); - - isSupermarket.ThrowIfTrue("禁止在超市消费"); - - eMealVoucher.Factories.Contains(checkData.Factory).ThrowIfFalse("禁止在当前厂区消费"); - - gainfo.No = originData; - var order = await _orderRepository.CreateDeviceConsumeOrderAsync(checkData, request, gainfo); - - await TryConsumeAsync(order.Id, async () => - { - await CommonHelper.RetryAsync(async () => - { - var detail = await _dbContext.Queryable().Where(x => x.No == no && x.IdNo == idNo).SingleAsync(); - //金额+- - detail.Balance += order.Amount; - (detail.Balance < 0).ThrowIfTrue("余额不足,无法消费"); - - await _dbContext.Updateable() - .SetColumns(x => x.Balance == detail.Balance) - .SetColumns(x => x.Version == x.Version + 1) - .SetColumns(x => x.ModifiedTime == DateTime.Now) - .Where(x => x.No == no && x.IdNo == idNo && x.Version == detail.Version) //必须与查询时的version一致 - .ExecuteCommandThrowVersionAsync(); - - //写入记录 - var balanceRecord = order.Adapt(); - balanceRecord.Remark = $"({no})" + current.Name; - await _dbContext.InsertAsync(balanceRecord); - }, 5); - }); - } - - /// - /// 消费前预检 - /// - /// - /// - /// - private async Task PreCheckAsync(string deviceUniqueNo, DateTime costDateTime) - { - var device = await _dbContext.Queryable().Where(x => x.UniqueNo == deviceUniqueNo).SingleAsync(); - device.ThrowIfNull("设备尚未登记"); - device.Enable.ThrowIfFalse("设备已被停用"); - (device.Type != DeviceTypeEnumType.Meal).ThrowIfTrue("设备类型有误"); - - var bindingInfo = await _dbContext.Queryable() - .LeftJoin((x, b) => x.BusinessPlaceCode == b.Code) - .LeftJoin((x, b, bs) => bs.PlaceCode == b.Code) - .Where(x => x.DeviceUniqueNo == deviceUniqueNo && x.BusinessPlaceCode.HasValue) - .Select((x, b, bs) => new - { - b.Code, - bs.ShiftCode, - Factory = x.TenantId - }) - .SingleAsync(); - - bindingInfo.ThrowIfNull("设备尚未登记营业点"); - - //获取当前消费餐次 - var shifts = await _dbContext.Queryable() - .Where(x => x.ShiftCode == bindingInfo.ShiftCode) - .Select(x => new { x.ShiftType, x.Start, x.End }) - .ToListAsync(); - shifts.ThrowIfEmpty("营业点餐次尚未设置"); - - var shift = shifts.FirstOrDefault(x => new TimePeriod - { - Start = x.Start, - End = x.End - }.IsPresent(costDateTime)); - shift.ThrowIfNull("非就餐时间"); - - var costDate = await _canteenSettingService.GetCostDateAsync(bindingInfo.Factory, costDateTime); - - return new OrderPreCheckDto - { - Factory = bindingInfo.Factory, - CostDate = costDate, - ShiftType = shift!.ShiftType, - BusinessPlaceCode = bindingInfo.Code, - BusinessShiftCode = bindingInfo.ShiftCode - }; - } - - /// - /// 设置设备ip - /// - /// - private async Task SetDeviceIpInfoAsync(string deviceNo) - { - try - { - if (_httpContextAccessor.HttpContext!.Request.Headers.TryGetValue("X-Requested-DeviceIp", out var ip)) - { - var device = await _dbContext.Queryable().Where(x => x.UniqueNo == deviceNo).SingleAsync(); - device.ConnectionInfo = new - { - ip = ip.ToString() - }.ToJson(); - - await _dbContext.UpdateAsync(device); - } - - _logger.LogInformation("设备ip获取:{deviceNo} {ip}", deviceNo, ip); - } - catch (Exception) - { - //ignore - } - } - /// /// 检查是否能够进行离线消费,处理hpt重复提交 /// @@ -700,34 +505,9 @@ public class OrderService : IOrderService if (orders.IsEmpty()) return true; - var order = orders.FirstOrDefault(); + var order = orders.FirstOrDefault()!; //存在在线order数据,但是状态未成功 return !order.IsOffline && order.OrderStatus != CanteenOrderStatusEnumType.Success; } - - private async Task TryConsumeAsync(long orderId, Func action) - { - try - { - await action(); - - await _dbContext.Updateable() - .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Success) - .SetColumns(x => x.ModifiedTime == DateTime.Now) - .Where(x => x.Id == orderId) - .ExecuteCommandAsync(); - } - catch (Exception ex) - { - await _dbContext.Updateable() - .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Failure) - .SetColumns(x => x.ModifiedTime == DateTime.Now) - .SetColumns(x => x.Result == ex.Message) - .Where(x => x.Id == orderId) - .ExecuteCommandAsync(); - - throw; - } - } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs b/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs index ba75b0e9..78bc5e07 100644 --- a/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs +++ b/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs @@ -40,8 +40,8 @@ public class BirthdayTicketService : BaseTicketService, IBirthdayTicketService { Type = TicketEnumType.Birthday, UserCode = item.Code, - OriginalAmount = amount, - Amount = amount, + OriginalBalance = amount, + Balance = amount, QrCode = qrCode, Remark = todayStr + "生日券", TenantId = item.Factory diff --git a/Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs index d3ca3c05..451b7ba4 100644 --- a/Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs +++ b/Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs @@ -10,7 +10,7 @@ namespace Dlhis.Entity.Canteen.Entities; /// 券 /// [SugarTable("Tickets", TableDescription = "券")] -public class TicketEntity : SugarBaseEntity, ITenantId +public class TicketEntity : SugarBaseEntity, ITenantId, IVersion { /// /// 类型 @@ -28,13 +28,13 @@ public class TicketEntity : SugarBaseEntity, ITenantId /// 初始余额 /// [SugarColumn(IsNullable = false, ColumnDescription = "初始余额")] - public decimal OriginalAmount { get; set; } + public decimal OriginalBalance { get; set; } /// /// 当前余额 /// [SugarColumn(IsNullable = false, ColumnDescription = "当前余额")] - public decimal Amount { get; set; } + public decimal Balance { get; set; } /// /// 消费码 @@ -49,4 +49,7 @@ public class TicketEntity : SugarBaseEntity, ITenantId public string Remark { get; set; } public string TenantId { get; set; } + + /// + public int Version { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs b/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs index 79d86f43..16f5a7fe 100644 --- a/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs +++ b/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs @@ -37,6 +37,14 @@ public enum BalanceRecordSourceEnumType /// [Description("电子餐券")] EMealVoucher, + + + /// + /// 生日券 + /// + [Description("生日券")] + Birthday, + //********************************************************************************************************* /// @@ -70,7 +78,7 @@ public enum BalanceRecordSourceEnumType /// [Description("其他基地餐补")] OtherTenantSubsidies, - + /// /// 余额写入 /// From 3999f8aa20528e1310f507232612d07ef6e2f797 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Wed, 19 Feb 2025 12:11:13 +0800 Subject: [PATCH 08/25] =?UTF-8?q?add=20=E8=80=83=E5=8B=A4=E5=88=86?= =?UTF-8?q?=E9=A1=B5=E5=92=8C=E8=A1=A5=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Implements/SapBusinessTripService.cs | 1 - .../Controllers/WorkGridsController.cs | 25 ++++++- .../WorkGridScheduleAttendancePageRequest.cs | 13 ++++ .../WorkGridScheduleAttendancePageResponse.cs | 63 +++++++++++++++++ .../Services/IWorkGridScheduleService.cs | 5 ++ .../Implements/WorkGridScheduleService.cs | 68 ++++++++++++++++++- 6 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleAttendancePageRequest.cs create mode 100644 Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleAttendancePageResponse.cs diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/SapBusinessTripService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/SapBusinessTripService.cs index 7460cf1a..a89f549d 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/SapBusinessTripService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/SapBusinessTripService.cs @@ -1,4 +1,3 @@ -using Dlhis.Basic.Device.Services; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Device.Entities; using Dlhis.Entity.Device.Enums; diff --git a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs index 4549aca8..c8a31385 100644 --- a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs +++ b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs @@ -51,7 +51,7 @@ public class WorkGridsController : ControllerBase { return await _workGridService.GetPageAsync(request); } - + /// /// 修改网格管理者 /// @@ -61,7 +61,7 @@ public class WorkGridsController : ControllerBase { await _workGridService.ChangeAsync(request.From, request.To); } - + /// /// 获取我的网格信息 /// @@ -151,4 +151,25 @@ public class WorkGridsController : ControllerBase { return await _workGridScheduleService.GetListSummaryAsync(workGridCode, start, end); } + + /// + /// 获取网格人员考勤记录分页 + /// + /// + /// + [HttpGet("user/attendance/page")] + public async Task> GetAttendancePageAsync(WorkGridScheduleAttendancePageRequest request) + { + return await _workGridScheduleService.GetAttendancePageAsync(request); + } + + /// + /// 网格人员考勤记录补传 + /// + /// + [HttpPost("user/attendance/upload")] + public async Task ManuallyUploadAsync(List logIds) + { + await _workGridScheduleService.ManuallyUploadAsync(logIds); + } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleAttendancePageRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleAttendancePageRequest.cs new file mode 100644 index 00000000..bc783d40 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleAttendancePageRequest.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; +using Kurisu.AspNetCore.CustomClass; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Basic.WorkGrids.Request; + +public class WorkGridScheduleAttendancePageRequest : PageDto +{ + [Required(ErrorMessage = "工号不能为空")] + public string UserCode { get; set; } + + public DateTimePeriod DateTimePeriod { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleAttendancePageResponse.cs b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleAttendancePageResponse.cs new file mode 100644 index 00000000..e4e3ff16 --- /dev/null +++ b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleAttendancePageResponse.cs @@ -0,0 +1,63 @@ +using Newtonsoft.Json; + +namespace Dlhis.Basic.WorkGrids.Response; + +public class WorkGridScheduleAttendancePageResponse +{ + public long Id { get; set; } + + /// + /// 设备号 + /// + public string DeviceUniqueNo { get; set; } + + /// + /// 设备部署点 + /// + public string DeployPlace { get; set; } + + /// + /// 用户学工号 + /// + public string UserCode { get; set; } + + + /// + /// 用户名称 + /// + public string UserName { get; set; } + + /// + /// 上传时间 + /// + public DateTime RaiseDateTime { get; set; } + + /// + /// 记录创建时间 + /// + public DateTime CreateTime { get; set; } + + /// + /// 序列号 + /// + public string SerialNo { get; set; } + + + [JsonIgnore] + public string OriginUserUniqueNo { get; set; } + + /// + /// 是否同步sap + /// + public bool Sync { get; set; } + + /// + /// 是否需要上传 + /// + public bool NeedUpload { get; set; } + + /// + /// 是否有效 + /// + public bool Status { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs index 2b6783d9..df2d46fc 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs @@ -1,5 +1,6 @@ using Dlhis.Basic.WorkGrids.Request; using Dlhis.Basic.WorkGrids.Response; +using Kurisu.AspNetCore.DataAccess.Dto; namespace Dlhis.Basic.WorkGrids.Services; @@ -13,4 +14,8 @@ public interface IWorkGridScheduleService : IScopeDependency Task> GetListAsync(Guid workGridCode, DateOnly date); Task> GetListSummaryAsync(Guid workGridCode, DateOnly start, DateOnly end); + + Task> GetAttendancePageAsync(WorkGridScheduleAttendancePageRequest request); + + Task ManuallyUploadAsync(List logIds); } \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs index 1e2f25c7..40c2d706 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs @@ -1,6 +1,12 @@ using Dlhis.Basic.WorkGrids.Request; using Dlhis.Basic.WorkGrids.Response; using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Device.Entities; +using Dlhis.Jip.Api; +using Dlhis.Jip.Api.Requests; +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; @@ -9,10 +15,12 @@ namespace Dlhis.Basic.WorkGrids.Services.Implements; public class WorkGridScheduleService : IWorkGridScheduleService { private readonly IDbContext _dbContext; + private readonly IJinkoJipApi _jinkoJipApi; - public WorkGridScheduleService(IDbContext dbContext) + public WorkGridScheduleService(IDbContext dbContext ,IJinkoJipApi jinkoJipApi) { _dbContext = dbContext; + _jinkoJipApi = jinkoJipApi; } public async Task SaveAsync(WorkGridScheduleSaveRequest request) @@ -78,4 +86,62 @@ public class WorkGridScheduleService : IWorkGridScheduleService }; }); } + + /// + public async Task> GetAttendancePageAsync(WorkGridScheduleAttendancePageRequest request) + { + return await _dbContext.Queryable() + .LeftJoin((log, d) => log.DeviceUniqueNo == d.UniqueNo) + .Where(log => log.UserUniqueNo == request.UserCode ) + .WhereIF(request.DateTimePeriod.HasValue(), log => log.RaiseDateTime >= request.DateTimePeriod.Start + && log.RaiseDateTime <= request.DateTimePeriod.End) + .OrderBy(log => log.RaiseDateTime) + .Select((log, d) => new WorkGridScheduleAttendancePageResponse + { + Id = log.Id, + OriginUserUniqueNo = log.UserUniqueNo, + DeviceUniqueNo = log.DeviceUniqueNo, + RaiseDateTime = log.RaiseDateTime, + CreateTime = log.CreateTime, + SerialNo = log.SerialNo, + DeployPlace = d.DeployPlace, + Sync = log.Sync, + Status = log.Status + }) + .ToPageListAsync(request); + } + + /// + public async Task ManuallyUploadAsync(List logIds) + { + var requests = await _dbContext.Queryable() + .LeftJoin((x, device) => x.DeviceUniqueNo == device.UniqueNo) + .Where(x => logIds.Contains(x.Id)) + .Where(x => x.NeedUpload && x.Sync == false) + .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() + .SetColumns(x => x.Sync == true) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => ids.Contains(x.Id)) + .ExecuteCommandAsync(); + } + } + } + } } \ No newline at end of file From f2f03e868579c1577d6725112044711dae8f97c8 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Mon, 24 Feb 2025 14:46:51 +0800 Subject: [PATCH 09/25] =?UTF-8?q?fix=20get=E5=8F=82=E6=95=B0=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs index c8a31385..7504ca30 100644 --- a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs +++ b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs @@ -134,7 +134,7 @@ public class WorkGridsController : ControllerBase /// /// [HttpGet("user/schedule/list")] - public async Task> GetListAsync(Guid workGridCode, DateOnly date) + public async Task> GetListAsync([FromQuery] Guid workGridCode, [FromQuery] DateOnly date) { return await _workGridScheduleService.GetListAsync(workGridCode, date); } From 4a20cf4169a9d8b14fb158d38d9e7a7201ca0465 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Mon, 24 Feb 2025 15:55:20 +0800 Subject: [PATCH 10/25] =?UTF-8?q?fix=20=E6=97=B6=E9=97=B4=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WorkGrids/Controllers/WorkGridsController.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs index 7504ca30..d70e7666 100644 --- a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs +++ b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs @@ -1,6 +1,7 @@ using Dlhis.Basic.WorkGrids.Request; using Dlhis.Basic.WorkGrids.Response; using Dlhis.Basic.WorkGrids.Services; +using Kurisu.AspNetCore.CustomClass; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop; using Microsoft.AspNetCore.Authorization; @@ -134,22 +135,23 @@ public class WorkGridsController : ControllerBase /// /// [HttpGet("user/schedule/list")] - public async Task> GetListAsync([FromQuery] Guid workGridCode, [FromQuery] DateOnly date) + public async Task> GetListAsync([FromQuery] Guid workGridCode, [FromQuery] DateTime date) { - return await _workGridScheduleService.GetListAsync(workGridCode, date); + return await _workGridScheduleService.GetListAsync(workGridCode, new DateOnly(date.Year, date.Month, date.Day)); } /// /// 获取网格人员排班详情 /// /// 网格 - /// 开始日期 - /// 结束日期 + /// /// [HttpGet("user/schedule/summary")] - public async Task> GetListSummaryAsync([FromQuery] Guid workGridCode, [FromQuery] DateOnly start, [FromQuery] DateOnly end) + public async Task> GetListSummaryAsync([FromQuery] Guid workGridCode, [FromQuery] DateTimePeriod datePeriod) { - return await _workGridScheduleService.GetListSummaryAsync(workGridCode, start, end); + var start = datePeriod.Start!.Value; + var end = datePeriod.End!.Value; + return await _workGridScheduleService.GetListSummaryAsync(workGridCode, new DateOnly(start.Year, start.Month, start.Day), new DateOnly(end.Year, end.Month, end.Day)); } /// From 0d90d3cc32917768a408e00640007790e03f7599 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 25 Feb 2025 11:42:39 +0800 Subject: [PATCH 11/25] =?UTF-8?q?fix=20=E8=A1=A8=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E7=89=B9=E6=80=A7=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs | 4 ++-- Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs | 4 ++++ Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs b/Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs index 22e58f7d..21ff88d1 100644 --- a/Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs +++ b/Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs @@ -21,13 +21,13 @@ public class WorkGridScheduleEntity : SugarBaseEntity, ITenantId /// /// 排班日期 /// - [SugarColumn(IsNullable = false, ColumnDescription = "排班日期")] + [SugarColumn(IsNullable = false, ColumnDataType = "date", ColumnDescription = "排班日期")] public DateOnly Date { get; set; } /// /// 排班类型 /// - [SugarColumn(IsNullable = false, ColumnDescription = "排班类型", SqlParameterDbType = typeof(EnumToStringConvert))] + [SugarColumn(IsNullable = false, ColumnDataType = "varchar(50)", ColumnDescription = "排班类型", SqlParameterDbType = typeof(EnumToStringConvert))] public WorkGridTimePeriodEnumType PeriodType { get; set; } /// diff --git a/Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs b/Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs index 1d842130..721823da 100644 --- a/Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs +++ b/Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs @@ -3,6 +3,7 @@ using Kurisu.AspNetCore.DataAccess.Entity; using Kurisu.AspNetCore.DataAccess.SqlSugar; using Mapster; using SqlSugar; +using SqlSugar.DbConvert; namespace Dlhis.Entity.Basic.Entity; @@ -16,6 +17,7 @@ public class WorkGridTimePeriodEntity : SugarBaseEntity, ITenantId /// 班次 /// [AdaptIgnore(MemberSide.Destination)] + [SugarColumn(IsNullable = false, ColumnDataType = "varchar(50)", SqlParameterDbType = typeof(EnumToStringConvert))] public WorkGridTimePeriodEnumType Type { get; set; } /// @@ -31,11 +33,13 @@ public class WorkGridTimePeriodEntity : SugarBaseEntity, ITenantId /// /// 开始时间 /// + [SugarColumn(IsNullable = false, ColumnDataType = "date")] public TimeOnly Start { get; set; } /// /// 结束时间 /// + [SugarColumn(IsNullable = false, ColumnDataType = "date")] public TimeOnly End { get; set; } diff --git a/Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs b/Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs index 7685a578..05ccd503 100644 --- a/Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs +++ b/Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs @@ -27,7 +27,7 @@ public class WorkGridUserEntity : SugarBaseEntity, ITenantId /// /// 排班类型 /// - [SugarColumn(IsNullable = true, ColumnDescription = "排班类型", SqlParameterDbType = typeof(EnumToStringConvert))] + [SugarColumn(IsNullable = true,ColumnDataType = "varchar(50)",ColumnDescription = "排班类型", SqlParameterDbType = typeof(EnumToStringConvert))] public WorkGridTimePeriodEnumType? ScheduleType { get; set; } /// From 8c915f73cee2868e7b12132c2aa2bd216b1f8d1e Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 25 Feb 2025 17:28:20 +0800 Subject: [PATCH 12/25] =?UTF-8?q?fix=20=E6=98=A0=E5=B0=84=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Response/WorkGridPageResponse.cs | 5 ++ .../WorkGridTimePeriodPageResponse.cs | 8 +++- .../Services/Implements/WorkGridService.cs | 8 +++- .../Implements/WorkGridTimePeriodService.cs | 46 ++++++++++--------- 4 files changed, 42 insertions(+), 25 deletions(-) diff --git a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridPageResponse.cs b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridPageResponse.cs index 3494011a..2ae483ae 100644 --- a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridPageResponse.cs +++ b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridPageResponse.cs @@ -28,4 +28,9 @@ public class WorkGridPageResponse /// 备注 /// public string Remark { get; set; } + + /// + /// 用户数量 + /// + public int UserCount { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridTimePeriodPageResponse.cs b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridTimePeriodPageResponse.cs index 03c23873..89ea9d65 100644 --- a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridTimePeriodPageResponse.cs +++ b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridTimePeriodPageResponse.cs @@ -1,5 +1,7 @@ using Dlhis.Entity.Basic.Enums; +using Kurisu.AspNetCore.Utils.Converters; using Kurisu.AspNetCore.Utils.Extensions; +using Newtonsoft.Json; namespace Dlhis.Basic.WorkGrids.Response; @@ -30,12 +32,14 @@ public class WorkGridTimePeriodPageResponse /// /// 开始时间 /// - public TimeOnly Start { get; set; } + [JsonConverter(typeof(ToDateJsonConverter))] + public DateTime Start { get; set; } /// /// 结束时间 /// - public TimeOnly End { get; set; } + [JsonConverter(typeof(ToDateJsonConverter))] + public DateTime End { get; set; } /// /// 配置描述 diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs index f087dd94..1df302e9 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs @@ -32,6 +32,11 @@ public class WorkGridService : IWorkGridService .WhereIF(request.Id.HasValue, x => x.Id != request.Id) .AnyAsync(); + if (!await _dbContext.Queryable().Where(x => x.Code == request.LeaderUserCode).AnyAsync()) + { + true.ThrowIfTrue($"工号:{request.LeaderUserCode}不存在"); + } + exists.ThrowIfTrue($"{request.LeaderUserCode}已存在管理的网格"); if (!request.Id.HasValue) @@ -63,7 +68,8 @@ public class WorkGridService : IWorkGridService Name = x.Name, LeaderUserCode = x.LeaderUserCode, UserName = ga.Name, - Remark = x.Remark + Remark = x.Remark, + UserCount = SqlFunc.Subqueryable().Where(p => p.WorkGridCode == x.Code).Count() }) .ToPageListAsync(request); } diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs index b07b4396..01d4dcc6 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs @@ -50,9 +50,11 @@ public class WorkGridTimePeriodService : IWorkGridTimePeriodService /// public async Task> GetPageAsync(WorkGridTimePeriodPageRequest request) { - return await _dbContext.Queryable() + var data = await _dbContext.Queryable() .Select() .ToPageListAsync(request); + + return data; } //************************************************************************************************************************************************* @@ -69,25 +71,25 @@ public class WorkGridTimePeriodService : IWorkGridTimePeriodService .SingleAsync(); } - /// - /// 检查时间段重合检查 - /// - /// - /// - private async Task CheckDuplicateTimePeriodAsync(WorkGridTimePeriodSaveRequest request) - { - var periods = await _dbContext.Queryable() - .Where(x => x.Type != request.Type) - .Select(x => new TimePeriod - { - Start = x.Start, - End = x.End - }) - .ToListAsync(); - - foreach (var period in periods) - { - period.IsDuplicate(request.Adapt()).ThrowIfTrue($"存在时间段重合[{period.Start}-{period.End}]"); - } - } + // /// + // /// 检查时间段重合检查 + // /// + // /// + // /// + // private async Task CheckDuplicateTimePeriodAsync(WorkGridTimePeriodSaveRequest request) + // { + // var periods = await _dbContext.Queryable() + // .Where(x => x.Type != request.Type) + // .Select(x => new TimePeriod + // { + // Start = x.Start, + // End = x.End + // }) + // .ToListAsync(); + // + // foreach (var period in periods) + // { + // period.IsDuplicate(request.Adapt()).ThrowIfTrue($"存在时间段重合[{period.Start}-{period.End}]"); + // } + // } } \ No newline at end of file From ca2f50511f55ec8ec632fff675ea63a15cb491b2 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 25 Feb 2025 17:31:22 +0800 Subject: [PATCH 13/25] =?UTF-8?q?fix=20name=E9=87=8D=E5=A4=8D=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WorkGrids/Services/Implements/WorkGridService.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs index 1df302e9..1072ded7 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs @@ -37,6 +37,13 @@ public class WorkGridService : IWorkGridService true.ThrowIfTrue($"工号:{request.LeaderUserCode}不存在"); } + if (await _dbContext.Queryable().Where(x => x.Name == request.Name) + .WhereIF(request.Id.HasValue, x => x.Id != request.Id) + .AnyAsync()) + { + true.ThrowIfTrue($"网格区域名称[{request.Name}]重复"); + } + exists.ThrowIfTrue($"{request.LeaderUserCode}已存在管理的网格"); if (!request.Id.HasValue) From 1669dcbd1184a6bcd4d7c49d97d8d2a6b2646ff6 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 25 Feb 2025 17:46:54 +0800 Subject: [PATCH 14/25] =?UTF-8?q?fix=20=E6=9F=A5=E7=9C=8B=E5=BD=93?= =?UTF-8?q?=E5=89=8D=E7=BD=91=E6=A0=BC=E5=88=86=E9=A1=B5PC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WorkGrids/Services/Implements/WorkGridService.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs index 1072ded7..0a217deb 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs @@ -1,5 +1,6 @@ using Dlhis.Basic.WorkGrids.Request; using Dlhis.Basic.WorkGrids.Response; +using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Kurisu.AspNetCore.Authentication.Abstractions; using Kurisu.AspNetCore.DataAccess.Dto; @@ -66,8 +67,13 @@ public class WorkGridService : IWorkGridService /// public async Task> GetPageAsync(WorkGridPageRequest request) { + var role = _currentUser.GetRole(); + var userCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode); + var isAll = role is "admin" or "tenant-admin"; + return await _dbContext.Queryable() .LeftJoin((x, ga) => x.LeaderUserCode == ga.Code) + .WhereIF(!isAll, x => x.LeaderUserCode == userCode) .Select((x, ga) => new WorkGridPageResponse { Id = x.Id, From 6232ba468339c88e062bf64832958a8f3133f057 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Wed, 26 Feb 2025 12:13:47 +0800 Subject: [PATCH 15/25] =?UTF-8?q?fix=20=E4=BC=98=E5=8C=96=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/WorkGridsController.cs | 8 +++++--- .../WorkGrids/Request/WorkGridPageRequest.cs | 5 ++++- .../Response/WorkGridScheduleResponse.cs | 2 ++ .../Services/IWorkGridScheduleService.cs | 3 ++- .../Implements/WorkGridScheduleService.cs | 18 +++++++++++------- .../Services/Implements/WorkGridService.cs | 5 ++++- 6 files changed, 28 insertions(+), 13 deletions(-) diff --git a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs index d70e7666..f60a721a 100644 --- a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs +++ b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs @@ -1,6 +1,7 @@ using Dlhis.Basic.WorkGrids.Request; using Dlhis.Basic.WorkGrids.Response; using Dlhis.Basic.WorkGrids.Services; +using Dlhis.Entity.Basic.Enums; using Kurisu.AspNetCore.CustomClass; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop; @@ -129,15 +130,16 @@ public class WorkGridsController : ControllerBase } /// - /// 获取人网格员排班列表 + /// 获取网格员排班列表 /// /// 网格code /// + /// /// [HttpGet("user/schedule/list")] - public async Task> GetListAsync([FromQuery] Guid workGridCode, [FromQuery] DateTime date) + public async Task> GetListAsync([FromQuery] Guid workGridCode, [FromQuery] DateTime date, [FromQuery] WorkGridTimePeriodEnumType? periodType) { - return await _workGridScheduleService.GetListAsync(workGridCode, new DateOnly(date.Year, date.Month, date.Day)); + return await _workGridScheduleService.GetListAsync(workGridCode, new DateOnly(date.Year, date.Month, date.Day), periodType); } /// diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridPageRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridPageRequest.cs index 936ee923..e5a2a3d2 100644 --- a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridPageRequest.cs +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridPageRequest.cs @@ -4,5 +4,8 @@ namespace Dlhis.Basic.WorkGrids.Request; public class WorkGridPageRequest : PageDto { - + /// + /// 网格code,不传则取我的网格 + /// + public Guid? WorkGridCode { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleResponse.cs b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleResponse.cs index eddfad3e..34a61f34 100644 --- a/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleResponse.cs +++ b/Src/Dlhis.Basic/WorkGrids/Response/WorkGridScheduleResponse.cs @@ -9,4 +9,6 @@ public class WorkGridScheduleResponse public WorkGridTimePeriodEnumType PeriodType { get; set; } public string UserCode { get; set; } + + public string UserName { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs index df2d46fc..a1b04591 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs @@ -1,5 +1,6 @@ using Dlhis.Basic.WorkGrids.Request; using Dlhis.Basic.WorkGrids.Response; +using Dlhis.Entity.Basic.Enums; using Kurisu.AspNetCore.DataAccess.Dto; namespace Dlhis.Basic.WorkGrids.Services; @@ -11,7 +12,7 @@ public interface IWorkGridScheduleService : IScopeDependency { Task SaveAsync(WorkGridScheduleSaveRequest request); - Task> GetListAsync(Guid workGridCode, DateOnly date); + Task> GetListAsync(Guid workGridCode, DateOnly date, WorkGridTimePeriodEnumType? periodType); Task> GetListSummaryAsync(Guid workGridCode, DateOnly start, DateOnly end); diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs index 40c2d706..fe8ba3ff 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs @@ -1,6 +1,7 @@ using Dlhis.Basic.WorkGrids.Request; using Dlhis.Basic.WorkGrids.Response; using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Basic.Enums; using Dlhis.Entity.Device.Entities; using Dlhis.Jip.Api; using Dlhis.Jip.Api.Requests; @@ -17,7 +18,7 @@ public class WorkGridScheduleService : IWorkGridScheduleService private readonly IDbContext _dbContext; private readonly IJinkoJipApi _jinkoJipApi; - public WorkGridScheduleService(IDbContext dbContext ,IJinkoJipApi jinkoJipApi) + public WorkGridScheduleService(IDbContext dbContext, IJinkoJipApi jinkoJipApi) { _dbContext = dbContext; _jinkoJipApi = jinkoJipApi; @@ -53,15 +54,18 @@ public class WorkGridScheduleService : IWorkGridScheduleService } /// - public async Task> GetListAsync(Guid workGridCode, DateOnly date) + public async Task> GetListAsync(Guid workGridCode, DateOnly date, WorkGridTimePeriodEnumType? periodType) { return await _dbContext.Queryable() + .LeftJoin((x, ga) => x.UserCode == ga.Code) .Where(x => x.WorkGridCode == workGridCode && x.Date == date) - .Select(x => new WorkGridScheduleResponse + .WhereIF(periodType.HasValue, x => x.PeriodType == periodType) + .Select((x, ga) => new WorkGridScheduleResponse { Date = x.Date, PeriodType = x.PeriodType, - UserCode = x.UserCode + UserCode = x.UserCode, + UserName = ga.Name }) .ToListAsync(); } @@ -72,7 +76,7 @@ public class WorkGridScheduleService : IWorkGridScheduleService var workGridSchedules = await _dbContext.Queryable() .Where(x => x.WorkGridCode == workGridCode && x.Date >= start && x.Date <= end) .ToListAsync(); - + return workGridSchedules.GroupBy(x => x.Date).Select(x => { return new WorkGridScheduleSummaryResponse @@ -90,9 +94,9 @@ public class WorkGridScheduleService : IWorkGridScheduleService /// public async Task> GetAttendancePageAsync(WorkGridScheduleAttendancePageRequest request) { - return await _dbContext.Queryable() + return await _dbContext.Queryable() .LeftJoin((log, d) => log.DeviceUniqueNo == d.UniqueNo) - .Where(log => log.UserUniqueNo == request.UserCode ) + .Where(log => log.UserUniqueNo == request.UserCode) .WhereIF(request.DateTimePeriod.HasValue(), log => log.RaiseDateTime >= request.DateTimePeriod.Start && log.RaiseDateTime <= request.DateTimePeriod.End) .OrderBy(log => log.RaiseDateTime) diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs index 0a217deb..d41b1856 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs @@ -74,6 +74,7 @@ public class WorkGridService : IWorkGridService return await _dbContext.Queryable() .LeftJoin((x, ga) => x.LeaderUserCode == ga.Code) .WhereIF(!isAll, x => x.LeaderUserCode == userCode) + .WhereIF(request.Search.IsPresent(), x => x.Name.Contains(request.Search) || x.LeaderUserCode == request.Search) .Select((x, ga) => new WorkGridPageResponse { Id = x.Id, @@ -105,7 +106,8 @@ public class WorkGridService : IWorkGridService { var currentUserCode = _currentUser.GetUserClaim("jinko-code"); var myWorkGrid = await _dbContext.Queryable() - .Where(x => x.LeaderUserCode == currentUserCode) + .WhereIF(request.WorkGridCode.HasValue == false, x => x.LeaderUserCode == currentUserCode) + .WhereIF(request.WorkGridCode.HasValue, x => x.Code == request.WorkGridCode) .Select(x => new WorkGridUserPageResponse { Id = x.Id, @@ -115,6 +117,7 @@ public class WorkGridService : IWorkGridService UserInfos = SqlFunc.Subqueryable() .LeftJoin((p, ga) => p.UserCode == ga.Code) .Where((p, ga) => p.WorkGridCode == x.Code) + .WhereIF(request.Search.IsPresent(), (p, ga) => p.UserCode == request.Search || ga.Name.Contains(request.Search)) .ToList((p, ga) => new WorkGridUserPageDetailResponse { Code = p.UserCode, From 9dd558b2599646c4f299b39cb0785d6403af5a18 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Mon, 3 Mar 2025 10:01:38 +0800 Subject: [PATCH 16/25] =?UTF-8?q?add=20=E7=A7=BB=E9=99=A4=E4=BA=BA?= =?UTF-8?q?=E5=91=98=E6=8E=92=E7=8F=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/WorkGridsController.cs | 10 +++++++++ .../Request/WorkGridScheduleSaveRequest.cs | 12 +++++++++++ .../Services/IWorkGridScheduleService.cs | 2 ++ .../Implements/WorkGridScheduleService.cs | 21 ++++++++++++++++--- 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs index f60a721a..5010a29f 100644 --- a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs +++ b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs @@ -128,6 +128,16 @@ public class WorkGridsController : ControllerBase { await _workGridScheduleService.SaveAsync(request); } + + /// + /// 移除网格人员排班 + /// + /// + [HttpPost("user/schedule/remove")] + public async Task RemoveAsyncScheduleAsync(WorkGridScheduleSaveRequest request) + { + await _workGridScheduleService.RemoveAsync(request); + } /// /// 获取网格员排班列表 diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleSaveRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleSaveRequest.cs index dcede077..08b23358 100644 --- a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleSaveRequest.cs +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleSaveRequest.cs @@ -4,11 +4,23 @@ namespace Dlhis.Basic.WorkGrids.Request; public class WorkGridScheduleSaveRequest { + /// + /// 网格code + /// public Guid WorkGridCode { get; set; } + /// + /// 排班日期 + /// public DateOnly Date { get; set; } + /// + /// 班次 + /// public WorkGridTimePeriodEnumType PeriodType { get; set; } + /// + /// 人员codes + /// public List UserCodes { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs index a1b04591..5dfd2345 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/IWorkGridScheduleService.cs @@ -12,6 +12,8 @@ public interface IWorkGridScheduleService : IScopeDependency { Task SaveAsync(WorkGridScheduleSaveRequest request); + Task RemoveAsync(WorkGridScheduleSaveRequest request); + Task> GetListAsync(Guid workGridCode, DateOnly date, WorkGridTimePeriodEnumType? periodType); Task> GetListSummaryAsync(Guid workGridCode, DateOnly start, DateOnly end); diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs index fe8ba3ff..740f7504 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs @@ -27,12 +27,14 @@ public class WorkGridScheduleService : IWorkGridScheduleService public async Task SaveAsync(WorkGridScheduleSaveRequest request) { var exists = await _dbContext.Queryable() - .Where(x => x.Date == request.Date) + .Where(x => x.WorkGridCode == request.WorkGridCode + && x.Date == request.Date + && request.UserCodes.Contains(x.UserCode) + ) .Where(x => x.PeriodType != request.PeriodType) - .Where(x => request.UserCodes.Contains(x.UserCode)) .AnyAsync(); - exists.ThrowIfTrue($"存在已经分配的人员"); + exists.ThrowIfTrue("当天已经存在排班人员"); var data = await _dbContext.Queryable() .Where(x => x.WorkGridCode == request.WorkGridCode) @@ -53,6 +55,19 @@ public class WorkGridScheduleService : IWorkGridScheduleService await _dbContext.InsertAsync(toInserts); } + /// + public async Task RemoveAsync(WorkGridScheduleSaveRequest request) + { + var data = await _dbContext.Queryable() + .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.DeleteReallyAsync(data); + } + /// public async Task> GetListAsync(Guid workGridCode, DateOnly date, WorkGridTimePeriodEnumType? periodType) { From d16ce92d638abad040e0af8ef5736268d8404d88 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Mon, 3 Mar 2025 10:18:14 +0800 Subject: [PATCH 17/25] =?UTF-8?q?fix=20=E7=A7=BB=E9=99=A4=E8=A6=86?= =?UTF-8?q?=E7=9B=96=E5=BC=8Fsave?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/Implements/WorkGridScheduleService.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs index 740f7504..b42ba1f4 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs @@ -28,22 +28,14 @@ public class WorkGridScheduleService : IWorkGridScheduleService { var exists = await _dbContext.Queryable() .Where(x => x.WorkGridCode == request.WorkGridCode + && x.PeriodType == request.PeriodType && x.Date == request.Date && request.UserCodes.Contains(x.UserCode) ) - .Where(x => x.PeriodType != request.PeriodType) .AnyAsync(); exists.ThrowIfTrue("当天已经存在排班人员"); - var data = await _dbContext.Queryable() - .Where(x => x.WorkGridCode == request.WorkGridCode) - .Where(x => x.Date == request.Date) - .Where(x => x.PeriodType == request.PeriodType) - .ToListAsync(); - - await _dbContext.DeleteReallyAsync(data); - var toInserts = request.UserCodes.Select(x => new WorkGridScheduleEntity { WorkGridCode = request.WorkGridCode, From 1c1b258e84580c5343dd588a7800e6b1cda8122d Mon Sep 17 00:00:00 2001 From: liguoyang Date: Mon, 3 Mar 2025 11:32:36 +0800 Subject: [PATCH 18/25] fix fromquery --- Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs index 5010a29f..c97f7c86 100644 --- a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs +++ b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs @@ -128,7 +128,7 @@ public class WorkGridsController : ControllerBase { await _workGridScheduleService.SaveAsync(request); } - + /// /// 移除网格人员排班 /// @@ -172,7 +172,7 @@ public class WorkGridsController : ControllerBase /// /// [HttpGet("user/attendance/page")] - public async Task> GetAttendancePageAsync(WorkGridScheduleAttendancePageRequest request) + public async Task> GetAttendancePageAsync([FromQuery] WorkGridScheduleAttendancePageRequest request) { return await _workGridScheduleService.GetAttendancePageAsync(request); } From d07755b9fbaf166b015b5bdde7d5bca6b92da360 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Mon, 3 Mar 2025 16:40:36 +0800 Subject: [PATCH 19/25] =?UTF-8?q?fix=20=E5=90=8C=E6=AD=A5=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E6=8E=92=E7=8F=AD=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs | 1 + .../WorkGrids/Services/Implements/WorkGridService.cs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs index c97f7c86..17cd70db 100644 --- a/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs +++ b/Src/Dlhis.Basic/WorkGrids/Controllers/WorkGridsController.cs @@ -114,6 +114,7 @@ public class WorkGridsController : ControllerBase /// /// [HttpPost("user/remove")] + [Transactional] public async Task RemoveUsersFromWorkGridAsync(WorkGridUserRemoveRequest request) { await _workGridService.RemoveAsync(request); diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs index d41b1856..c01d8c73 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs @@ -171,6 +171,11 @@ public class WorkGridService : IWorkGridService .Where(x => request.UserCodes.Contains(x.UserCode)) .ToListAsync(); + var workGridSchedules = await _dbContext.Queryable().Where(x => x.WorkGridCode == myWorkGrid.Code) + .Where(x => request.UserCodes.Contains(x.UserCode)) + .ToListAsync(); + await _dbContext.DeleteReallyAsync(workGridUsers); + await _dbContext.DeleteReallyAsync(workGridSchedules); } } \ No newline at end of file From 7574900cc20208df9f3f8b567689f84443481727 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Mon, 3 Mar 2025 18:22:54 +0800 Subject: [PATCH 20/25] =?UTF-8?q?add=20=E6=93=8D=E4=BD=9C=E6=97=A5?= =?UTF-8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Common/ApiLog/Services/ApiLogService.cs | 3 +-- .../Common/ApiLog/Services/IOperateLog.cs | 9 +++++++ .../Services/Implements/OperateLogService.cs | 25 +++++++++++++++++++ .../Services/Implements/FileVersionService.cs | 2 +- .../Implements/WorkGridScheduleService.cs | 15 ++++++++++- .../Services/Implements/WorkGridService.cs | 21 +++++++++++++++- .../Implements/WorkGridTimePeriodService.cs | 12 ++++++--- .../Basic/Entity/WorkGridEntity.cs | 1 + .../Basic/Entity/WorkGridTimePeriodEntity.cs | 4 +-- .../Common/{ => Entities}/ApiLogEntity.cs | 4 +-- .../{ => Entities}/FileVersionEntity.cs | 2 +- .../Common/Entities/OperateLogEntity.cs | 21 ++++++++++++++++ .../Common/Enums/OperateLogType.cs | 10 ++++++++ .../Jobs/DeleteApiLogTaskJob.cs | 2 +- 14 files changed, 116 insertions(+), 15 deletions(-) create mode 100644 Src/Dlhis.Basic/Common/ApiLog/Services/IOperateLog.cs create mode 100644 Src/Dlhis.Basic/Common/ApiLog/Services/Implements/OperateLogService.cs rename Src/Dlhis.Entity/Common/{ => Entities}/ApiLogEntity.cs (97%) rename Src/Dlhis.Entity/Common/{ => Entities}/FileVersionEntity.cs (96%) create mode 100644 Src/Dlhis.Entity/Common/Entities/OperateLogEntity.cs create mode 100644 Src/Dlhis.Entity/Common/Enums/OperateLogType.cs diff --git a/Src/Dlhis.Basic/Common/ApiLog/Services/ApiLogService.cs b/Src/Dlhis.Basic/Common/ApiLog/Services/ApiLogService.cs index 8474b220..d03cfb02 100644 --- a/Src/Dlhis.Basic/Common/ApiLog/Services/ApiLogService.cs +++ b/Src/Dlhis.Basic/Common/ApiLog/Services/ApiLogService.cs @@ -1,10 +1,9 @@ using Dlhis.Basic.Common.ApiLog.Request; using Dlhis.Basic.Common.ApiLog.Response; using Dlhis.Basic.Common.ApiLog.Services.Implements; -using Dlhis.Entity.Common; +using Dlhis.Entity.Common.Entities; 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; diff --git a/Src/Dlhis.Basic/Common/ApiLog/Services/IOperateLog.cs b/Src/Dlhis.Basic/Common/ApiLog/Services/IOperateLog.cs new file mode 100644 index 00000000..1b572870 --- /dev/null +++ b/Src/Dlhis.Basic/Common/ApiLog/Services/IOperateLog.cs @@ -0,0 +1,9 @@ +using Dlhis.Entity.Common.Enums; + +namespace Dlhis.Basic.Common.ApiLog.Services; + +public interface IOperateLog : IScopeDependency +{ + Task LogAsync(OperateLogType type, string content); +} + diff --git a/Src/Dlhis.Basic/Common/ApiLog/Services/Implements/OperateLogService.cs b/Src/Dlhis.Basic/Common/ApiLog/Services/Implements/OperateLogService.cs new file mode 100644 index 00000000..68b91673 --- /dev/null +++ b/Src/Dlhis.Basic/Common/ApiLog/Services/Implements/OperateLogService.cs @@ -0,0 +1,25 @@ +using Dlhis.Entity.Common.Entities; +using Dlhis.Entity.Common.Enums; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; + +namespace Dlhis.Basic.Common.ApiLog.Services.Implements; + +public class OperateLogService : IOperateLog +{ + private readonly IDbContext _dbContext; + + public OperateLogService(IDbContext dbContext) + { + _dbContext = dbContext.ChangeDb("log"); + } + + /// + public async Task LogAsync(OperateLogType type, string content) + { + await _dbContext.InsertAsync(new OperateLogEntity + { + Type = type, + Content = content + }); + } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/Common/FileOperation/Services/Implements/FileVersionService.cs b/Src/Dlhis.Basic/Common/FileOperation/Services/Implements/FileVersionService.cs index 9c896eef..9dfa8c20 100644 --- a/Src/Dlhis.Basic/Common/FileOperation/Services/Implements/FileVersionService.cs +++ b/Src/Dlhis.Basic/Common/FileOperation/Services/Implements/FileVersionService.cs @@ -1,6 +1,6 @@ using Dlhis.Basic.Common.FileOperation.Request; using Dlhis.Basic.Common.FileOperation.Response; -using Dlhis.Entity.Common; +using Dlhis.Entity.Common.Entities; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs index b42ba1f4..ebf66e67 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs @@ -1,7 +1,9 @@ +using Dlhis.Basic.Common.ApiLog.Services; using Dlhis.Basic.WorkGrids.Request; using Dlhis.Basic.WorkGrids.Response; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Basic.Enums; +using Dlhis.Entity.Common.Enums; using Dlhis.Entity.Device.Entities; using Dlhis.Jip.Api; using Dlhis.Jip.Api.Requests; @@ -17,15 +19,20 @@ public class WorkGridScheduleService : IWorkGridScheduleService { private readonly IDbContext _dbContext; private readonly IJinkoJipApi _jinkoJipApi; + private readonly IOperateLog _operateLog; - public WorkGridScheduleService(IDbContext dbContext, IJinkoJipApi jinkoJipApi) + public WorkGridScheduleService(IDbContext dbContext, IJinkoJipApi jinkoJipApi, IOperateLog operateLog) { _dbContext = dbContext; _jinkoJipApi = jinkoJipApi; + _operateLog = operateLog; } public async Task SaveAsync(WorkGridScheduleSaveRequest request) { + var workGrid = await _dbContext.Queryable().SingleAsync(x => x.Code == request.WorkGridCode); + workGrid.ThrowIfNull("工作网格不存在"); + var exists = await _dbContext.Queryable() .Where(x => x.WorkGridCode == request.WorkGridCode && x.PeriodType == request.PeriodType @@ -45,11 +52,16 @@ public class WorkGridScheduleService : IWorkGridScheduleService }).ToList(); await _dbContext.InsertAsync(toInserts); + + await _operateLog.LogAsync(OperateLogType.WorkGrid, $"新增网格({workGrid.Name}){request.Date.ToString("yyyy-M-d")}的{request.PeriodType.GetDescription()}人员:{request.UserCodes.Join(",")}"); } /// public async Task RemoveAsync(WorkGridScheduleSaveRequest request) { + var workGrid = await _dbContext.Queryable().SingleAsync(x => x.Code == request.WorkGridCode); + workGrid.ThrowIfNull("工作网格不存在"); + var data = await _dbContext.Queryable() .Where(x => x.WorkGridCode == request.WorkGridCode) .Where(x => x.Date == request.Date) @@ -58,6 +70,7 @@ public class WorkGridScheduleService : IWorkGridScheduleService .ToListAsync(); await _dbContext.DeleteReallyAsync(data); + await _operateLog.LogAsync(OperateLogType.WorkGrid, $"移除网格({workGrid.Name}){request.Date.ToString("yyyy-M-d")}的{request.PeriodType.GetDescription()}人员:{request.UserCodes.Join(",")}"); } /// diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs index c01d8c73..9a7c27de 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs @@ -1,7 +1,9 @@ +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.Common.Enums; using Kurisu.AspNetCore.Authentication.Abstractions; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; @@ -16,16 +18,21 @@ public class WorkGridService : IWorkGridService { private readonly IDbContext _dbContext; private readonly ICurrentUser _currentUser; + private readonly IOperateLog _operateLog; - public WorkGridService(IDbContext dbContext, ICurrentUser currentUser) + public WorkGridService(IDbContext dbContext, ICurrentUser currentUser, IOperateLog operateLog) { _dbContext = dbContext; _currentUser = currentUser; + _operateLog = operateLog; } /// public async Task SaveAsync(List requests) { + var insertGrids = new List(); + var updateGrids = new List(); + foreach (var request in requests) { var exists = await _dbContext.Queryable() @@ -53,15 +60,22 @@ public class WorkGridService : IWorkGridService entity.Code = Guid.NewGuid(); await _dbContext.InsertAsync(entity); + insertGrids.Add($"{entity.Name}({entity.LeaderUserCode})"); } else { var entity = await _dbContext.Queryable().Where(x => x.Id == request.Id).SingleAsync(); + entity.ThrowIfNull("网格不存在"); + + updateGrids.Add($"{entity.Name}->{request.Name}"); request.Adapt(entity); await _dbContext.UpdateAsync(entity); } } + + await _operateLog.LogAsync(OperateLogType.WorkGrid, "创建网格:" + insertGrids.Join("\r\n")); + await _operateLog.LogAsync(OperateLogType.WorkGrid, "修改网格:" + updateGrids.Join("\r\n")); } /// @@ -99,6 +113,8 @@ public class WorkGridService : IWorkGridService workGrid.LeaderUserCode = to; await _dbContext.UpdateAsync(workGrid); + + await _operateLog.LogAsync(OperateLogType.WorkGrid, $"网格({workGrid.Name})修改负责人{from}->{to}"); } /// @@ -158,6 +174,7 @@ public class WorkGridService : IWorkGridService }).ToList(); await _dbContext.InsertAsync(dataToInserts); + await _operateLog.LogAsync(OperateLogType.WorkGrid, $"分配人员到网格({myWorkGrid.Name}),人员:{dataToInserts.Select(x => x.UserCode).Join(",")}"); } /// @@ -177,5 +194,7 @@ public class WorkGridService : IWorkGridService await _dbContext.DeleteReallyAsync(workGridUsers); await _dbContext.DeleteReallyAsync(workGridSchedules); + + await _operateLog.LogAsync(OperateLogType.WorkGrid, $"从网格({myWorkGrid.Name})移除人员:{request.UserCodes.Join(",")}"); } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs index 01d4dcc6..e59c4ac0 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs @@ -1,8 +1,9 @@ +using Dlhis.Basic.Common.ApiLog.Services; using Dlhis.Basic.WorkGrids.Request; using Dlhis.Basic.WorkGrids.Response; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Basic.Enums; -using Kurisu.AspNetCore.CustomClass; +using Dlhis.Entity.Common.Enums; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; @@ -14,10 +15,12 @@ namespace Dlhis.Basic.WorkGrids.Services.Implements; public class WorkGridTimePeriodService : IWorkGridTimePeriodService { private readonly IDbContext _dbContext; + private readonly IOperateLog _operateLog; - public WorkGridTimePeriodService(IDbContext dbContext) + public WorkGridTimePeriodService(IDbContext dbContext, IOperateLog operateLog) { _dbContext = dbContext; + _operateLog = operateLog; } /// @@ -37,13 +40,16 @@ public class WorkGridTimePeriodService : IWorkGridTimePeriodService var data = request.Adapt(); data.Type = request.Type; await _dbContext.InsertAsync(data); + + await _operateLog.LogAsync(OperateLogType.WorkGrid, $"创建网格时间配置:{request.ToJson()}"); } else { var entity = await _dbContext.Queryable().Where(x => x.Id == request.Id).SingleAsync(); + var log = $"修改网格时间配置:{entity.ToJson()}->{request.ToJson()}"; request.Adapt(entity); - await _dbContext.UpdateAsync(entity); + await _operateLog.LogAsync(OperateLogType.WorkGrid, log); } } diff --git a/Src/Dlhis.Entity/Basic/Entity/WorkGridEntity.cs b/Src/Dlhis.Entity/Basic/Entity/WorkGridEntity.cs index f616edcf..d1ff88ff 100644 --- a/Src/Dlhis.Entity/Basic/Entity/WorkGridEntity.cs +++ b/Src/Dlhis.Entity/Basic/Entity/WorkGridEntity.cs @@ -26,6 +26,7 @@ public class WorkGridEntity : SugarBaseEntity /// /// 负责人工号 /// + [AdaptIgnore(MemberSide.Destination)] [SugarColumn(IsNullable = false, ColumnDescription = "负责人工号", UniqueGroupNameList = new[] { "idx_WorkGrid_LeaderUserCode" })] public string LeaderUserCode { get; set; } diff --git a/Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs b/Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs index 721823da..b13e0512 100644 --- a/Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs +++ b/Src/Dlhis.Entity/Basic/Entity/WorkGridTimePeriodEntity.cs @@ -41,8 +41,6 @@ public class WorkGridTimePeriodEntity : SugarBaseEntity, ITenantId /// [SugarColumn(IsNullable = false, ColumnDataType = "date")] public TimeOnly End { get; set; } - - - [SugarColumn(UniqueGroupNameList = new[] { "idx_workGridTimePeriod_type_tenantId" })] + public string TenantId { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Common/ApiLogEntity.cs b/Src/Dlhis.Entity/Common/Entities/ApiLogEntity.cs similarity index 97% rename from Src/Dlhis.Entity/Common/ApiLogEntity.cs rename to Src/Dlhis.Entity/Common/Entities/ApiLogEntity.cs index 6b5132d7..5d40e0dd 100644 --- a/Src/Dlhis.Entity/Common/ApiLogEntity.cs +++ b/Src/Dlhis.Entity/Common/Entities/ApiLogEntity.cs @@ -1,9 +1,9 @@ using Kurisu.AspNetCore.DataAccess.SqlSugar; +using Microsoft.Extensions.Logging; using SqlSugar; using SqlSugar.DbConvert; -using Microsoft.Extensions.Logging; -namespace Dlhis.Entity.Common; +namespace Dlhis.Entity.Common.Entities; /// /// api日志表 diff --git a/Src/Dlhis.Entity/Common/FileVersionEntity.cs b/Src/Dlhis.Entity/Common/Entities/FileVersionEntity.cs similarity index 96% rename from Src/Dlhis.Entity/Common/FileVersionEntity.cs rename to Src/Dlhis.Entity/Common/Entities/FileVersionEntity.cs index 006656ca..50819373 100644 --- a/Src/Dlhis.Entity/Common/FileVersionEntity.cs +++ b/Src/Dlhis.Entity/Common/Entities/FileVersionEntity.cs @@ -1,7 +1,7 @@ using Kurisu.AspNetCore.DataAccess.SqlSugar; using SqlSugar; -namespace Dlhis.Entity.Common; +namespace Dlhis.Entity.Common.Entities; /// /// 文件版本信息 diff --git a/Src/Dlhis.Entity/Common/Entities/OperateLogEntity.cs b/Src/Dlhis.Entity/Common/Entities/OperateLogEntity.cs new file mode 100644 index 00000000..2f9f724e --- /dev/null +++ b/Src/Dlhis.Entity/Common/Entities/OperateLogEntity.cs @@ -0,0 +1,21 @@ +using Dlhis.Entity.Common.Enums; +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using SqlSugar; +using SqlSugar.DbConvert; + +namespace Dlhis.Entity.Common.Entities; + +[SugarTable(TableName = "OperateLogs")] +public class OperateLogEntity : SugarBaseEntity +{ + [SugarColumn(IsNullable = false, SqlParameterDbType = typeof(EnumToStringConvert))] + public OperateLogType Type { get; set; } + + + [SugarColumn(IsNullable = true, ColumnDataType = "text")] + public string Request { get; set; } + + + [SugarColumn(IsNullable = false)] + public string Content { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Common/Enums/OperateLogType.cs b/Src/Dlhis.Entity/Common/Enums/OperateLogType.cs new file mode 100644 index 00000000..ee72d243 --- /dev/null +++ b/Src/Dlhis.Entity/Common/Enums/OperateLogType.cs @@ -0,0 +1,10 @@ +using System.ComponentModel; + +namespace Dlhis.Entity.Common.Enums; + +[Description("操作日志类型")] +public enum OperateLogType +{ + [Description("工作网格")] + WorkGrid +} \ No newline at end of file diff --git a/Src/Dlhis.ScheduledTask/Jobs/DeleteApiLogTaskJob.cs b/Src/Dlhis.ScheduledTask/Jobs/DeleteApiLogTaskJob.cs index 3a4652b3..094e3954 100644 --- a/Src/Dlhis.ScheduledTask/Jobs/DeleteApiLogTaskJob.cs +++ b/Src/Dlhis.ScheduledTask/Jobs/DeleteApiLogTaskJob.cs @@ -1,4 +1,4 @@ -using Dlhis.Entity.Common; +using Dlhis.Entity.Common.Entities; using Dlhis.ScheduledTask.Attributes; namespace Dlhis.ScheduledTask.Jobs; From 045459575a867bce17e59c5f0df2a31c05de0d42 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 4 Mar 2025 10:13:04 +0800 Subject: [PATCH 21/25] =?UTF-8?q?add=20log=E8=BF=9E=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Src/Dlhis.Basic/appsettings.json | 1 + Src/Dlhis.Entity/SqlSugarPack.cs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Src/Dlhis.Basic/appsettings.json b/Src/Dlhis.Basic/appsettings.json index 23a2cff2..b5669e14 100644 --- a/Src/Dlhis.Basic/appsettings.json +++ b/Src/Dlhis.Basic/appsettings.json @@ -23,6 +23,7 @@ "SqlSugarOptions": { "DefaultConnectionString": "server=192.168.199.124;port=3306;userid=root;password=dlhis123;database=yikatong;charset=utf8mb4;", "SlaveConnectionString": [], + "LogConnectionString": "server=192.168.199.124;port=3306;userid=root;password=dlhis123;database=log;charset=utf8mb4;", "IdentityConnectionString": "server=192.168.199.124;port=3306;userid=root;password=dlhis123;database=identity;charset=utf8mb4;", "FaceConnectionString": "server=192.168.199.124;port=3306;userid=root;password=dlhis123;database=face;charset=utf8mb4;", "Timeout": 30, diff --git a/Src/Dlhis.Entity/SqlSugarPack.cs b/Src/Dlhis.Entity/SqlSugarPack.cs index efc5cd1c..b12e24c1 100644 --- a/Src/Dlhis.Entity/SqlSugarPack.cs +++ b/Src/Dlhis.Entity/SqlSugarPack.cs @@ -1,5 +1,5 @@ using Dlhis.Entity.Basic.Entity; -using Dlhis.Entity.Device.Entities; +using Dlhis.Entity.Common.Entities; using Kurisu.AspNetCore; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; @@ -102,5 +102,11 @@ public class SqlSugarPack : BaseAppPack var faceDb = db.ChangeDb("face"); faceDb.Client.DbMaintenance.CreateDatabase(); faceDb.Client.CodeFirst.InitTables(); + + + var logDb = db.ChangeDb("log"); + + logDb.Client.DbMaintenance.CreateDatabase(); + logDb.Client.CodeFirst.InitTables(); } } \ No newline at end of file From 9f566d016d743845294d709b135ec856b639efa3 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 4 Mar 2025 10:27:20 +0800 Subject: [PATCH 22/25] =?UTF-8?q?fix=20=E4=BC=98=E5=8C=96=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/Implements/OperateLogService.cs | 31 ++++++++++++++++--- .../Services/Implements/WorkGridService.cs | 2 +- .../Common/Entities/OperateLogEntity.cs | 12 +++---- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/Src/Dlhis.Basic/Common/ApiLog/Services/Implements/OperateLogService.cs b/Src/Dlhis.Basic/Common/ApiLog/Services/Implements/OperateLogService.cs index 68b91673..3081ccbf 100644 --- a/Src/Dlhis.Basic/Common/ApiLog/Services/Implements/OperateLogService.cs +++ b/Src/Dlhis.Basic/Common/ApiLog/Services/Implements/OperateLogService.cs @@ -1,25 +1,46 @@ using Dlhis.Entity.Common.Entities; using Dlhis.Entity.Common.Enums; +using Kurisu.AspNetCore.Authentication.Abstractions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; namespace Dlhis.Basic.Common.ApiLog.Services.Implements; public class OperateLogService : IOperateLog { + private readonly ICurrentUser _currentUser; + private readonly ILogger _logger; private readonly IDbContext _dbContext; - public OperateLogService(IDbContext dbContext) + public OperateLogService(IDbContext dbContext, ICurrentUser currentUser, ILogger logger) { + _currentUser = currentUser; + _logger = logger; _dbContext = dbContext.ChangeDb("log"); } /// public async Task LogAsync(OperateLogType type, string content) { - await _dbContext.InsertAsync(new OperateLogEntity + var now = DateTime.Now; + var userId = _currentUser.GetIntSubjectId(); + var userName = _currentUser.GetName(); + + try { - Type = type, - Content = content - }); + await _dbContext.InsertAsync(new OperateLogEntity + { + Type = type, + Content = content, + Operator = userName, + CreateTime = now, + ModifiedTime = now, + CreatedBy = userId, + ModifiedBy = userId + }); + } + catch (Exception e) + { + _logger.LogError(e, "记录操作日志失败:{error}", e.Message); + } } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs index 9a7c27de..9b6c977a 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs @@ -149,7 +149,7 @@ public class WorkGridService : IWorkGridService public async Task AssignAsync(WorkGridUserAssignRequest request) { var currentFactory = _currentUser.GetStringTenantId(); - var currentUserCode = _currentUser.GetUserClaim("jinko-code"); + var currentUserCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode); var myWorkGrid = await _dbContext.Queryable().Where(x => x.LeaderUserCode == currentUserCode).SingleAsync(); myWorkGrid.ThrowIfNull("工作网格尚未配置,请联系管理员"); diff --git a/Src/Dlhis.Entity/Common/Entities/OperateLogEntity.cs b/Src/Dlhis.Entity/Common/Entities/OperateLogEntity.cs index 2f9f724e..b8080855 100644 --- a/Src/Dlhis.Entity/Common/Entities/OperateLogEntity.cs +++ b/Src/Dlhis.Entity/Common/Entities/OperateLogEntity.cs @@ -5,17 +5,17 @@ using SqlSugar.DbConvert; namespace Dlhis.Entity.Common.Entities; -[SugarTable(TableName = "OperateLogs")] +[SugarTable(TableName = "OperateLogs", TableDescription = "操作日志")] public class OperateLogEntity : SugarBaseEntity { - [SugarColumn(IsNullable = false, SqlParameterDbType = typeof(EnumToStringConvert))] + [SugarColumn(IsNullable = false, ColumnDataType = "varchar(50)", SqlParameterDbType = typeof(EnumToStringConvert))] public OperateLogType Type { get; set; } - [SugarColumn(IsNullable = true, ColumnDataType = "text")] - public string Request { get; set; } - + [SugarColumn(IsNullable = false, ColumnDataType = "text")] + public string Content { get; set; } + [SugarColumn(IsNullable = false)] - public string Content { get; set; } + public string Operator { get; set; } } \ No newline at end of file From 860591570eefdcebef690e67a14dad70920d42bf Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 4 Mar 2025 15:02:00 +0800 Subject: [PATCH 23/25] =?UTF-8?q?fix=20=E9=80=BB=E8=BE=91=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controller/OperateLogsController.cs | 36 +++++++++++++ .../ApiLog/Request/OperateLogPageRequest.cs | 9 ++++ .../ApiLog/Response/OperateLogResponse.cs | 10 ++++ .../Common/ApiLog/Services/IOperateLog.cs | 5 ++ .../Services/Implements/OperateLogService.cs | 17 +++++++ .../Services/IFactorySettingService.cs | 6 +++ .../Implements/FactorySettingService.cs | 37 +++++++++++++- .../WorkGridScheduleAttendancePageRequest.cs | 1 - .../Request/WorkGridScheduleSaveRequest.cs | 13 ++++- .../Implements/WorkGridScheduleService.cs | 37 ++++++++++++-- .../Services/Implements/WorkGridService.cs | 50 ++++++++++++------- .../Implements/WorkGridTimePeriodService.cs | 13 ----- .../Basic/Entity/WorkGridScheduleEntity.cs | 15 ++---- .../Basic/Entity/WorkGridUserEntity.cs | 16 +----- .../Sys/Entities/FactorySettingEntity.cs | 7 ++- 15 files changed, 208 insertions(+), 64 deletions(-) create mode 100644 Src/Dlhis.Basic/Common/ApiLog/Controller/OperateLogsController.cs create mode 100644 Src/Dlhis.Basic/Common/ApiLog/Request/OperateLogPageRequest.cs create mode 100644 Src/Dlhis.Basic/Common/ApiLog/Response/OperateLogResponse.cs diff --git a/Src/Dlhis.Basic/Common/ApiLog/Controller/OperateLogsController.cs b/Src/Dlhis.Basic/Common/ApiLog/Controller/OperateLogsController.cs new file mode 100644 index 00000000..8388bf35 --- /dev/null +++ b/Src/Dlhis.Basic/Common/ApiLog/Controller/OperateLogsController.cs @@ -0,0 +1,36 @@ +using Dlhis.Basic.Common.ApiLog.Request; +using Dlhis.Basic.Common.ApiLog.Response; +using Dlhis.Basic.Common.ApiLog.Services; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.UnifyResultAndValidation.Aop; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Dlhis.Basic.Common.ApiLog.Controller; + +/// +/// API日志控制器 +/// +[Authorize] +[Route("api/[controller]")] +[ApiController] +public class OperateLogsController : ControllerBase +{ + private readonly IOperateLog _operateLog; + + public OperateLogsController(IOperateLog operateLog) + { + _operateLog = operateLog; + } + + /// + /// 获取操作日志 + /// + /// + [DisableApiLog] + [HttpGet("page")] + public async Task> GetOperateLogPageAsync([FromQuery] OperateLogPageRequest request) + { + return await _operateLog.GetOperateLogPageAsync(request); + } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/Common/ApiLog/Request/OperateLogPageRequest.cs b/Src/Dlhis.Basic/Common/ApiLog/Request/OperateLogPageRequest.cs new file mode 100644 index 00000000..72ad0a4c --- /dev/null +++ b/Src/Dlhis.Basic/Common/ApiLog/Request/OperateLogPageRequest.cs @@ -0,0 +1,9 @@ +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Basic.Common.ApiLog.Request +{ + public class OperateLogPageRequest : PageDto + { + + } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/Common/ApiLog/Response/OperateLogResponse.cs b/Src/Dlhis.Basic/Common/ApiLog/Response/OperateLogResponse.cs new file mode 100644 index 00000000..e1593e98 --- /dev/null +++ b/Src/Dlhis.Basic/Common/ApiLog/Response/OperateLogResponse.cs @@ -0,0 +1,10 @@ +namespace Dlhis.Basic.Common.ApiLog.Response; + +public class OperateLogResponse +{ + public string Content { get; set; } + + public string Operator { get; set; } + + public DateTime CreateTime { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/Common/ApiLog/Services/IOperateLog.cs b/Src/Dlhis.Basic/Common/ApiLog/Services/IOperateLog.cs index 1b572870..36f637a4 100644 --- a/Src/Dlhis.Basic/Common/ApiLog/Services/IOperateLog.cs +++ b/Src/Dlhis.Basic/Common/ApiLog/Services/IOperateLog.cs @@ -1,9 +1,14 @@ +using Dlhis.Basic.Common.ApiLog.Request; +using Dlhis.Basic.Common.ApiLog.Response; using Dlhis.Entity.Common.Enums; +using Kurisu.AspNetCore.DataAccess.Dto; namespace Dlhis.Basic.Common.ApiLog.Services; public interface IOperateLog : IScopeDependency { Task LogAsync(OperateLogType type, string content); + + Task> GetOperateLogPageAsync(OperateLogPageRequest request); } diff --git a/Src/Dlhis.Basic/Common/ApiLog/Services/Implements/OperateLogService.cs b/Src/Dlhis.Basic/Common/ApiLog/Services/Implements/OperateLogService.cs index 3081ccbf..b2a26087 100644 --- a/Src/Dlhis.Basic/Common/ApiLog/Services/Implements/OperateLogService.cs +++ b/Src/Dlhis.Basic/Common/ApiLog/Services/Implements/OperateLogService.cs @@ -1,6 +1,10 @@ +using Dlhis.Basic.Common.ApiLog.Request; +using Dlhis.Basic.Common.ApiLog.Response; using Dlhis.Entity.Common.Entities; using Dlhis.Entity.Common.Enums; using Kurisu.AspNetCore.Authentication.Abstractions; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; namespace Dlhis.Basic.Common.ApiLog.Services.Implements; @@ -43,4 +47,17 @@ public class OperateLogService : IOperateLog _logger.LogError(e, "记录操作日志失败:{error}", e.Message); } } + + /// + public async Task> GetOperateLogPageAsync(OperateLogPageRequest request) + { + return await _dbContext.Queryable() + .Select(x => new OperateLogResponse + { + Content = x.Content, + Operator = x.Operator, + CreateTime = x.CreateTime + }) + .ToPageListAsync(request); + } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/Organization/Services/IFactorySettingService.cs b/Src/Dlhis.Basic/Organization/Services/IFactorySettingService.cs index f37f7803..e004fd5e 100644 --- a/Src/Dlhis.Basic/Organization/Services/IFactorySettingService.cs +++ b/Src/Dlhis.Basic/Organization/Services/IFactorySettingService.cs @@ -10,4 +10,10 @@ public interface IFactorySettingService : IScopeDependency Task SaveAsync(FactorySettingSaveRequest request); Task GetFactorySettingAsync(string factory, bool usePermission); + + Task GetWorkGridSetLimitAsync(); + + Task CheckWorkGridSetLimitAsync(DateOnly date); + + Task IsWorkGridSetLimitAsync(DateOnly date); } \ No newline at end of file diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/FactorySettingService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/FactorySettingService.cs index 104d2fdb..485a2c8b 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/FactorySettingService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/FactorySettingService.cs @@ -6,9 +6,11 @@ using Dlhis.Entity.Basic.Enums; using Dlhis.Entity.Sys.Entities; using Dlhis.Sys.Api; using Dlhis.Sys.Api.Response; +using Kurisu.AspNetCore.Authentication.Abstractions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using Kurisu.AspNetCore.Utils.Extensions; using Mapster; +using SqlSugar; namespace Dlhis.Basic.Organization.Services.Implements; @@ -16,11 +18,13 @@ public class FactorySettingService : IFactorySettingService { private readonly IDbContext _dbContext; private readonly ITenantApi _tenantApi; + private readonly ICurrentUser _currentUser; - public FactorySettingService(IDbContext dbContext, ITenantApi tenantApi) + public FactorySettingService(IDbContext dbContext, ITenantApi tenantApi, ICurrentUser currentUser) { _dbContext = dbContext; _tenantApi = tenantApi; + _currentUser = currentUser; } public async Task> GetListAsync(bool usePermission) @@ -67,6 +71,37 @@ public class FactorySettingService : IFactorySettingService return setting; } + /// + public async Task GetWorkGridSetLimitAsync() + { + var factory = _currentUser.GetStringTenantId(); + var v = new TimeOnly(20, 30, 0); + + var vv = await _dbContext.Queryable() + .Where(x => x.TenantId == factory) + .Select(x => SqlFunc.IsNull(x.WorkGridSetLimit, v)) + .SingleAsync(); + + return vv!.Value; + } + + /// + public async Task CheckWorkGridSetLimitAsync(DateOnly date) + { + var result = await IsWorkGridSetLimitAsync(date); + result.ThrowIfTrue("当前时间不可编辑"); + } + + /// + public async Task IsWorkGridSetLimitAsync(DateOnly date) + { + var now = DateTime.Now; + var time = await GetWorkGridSetLimitAsync(); + var setting = date.ToDateTime(time); + + return now >= setting; + } + //************************************************************************************************************************************************************ private async Task> GetFactorySettingsAsync(string factory, bool usePermission) diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleAttendancePageRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleAttendancePageRequest.cs index bc783d40..fcf0ae17 100644 --- a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleAttendancePageRequest.cs +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleAttendancePageRequest.cs @@ -6,7 +6,6 @@ namespace Dlhis.Basic.WorkGrids.Request; public class WorkGridScheduleAttendancePageRequest : PageDto { - [Required(ErrorMessage = "工号不能为空")] public string UserCode { get; set; } public DateTimePeriod DateTimePeriod { get; set; } diff --git a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleSaveRequest.cs b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleSaveRequest.cs index 08b23358..c1ca7415 100644 --- a/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleSaveRequest.cs +++ b/Src/Dlhis.Basic/WorkGrids/Request/WorkGridScheduleSaveRequest.cs @@ -1,8 +1,9 @@ +using System.ComponentModel.DataAnnotations; using Dlhis.Entity.Basic.Enums; namespace Dlhis.Basic.WorkGrids.Request; -public class WorkGridScheduleSaveRequest +public class WorkGridScheduleSaveRequest : IValidatableObject { /// /// 网格code @@ -23,4 +24,14 @@ public class WorkGridScheduleSaveRequest /// 人员codes /// public List UserCodes { get; set; } + + /// + public IEnumerable Validate(ValidationContext validationContext) + { + var now = DateTime.Now; + if (Date.ToDateTime(new TimeOnly(0, 0)) < now.Date) + { + yield return new ValidationResult("不可编辑历史数据"); + } + } } \ No newline at end of file diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs index ebf66e67..23313c52 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridScheduleService.cs @@ -1,17 +1,21 @@ using Dlhis.Basic.Common.ApiLog.Services; +using Dlhis.Basic.Organization.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.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; @@ -20,22 +24,31 @@ public class WorkGridScheduleService : IWorkGridScheduleService private readonly IDbContext _dbContext; private readonly IJinkoJipApi _jinkoJipApi; private readonly IOperateLog _operateLog; + private readonly ICurrentUser _currentUser; + private readonly IFactorySettingService _factorySettingService; - public WorkGridScheduleService(IDbContext dbContext, IJinkoJipApi jinkoJipApi, IOperateLog operateLog) + public WorkGridScheduleService(IDbContext dbContext, + IJinkoJipApi jinkoJipApi, + IOperateLog operateLog, + ICurrentUser currentUser, + IFactorySettingService factorySettingService) { _dbContext = dbContext; _jinkoJipApi = jinkoJipApi; _operateLog = operateLog; + _currentUser = currentUser; + _factorySettingService = factorySettingService; } public async Task SaveAsync(WorkGridScheduleSaveRequest request) { + //await _factorySettingService.CheckWorkGridSetLimitAsync(request.Date); + var workGrid = await _dbContext.Queryable().SingleAsync(x => x.Code == request.WorkGridCode); workGrid.ThrowIfNull("工作网格不存在"); var exists = await _dbContext.Queryable() .Where(x => x.WorkGridCode == request.WorkGridCode - && x.PeriodType == request.PeriodType && x.Date == request.Date && request.UserCodes.Contains(x.UserCode) ) @@ -59,9 +72,11 @@ public class WorkGridScheduleService : IWorkGridScheduleService /// public async Task RemoveAsync(WorkGridScheduleSaveRequest request) { + //await _factorySettingService.CheckWorkGridSetLimitAsync(request.Date); + var workGrid = await _dbContext.Queryable().SingleAsync(x => x.Code == request.WorkGridCode); workGrid.ThrowIfNull("工作网格不存在"); - + var data = await _dbContext.Queryable() .Where(x => x.WorkGridCode == request.WorkGridCode) .Where(x => x.Date == request.Date) @@ -114,11 +129,25 @@ public class WorkGridScheduleService : IWorkGridScheduleService /// public async Task> GetAttendancePageAsync(WorkGridScheduleAttendancePageRequest request) { + var jinkoCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode); + var workGrid = await _dbContext.Queryable().Where(x => x.LeaderUserCode == jinkoCode).SingleAsync(); + if (workGrid == null) + { + return new Pagination + { + PageIndex = request.PageIndex, + PageSize = request.PageSize, + Total = 0, + Data = null + }; + } + return await _dbContext.Queryable() .LeftJoin((log, d) => log.DeviceUniqueNo == d.UniqueNo) - .Where(log => log.UserUniqueNo == request.UserCode) .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().Where(p => p.WorkGridCode == workGrid.Code && p.UserCode == log.UserUniqueNo).Any()) .OrderBy(log => log.RaiseDateTime) .Select((log, d) => new WorkGridScheduleAttendancePageResponse { diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs index 9b6c977a..cebce3af 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridService.cs @@ -20,7 +20,9 @@ public class WorkGridService : IWorkGridService private readonly ICurrentUser _currentUser; private readonly IOperateLog _operateLog; - public WorkGridService(IDbContext dbContext, ICurrentUser currentUser, IOperateLog operateLog) + public WorkGridService(IDbContext dbContext, + ICurrentUser currentUser, + IOperateLog operateLog) { _dbContext = dbContext; _currentUser = currentUser; @@ -33,18 +35,13 @@ public class WorkGridService : IWorkGridService var insertGrids = new List(); var updateGrids = new List(); + var leaderUserCodes = requests.Select(x => x.LeaderUserCode).Distinct().ToList(); + var existsUserCodes = await _dbContext.Queryable().Where(x => leaderUserCodes.Contains(x.Code)).Select(x => x.Code).ToListAsync(); + var notExistsUserCodes = leaderUserCodes.Except(existsUserCodes).ToList(); + notExistsUserCodes.ThrowIfExists($"工号:{notExistsUserCodes.Join(",")}不存在"); + foreach (var request in requests) { - var exists = await _dbContext.Queryable() - .Where(x => x.LeaderUserCode == request.LeaderUserCode) - .WhereIF(request.Id.HasValue, x => x.Id != request.Id) - .AnyAsync(); - - if (!await _dbContext.Queryable().Where(x => x.Code == request.LeaderUserCode).AnyAsync()) - { - true.ThrowIfTrue($"工号:{request.LeaderUserCode}不存在"); - } - if (await _dbContext.Queryable().Where(x => x.Name == request.Name) .WhereIF(request.Id.HasValue, x => x.Id != request.Id) .AnyAsync()) @@ -52,12 +49,18 @@ public class WorkGridService : IWorkGridService true.ThrowIfTrue($"网格区域名称[{request.Name}]重复"); } - exists.ThrowIfTrue($"{request.LeaderUserCode}已存在管理的网格"); if (!request.Id.HasValue) { + var exists = await _dbContext.Queryable() + .Where(x => x.LeaderUserCode == request.LeaderUserCode) + .WhereIF(request.Id.HasValue, x => x.Id != request.Id) + .AnyAsync(); + exists.ThrowIfTrue($"{request.LeaderUserCode}人员存在管理中的网格,无法添加"); + var entity = request.Adapt(); entity.Code = Guid.NewGuid(); + entity.LeaderUserCode = request.LeaderUserCode; await _dbContext.InsertAsync(entity); insertGrids.Add($"{entity.Name}({entity.LeaderUserCode})"); @@ -82,6 +85,7 @@ public class WorkGridService : IWorkGridService public async Task> GetPageAsync(WorkGridPageRequest request) { var role = _currentUser.GetRole(); + var factory = _currentUser.GetStringTenantId(); var userCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode); var isAll = role is "admin" or "tenant-admin"; @@ -89,6 +93,7 @@ public class WorkGridService : IWorkGridService .LeftJoin((x, ga) => x.LeaderUserCode == ga.Code) .WhereIF(!isAll, x => x.LeaderUserCode == userCode) .WhereIF(request.Search.IsPresent(), x => x.Name.Contains(request.Search) || x.LeaderUserCode == request.Search) + .Where(x => SqlFunc.Subqueryable().Where(p => p.Code == x.LeaderUserCode && p.Factory == factory).Any()) .Select((x, ga) => new WorkGridPageResponse { Id = x.Id, @@ -108,9 +113,14 @@ public class WorkGridService : IWorkGridService var workGrid = await _dbContext.Queryable().Where(x => x.LeaderUserCode == from).SingleAsync(); workGrid.ThrowIfNull("网格不存在"); + var beforeGainfo = await _dbContext.Queryable().Where(x => x.Code == from).SingleAsync(); + beforeGainfo.ThrowIfNull($"{from}人员不存在"); + var gainfo = await _dbContext.Queryable().Where(x => x.Code == to).SingleAsync(); gainfo.ThrowIfNull($"{to}人员不存在"); + (gainfo.Factory != beforeGainfo.Factory).ThrowIfTrue($"必须选择相同厂区({beforeGainfo.Factory})人员管理({gainfo.Factory}错误)"); + workGrid.LeaderUserCode = to; await _dbContext.UpdateAsync(workGrid); @@ -120,7 +130,7 @@ public class WorkGridService : IWorkGridService /// public async Task GetMyWorkGridAsync(WorkGridPageRequest request) { - var currentUserCode = _currentUser.GetUserClaim("jinko-code"); + var currentUserCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode); var myWorkGrid = await _dbContext.Queryable() .WhereIF(request.WorkGridCode.HasValue == false, x => x.LeaderUserCode == currentUserCode) .WhereIF(request.WorkGridCode.HasValue, x => x.Code == request.WorkGridCode) @@ -162,10 +172,10 @@ public class WorkGridService : IWorkGridService (count != request.UserCodes.Count).ThrowIfTrue("存在非当前厂区人员,请检查"); - var existsAssigned = await _dbContext.Queryable().Where(x => x.WorkGridCode == myWorkGrid.Code) + var existsAssigned = await _dbContext.Queryable() .Where(x => request.UserCodes.Contains(x.UserCode)) .AnyAsync(); - existsAssigned.ThrowIfTrue("存在已经分配人员,请勿重复分配"); + existsAssigned.ThrowIfTrue("存在已经分配人员,操作失败!"); var dataToInserts = request.UserCodes.Select(x => new WorkGridUserEntity { @@ -180,15 +190,19 @@ public class WorkGridService : IWorkGridService /// public async Task RemoveAsync(WorkGridUserRemoveRequest request) { - var currentUserCode = _currentUser.GetUserClaim("jinko-code"); + var currentUserCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode); var myWorkGrid = await _dbContext.Queryable().Where(x => x.LeaderUserCode == currentUserCode).SingleAsync(); myWorkGrid.ThrowIfNull("工作网格尚未配置,请联系管理员"); - var workGridUsers = await _dbContext.Queryable().Where(x => x.WorkGridCode == myWorkGrid.Code) + var workGridUsers = await _dbContext.Queryable() + .Where(x => x.WorkGridCode == myWorkGrid.Code) .Where(x => request.UserCodes.Contains(x.UserCode)) .ToListAsync(); - var workGridSchedules = await _dbContext.Queryable().Where(x => x.WorkGridCode == myWorkGrid.Code) + var date = DateOnly.FromDateTime(DateTime.Today); + var workGridSchedules = await _dbContext.Queryable() + .Where(x => x.Date > date) + .Where(x => x.WorkGridCode == myWorkGrid.Code) .Where(x => request.UserCodes.Contains(x.UserCode)) .ToListAsync(); diff --git a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs index e59c4ac0..06922bef 100644 --- a/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs +++ b/Src/Dlhis.Basic/WorkGrids/Services/Implements/WorkGridTimePeriodService.cs @@ -2,7 +2,6 @@ using Dlhis.Basic.Common.ApiLog.Services; using Dlhis.Basic.WorkGrids.Request; using Dlhis.Basic.WorkGrids.Response; using Dlhis.Entity.Basic.Entity; -using Dlhis.Entity.Basic.Enums; using Dlhis.Entity.Common.Enums; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; @@ -27,7 +26,6 @@ public class WorkGridTimePeriodService : IWorkGridTimePeriodService public async Task SaveAsync(WorkGridTimePeriodSaveRequest request) { //await CheckDuplicateTimePeriodAsync(request); - if (!request.Id.HasValue) { //判断重复配置 @@ -65,17 +63,6 @@ public class WorkGridTimePeriodService : IWorkGridTimePeriodService //************************************************************************************************************************************************* - /// - /// 根据类型获取配置 - /// - /// - /// - private async Task GetSettingAsync(WorkGridTimePeriodEnumType timePeriodType) - { - return await _dbContext.Queryable() - .Where(x => x.Type == timePeriodType) - .SingleAsync(); - } // /// // /// 检查时间段重合检查 diff --git a/Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs b/Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs index 21ff88d1..53d0b25a 100644 --- a/Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs +++ b/Src/Dlhis.Entity/Basic/Entity/WorkGridScheduleEntity.cs @@ -1,5 +1,4 @@ using Dlhis.Entity.Basic.Enums; -using Kurisu.AspNetCore.DataAccess.Entity; using Kurisu.AspNetCore.DataAccess.SqlSugar; using SqlSugar; using SqlSugar.DbConvert; @@ -9,19 +8,19 @@ namespace Dlhis.Entity.Basic.Entity; /// /// /// -[SugarTable(TableName = "WorkGridSchedule")] -public class WorkGridScheduleEntity : SugarBaseEntity, ITenantId +[SugarTable(TableName = "WorkGridSchedules")] +public class WorkGridScheduleEntity : SugarBaseEntity { /// /// 网格code /// - [SugarColumn(IsNullable = false, ColumnDescription = "网格code")] + [SugarColumn(IsNullable = false, ColumnDescription = "网格code", IndexGroupNameList = new[] { "idx_WorkGridSchedules_workGridCode_date" })] public Guid WorkGridCode { get; set; } /// /// 排班日期 /// - [SugarColumn(IsNullable = false, ColumnDataType = "date", ColumnDescription = "排班日期")] + [SugarColumn(IsNullable = false, ColumnDataType = "date", ColumnDescription = "排班日期", IndexGroupNameList = new[] { "idx_WorkGridSchedules_workGridCode_date" })] public DateOnly Date { get; set; } /// @@ -33,10 +32,6 @@ public class WorkGridScheduleEntity : SugarBaseEntity, ITenantId /// /// 工号 /// - [SugarColumn(IsNullable = false, ColumnDescription = "工号")] + [SugarColumn(IsNullable = false, ColumnDescription = "工号", IndexGroupNameList = new[] { "idx_WorkGridSchedules_userCode" })] public string UserCode { get; set; } - - - /// - public string TenantId { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs b/Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs index 05ccd503..dd998292 100644 --- a/Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs +++ b/Src/Dlhis.Entity/Basic/Entity/WorkGridUserEntity.cs @@ -1,8 +1,5 @@ -using Dlhis.Entity.Basic.Enums; -using Kurisu.AspNetCore.DataAccess.Entity; using Kurisu.AspNetCore.DataAccess.SqlSugar; using SqlSugar; -using SqlSugar.DbConvert; namespace Dlhis.Entity.Basic.Entity; @@ -10,7 +7,7 @@ namespace Dlhis.Entity.Basic.Entity; /// 网格人员 /// [SugarTable(TableName = "WorkGridUsers")] -public class WorkGridUserEntity : SugarBaseEntity, ITenantId +public class WorkGridUserEntity : SugarBaseEntity { /// /// 网格code @@ -21,15 +18,6 @@ public class WorkGridUserEntity : SugarBaseEntity, ITenantId /// /// 网格人员 /// - [SugarColumn(IsNullable = false, ColumnDescription = "网格人员")] + [SugarColumn(IsNullable = false, ColumnDescription = "网格人员", UniqueGroupNameList = new[] { "idx_WorkGridUsers_userCode" })] public string UserCode { get; set; } - - /// - /// 排班类型 - /// - [SugarColumn(IsNullable = true,ColumnDataType = "varchar(50)",ColumnDescription = "排班类型", SqlParameterDbType = typeof(EnumToStringConvert))] - public WorkGridTimePeriodEnumType? ScheduleType { get; set; } - - /// - public string TenantId { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Sys/Entities/FactorySettingEntity.cs b/Src/Dlhis.Entity/Sys/Entities/FactorySettingEntity.cs index 89b9f935..2a764e84 100644 --- a/Src/Dlhis.Entity/Sys/Entities/FactorySettingEntity.cs +++ b/Src/Dlhis.Entity/Sys/Entities/FactorySettingEntity.cs @@ -34,12 +34,15 @@ public class FactorySettingEntity : SugarBaseEntity, ITenantId /// [SugarColumn(ColumnDescription = "人脸检测配置", IsNullable = true, IsJson = true)] public FaceImageDetectionDto FaceImageDetection { get; set; } - - + + /// /// 外包自动离职天数(无通行记录) /// public int NoRecordAutoResignOutsourceDays { get; set; } + [SugarColumn(IsNullable = true, ColumnDataType = "time", ColumnDescription = "工作网格编辑限制时间")] + public TimeOnly? WorkGridSetLimit { get; set; } + public string TenantId { get; set; } } \ No newline at end of file From a9ef44f776525133eaa4c600c3d28fa01003ec72 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 4 Mar 2025 15:05:36 +0800 Subject: [PATCH 24/25] fix nullable --- Src/Dlhis.Entity/Common/Entities/OperateLogEntity.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/Dlhis.Entity/Common/Entities/OperateLogEntity.cs b/Src/Dlhis.Entity/Common/Entities/OperateLogEntity.cs index b8080855..9844134d 100644 --- a/Src/Dlhis.Entity/Common/Entities/OperateLogEntity.cs +++ b/Src/Dlhis.Entity/Common/Entities/OperateLogEntity.cs @@ -16,6 +16,6 @@ public class OperateLogEntity : SugarBaseEntity public string Content { get; set; } - [SugarColumn(IsNullable = false)] + [SugarColumn(IsNullable = true)] public string Operator { get; set; } } \ No newline at end of file From 6e6578b1979b043433bf6f08f75fdad04ecc0694 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Wed, 5 Mar 2025 12:10:47 +0800 Subject: [PATCH 25/25] =?UTF-8?q?fix=20=E5=A2=9E=E5=8A=A0=E9=80=9A?= =?UTF-8?q?=E8=A1=8C=E8=AE=B0=E5=BD=95=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/Implements/OperateLogService.cs | 2 + .../Device/Entities/DeviceUploadLogEntity.cs | 7 ++ .../Implements/DeviceUploadLogService.cs | 94 ++++++++++++++++++- 3 files changed, 102 insertions(+), 1 deletion(-) diff --git a/Src/Dlhis.Basic/Common/ApiLog/Services/Implements/OperateLogService.cs b/Src/Dlhis.Basic/Common/ApiLog/Services/Implements/OperateLogService.cs index b2a26087..3ddd9aaa 100644 --- a/Src/Dlhis.Basic/Common/ApiLog/Services/Implements/OperateLogService.cs +++ b/Src/Dlhis.Basic/Common/ApiLog/Services/Implements/OperateLogService.cs @@ -6,6 +6,7 @@ using Kurisu.AspNetCore.Authentication.Abstractions; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using SqlSugar; namespace Dlhis.Basic.Common.ApiLog.Services.Implements; @@ -58,6 +59,7 @@ public class OperateLogService : IOperateLog Operator = x.Operator, CreateTime = x.CreateTime }) + .OrderBy(x => x.CreateTime, OrderByType.Desc) .ToPageListAsync(request); } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Device/Entities/DeviceUploadLogEntity.cs b/Src/Dlhis.Entity/Device/Entities/DeviceUploadLogEntity.cs index e8789cde..b6575422 100644 --- a/Src/Dlhis.Entity/Device/Entities/DeviceUploadLogEntity.cs +++ b/Src/Dlhis.Entity/Device/Entities/DeviceUploadLogEntity.cs @@ -76,6 +76,13 @@ public class DeviceUploadLogEntity : SugarBaseEntity, ITenantId public string Image { get; set; } + /// + /// 网格信息 + /// + [SugarColumn(IsNullable = true, ColumnDataType = "text")] + public string WorkGridInfo { get; set; } + + [SugarColumn(IndexGroupNameList = new[] { "idx_DeviceUploadLog_TenantId" })] public string TenantId { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs b/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs index 6336d998..d98f124b 100644 --- a/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs +++ b/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs @@ -42,6 +42,28 @@ public class DeviceUploadLogService : IDeviceUploadLogService var gainfo3 = await _dbContext.Queryable().Where(x => gainfoCardNos.Contains(x.Code)).Select(x => new { x.Code, x.Type }).ToListAsync(); var gainfos = gainfo1.Concat(gainfo2).Concat(gainfo3).DistinctBy(x => x.Code).ToList(); + var userCodes2 = gainfos.Select(x => x.Code).Distinct().ToList(); + + var min = DateOnly.FromDateTime(requests.Min(x => x.RaiseDateTime)).AddDays(-1); + var max = DateOnly.FromDateTime(requests.Max(x => x.RaiseDateTime)); + + var workGridUsers = await _dbContext.Queryable() + .Where(x => userCodes2.Contains(x.UserCode)) + .ToListAsync(); + + var workGridSchedules = await _dbContext.Queryable() + .Where(x => x.Date >= min && x.Date <= max) + .Where(x => userCodes2.Contains(x.UserCode)).ToListAsync(); + + var factories = devices.Select(x => x.TenantId).Distinct().ToList(); + var workGridTimePeriods = await _dbContext.Queryable() + .Where(x => factories.Contains(x.TenantId)) + .Select(x => new + { + x.Type, x.Start, x.End, x.Before, x.After, x.TenantId + }) + .ToListAsync(); + var inserts = new List(); foreach (var request in requests.Where(x => existsDeviceUniqueNos.Contains(x.DeviceUniqueNo))) { @@ -68,10 +90,70 @@ public class DeviceUploadLogService : IDeviceUploadLogService var device = devices.First(x => x.UniqueNo == request.DeviceUniqueNo); var userType = gainfos.FirstOrDefault(x => x.Code == request.UserUniqueNo)?.Type; - var needUpload = userType is GainfoUserTypeEnumType.Normal or GainfoUserTypeEnumType.SecurityWhite && (device.Type == DeviceTypeEnumType.Attendance || (device.Type == DeviceTypeEnumType.Door && device.AsAttendance)); + var needUpload = ((userType is GainfoUserTypeEnumType.Normal or GainfoUserTypeEnumType.SecurityWhite) + && (device.Type == DeviceTypeEnumType.Attendance || (device.Type == DeviceTypeEnumType.Door && device.AsAttendance))); var dataType = device.Type == DeviceTypeEnumType.Attendance ? DeviceUploadLogTypeEnumType.Attendance : DeviceUploadLogTypeEnumType.Door; + + var workGridInfo = new WorkGridInfo(); + var currentWorkGridTimePeriods = workGridTimePeriods.Where(x => x.TenantId == device.TenantId).ToList(); + var workGridUser = workGridUsers.FirstOrDefault(x => x.UserCode == request.UserUniqueNo); + if (currentWorkGridTimePeriods.Any() && workGridUser != null) + { + workGridInfo.TimeSetting = currentWorkGridTimePeriods; + workGridInfo.WorkGrid = new + { + workGridUser.WorkGridCode + }; + var currentDate = request.RaiseDateTime.Date; + var currentDateOnly = DateOnly.FromDateTime(currentDate); + + var currentDayWorkGridTimePeriod = currentWorkGridTimePeriods.FirstOrDefault(x => x.Type == WorkGridTimePeriodEnumType.Day); + var currentDayWorkGridSchedule = workGridSchedules.FirstOrDefault(x => x.PeriodType == WorkGridTimePeriodEnumType.Day && x.Date == currentDateOnly); + if (currentDayWorkGridTimePeriod != null && currentDayWorkGridSchedule != null) + { + var start = currentDate.Add(currentDayWorkGridTimePeriod.Start.AddMinutes(currentDayWorkGridTimePeriod.Before).ToTimeSpan()); + var end = currentDate.Add(currentDayWorkGridTimePeriod.End.AddMinutes(currentDayWorkGridTimePeriod.After).ToTimeSpan()); + + if (request.RaiseDateTime >= start && request.RaiseDateTime <= end) + { + workGridInfo.PeriodType = WorkGridTimePeriodEnumType.Day; + } + } + + var currentNightWorkGridTimePeriod = currentWorkGridTimePeriods.FirstOrDefault(x => x.Type == WorkGridTimePeriodEnumType.Night); + var currentNightWorkGridSchedules = workGridSchedules + .Where(x => x.PeriodType == WorkGridTimePeriodEnumType.Night && (x.Date == currentDateOnly || x.Date == currentDateOnly.AddDays(-1))).ToList(); + if (currentNightWorkGridTimePeriod != null && currentNightWorkGridSchedules.Any()) + { + var startTime = currentNightWorkGridTimePeriod.Start.AddMinutes(currentNightWorkGridTimePeriod.Before); + var endTime = currentNightWorkGridTimePeriod.End.AddMinutes(currentNightWorkGridTimePeriod.After); + + if (currentNightWorkGridSchedules.Any(x => x.Date == currentDateOnly)) + { + var start = currentDateOnly.ToDateTime(startTime); + var end = currentDateOnly.ToDateTime(new TimeOnly(23, 59, 59, 999)); + + if (request.RaiseDateTime >= start && request.RaiseDateTime <= end) + { + workGridInfo.PeriodType = WorkGridTimePeriodEnumType.Night; + } + } + + if (currentNightWorkGridSchedules.Any(x => x.Date == currentDateOnly.AddDays(-1))) + { + var start = currentDateOnly.AddDays(-1).ToDateTime(startTime); + var end = currentDateOnly.ToDateTime(endTime); + + if (request.RaiseDateTime >= start && request.RaiseDateTime <= end) + { + workGridInfo.PeriodType = WorkGridTimePeriodEnumType.Night; + } + } + } + } + inserts.Add(new DeviceUploadLogEntity { DeviceCode = device.Code, @@ -85,6 +167,7 @@ public class DeviceUploadLogService : IDeviceUploadLogService TenantId = device.TenantId, Status = request.Status ?? true, Image = request.Image, + WorkGridInfo = workGridInfo.ToJson(), CreatedBy = 1, ModifiedBy = 1 }); @@ -316,4 +399,13 @@ public class DeviceUploadLogService : IDeviceUploadLogService Data = r }; } +} + +public class WorkGridInfo +{ + public object WorkGrid { get; set; } + public WorkGridTimePeriodEnumType? PeriodType { get; set; } + public object TimeSetting { get; set; } + + public bool NeedUpload => WorkGrid != null && PeriodType.HasValue; } \ No newline at end of file