feat: enhance project board query with skill and user details

This commit is contained in:
2025-12-16 14:18:00 +03:30
parent 2972807c9f
commit 9e5a494881
4 changed files with 32 additions and 7 deletions

View File

@@ -1,4 +1,5 @@
using FluentValidation;
using FluentValidation.Validators;
using GozareshgirProgramManager.Application.Modules.Projects.DTOs;
namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.SetTimeProject;
@@ -15,6 +16,9 @@ public class SetTimeProjectCommandValidator:AbstractValidator<SetTimeProjectComm
RuleForEach(x => x.SectionItems)
.SetValidator(command => new SetTimeProjectSectionItemValidator());
RuleFor(x => x.SectionItems)
.Must(sectionItems => sectionItems.Any(si => si.InitData?.Hours > 0))
.WithMessage("حداقل یکی از بخش‌ها باید مقدار ساعت معتبری داشته باشد.");
}
}
public class SetTimeProjectSectionItemValidator:AbstractValidator<SetTimeProjectSectionItem>
@@ -30,13 +34,14 @@ public class SetTimeProjectSectionItemValidator:AbstractValidator<SetTimeProject
.SetValidator(new TimeDataValidator());
RuleForEach(x=>x.AdditionalTime)
.SetValidator(new TimeDataValidator());
.SetValidator(new AdditionalTimeDataValidator());
}
}
public class TimeDataValidator : AbstractValidator<SetTimeSectionTime>
public class AdditionalTimeDataValidator: AbstractValidator<SetTimeSectionTime>
{
public TimeDataValidator()
public AdditionalTimeDataValidator()
{
RuleFor(x => x.Hours)
.GreaterThanOrEqualTo(0)
@@ -45,6 +50,13 @@ public class TimeDataValidator : AbstractValidator<SetTimeSectionTime>
RuleFor(x=>x.Description)
.MaximumLength(500)
.WithMessage("توضیحات نمی‌تواند بیشتر از 500 کاراکتر باشد.");
}
}
public class TimeDataValidator : AbstractValidator<SetTimeSectionTime>
{
public TimeDataValidator()
{
}
}

View File

@@ -28,7 +28,8 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
.ThenInclude(x => x.Phase)
.ThenInclude(x => x.Project)
.Include(x => x.Activities)
.Include(x => x.AdditionalTimes).AsQueryable();
.Include(x => x.AdditionalTimes).AsQueryable().
Include(x => x.Skill).AsQueryable();
if (!_authHelper.HasPermission(ProgramManagerPermissionCode.Board.All.ViewAll))
{
@@ -42,10 +43,14 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
var data = await queryable.ToListAsync(cancellationToken);
var activityUserIds = data.SelectMany(x => x.Activities).Select(a => a.UserId).Distinct().ToList();
var assignedUser = data.Select(x => x.CurrentAssignedUserId)
.Concat(data.Select(x => x.OriginalAssignedUserId)).ToList();
var allUserIds = activityUserIds.Concat(assignedUser).Distinct().ToList();
var users = await _programManagerDbContext.Users.AsNoTracking()
.Where(x => activityUserIds.Contains(x.Id))
.Where(x => allUserIds.Contains(x.Id))
.Select(x => new { x.Id, x.FullName })
.ToDictionaryAsync(x => x.Id, x => x.FullName, cancellationToken);
var result = data.Select(x =>
{
@@ -101,7 +106,11 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
CompleteSecond = x.FinalEstimatedHours.TotalSeconds,
CurrentSecond = activityTimeData.Sum(a => a.TotalSeconds),
Histories = mergedHistories
}
},
OriginalUser = users.GetValueOrDefault(x.OriginalAssignedUserId, "ناشناس"),
AssignedUser = x.CurrentAssignedUserId == x.OriginalAssignedUserId ? null
: users.GetValueOrDefault(x.CurrentAssignedUserId, "ناشناس"),
SkillName = x.Skill?.Name??"-",
};
}).ToList();

View File

@@ -10,6 +10,10 @@ public class ProjectBoardListResponse
public string TaskName { get; set; }
public ProjectProgressDto Progress { get; set; }
public TaskSectionStatus SectionStatus { get; set; }
public string? AssignedUser { get; set; }
public string OriginalUser { get; set; }
public string SkillName { get; set; }
}
public class ProjectProgressDto
{