fix(加班申请、工作报告、我的绩效): 修复一系列bug、对不合理的地方进行调整。

This commit is contained in:
dk
2026-06-22 22:58:03 +08:00
parent b4f6eab64c
commit 856668ec25
12 changed files with 365 additions and 64 deletions

View File

@@ -2,11 +2,21 @@ package com.njcn.rdms.module.project.controller.admin.overtime.team.vo;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@Schema(description = "管理后台 - 团队加班申请统计 Request VO") @Schema(description = "管理后台 - 团队加班申请统计 Request VO")
@Data @Data
public class TeamOvertimeSummaryReqVO { public class TeamOvertimeSummaryReqVO {
@Schema(description = "统计月份,不传默认当前月", example = "2026-06") @Schema(description = "加班日期区间起始(不传默认当月第一天)", example = "2026-06-01")
private String month; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate overtimeDateStart;
@Schema(description = "加班日期区间结束(不传默认当月最后一天)", example = "2026-06-30")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate overtimeDateEnd;
} }

View File

@@ -3,12 +3,17 @@ package com.njcn.rdms.module.project.controller.admin.overtime.team.vo;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import java.time.LocalDate;
@Schema(description = "管理后台 - 团队加班申请统计 Response VO") @Schema(description = "管理后台 - 团队加班申请统计 Response VO")
@Data @Data
public class TeamOvertimeSummaryRespVO { public class TeamOvertimeSummaryRespVO {
@Schema(description = "统计月份", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026-06") @Schema(description = "实际查询加班日期区间起始", requiredMode = Schema.RequiredMode.REQUIRED)
private String month; private LocalDate overtimeDateStart;
@Schema(description = "实际查询加班日期区间结束", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDate overtimeDateEnd;
@Schema(description = "申请总数", requiredMode = Schema.RequiredMode.REQUIRED, example = "12") @Schema(description = "申请总数", requiredMode = Schema.RequiredMode.REQUIRED, example = "12")
private Integer totalApplicationCount; private Integer totalApplicationCount;

View File

@@ -1,10 +1,11 @@
package com.njcn.rdms.module.project.controller.admin.workreport.common; package com.njcn.rdms.module.project.controller.admin.workreport.common;
import com.njcn.rdms.framework.common.util.http.HttpUtils;
import com.njcn.rdms.module.project.service.workreport.export.WorkReportExportFile; import com.njcn.rdms.module.project.service.workreport.export.WorkReportExportFile;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
public final class WorkReportExportResponseUtils { public final class WorkReportExportResponseUtils {
@@ -12,7 +13,8 @@ public final class WorkReportExportResponseUtils {
} }
public static void write(HttpServletResponse response, WorkReportExportFile file) throws IOException { public static void write(HttpServletResponse response, WorkReportExportFile file) throws IOException {
response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(file.filename())); response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''"
+ URLEncoder.encode(file.filename(), StandardCharsets.UTF_8).replace("+", "%20"));
response.setContentType(file.contentType()); response.setContentType(file.contentType());
response.setContentLength(file.content().length); response.setContentLength(file.content().length);
response.getOutputStream().write(file.content()); response.getOutputStream().write(file.content());

View File

@@ -3,6 +3,11 @@ package com.njcn.rdms.module.project.controller.admin.workreport.team.vo;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@Schema(description = "管理后台 - 团队工作报告统计 Request VO") @Schema(description = "管理后台 - 团队工作报告统计 Request VO")
@Data @Data
@@ -12,7 +17,14 @@ public class TeamReportSummaryReqVO {
@NotBlank(message = "报告类型不能为空") @NotBlank(message = "报告类型不能为空")
private String reportType; private String reportType;
@Schema(description = "周期主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "weekly-2026-06-08-2026-06-14") @Schema(description = "周期主键(单周期查询时使用,与日期区间二选一)", example = "weekly-2026-06-08-2026-06-14")
@NotBlank(message = "周期主键不能为空")
private String periodKey; private String periodKey;
@Schema(description = "周期起始日期(区间查询时使用,与 periodKey 二选一)", example = "2026-06-15")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate periodStartDate;
@Schema(description = "周期结束日期(区间查询时使用,与 periodKey 二选一)", example = "2026-06-28")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate periodEndDate;
} }

View File

@@ -4,12 +4,19 @@ import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import java.time.LocalDate;
import java.util.List; import java.util.List;
@Schema(description = "管理后台 - 团队工作报告统计 Response VO") @Schema(description = "管理后台 - 团队工作报告统计 Response VO")
@Data @Data
public class TeamReportSummaryRespVO { public class TeamReportSummaryRespVO {
@Schema(description = "实际查询周期起始日期")
private LocalDate periodStartDate;
@Schema(description = "实际查询周期结束日期")
private LocalDate periodEndDate;
@Schema(description = "应填人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "18") @Schema(description = "应填人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "18")
private Integer totalShouldSubmit; private Integer totalShouldSubmit;

View File

@@ -10,6 +10,7 @@ import com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyRep
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@@ -24,7 +25,7 @@ public interface MonthlyReportMapper extends BaseMapperX<MonthlyReportDO> {
} }
default List<MonthlyReportDO> selectListByReporterIdsAndPeriodKey(Collection<Long> reporterIds, String periodKey, default List<MonthlyReportDO> selectListByReporterIdsAndPeriodKey(Collection<Long> reporterIds, String periodKey,
Collection<String> allowedStatusCodes) { Collection<String> allowedStatusCodes) {
if (reporterIds == null || reporterIds.isEmpty() || !StringUtils.hasText(periodKey)) { if (reporterIds == null || reporterIds.isEmpty() || !StringUtils.hasText(periodKey)) {
return List.of(); return List.of();
} }
@@ -40,12 +41,34 @@ public interface MonthlyReportMapper extends BaseMapperX<MonthlyReportDO> {
return selectList(wrapper); return selectList(wrapper);
} }
/**
* 按报告人 ID 列表与周期日期区间查询月报periodStartDate 落在 [startDate, endDate] 内)。
*/
default List<MonthlyReportDO> selectListByReporterIdsAndPeriodDateRange(Collection<Long> reporterIds,
LocalDate startDate, LocalDate endDate,
Collection<String> allowedStatusCodes) {
if (reporterIds == null || reporterIds.isEmpty()) {
return List.of();
}
LambdaQueryWrapperX<MonthlyReportDO> wrapper = new LambdaQueryWrapperX<MonthlyReportDO>()
.in(MonthlyReportDO::getReporterId, reporterIds)
.geIfPresent(MonthlyReportDO::getPeriodStartDate, startDate)
.leIfPresent(MonthlyReportDO::getPeriodStartDate, endDate);
if (allowedStatusCodes != null) {
if (allowedStatusCodes.isEmpty()) {
return List.of();
}
wrapper.in(MonthlyReportDO::getStatusCode, allowedStatusCodes);
}
return selectList(wrapper);
}
default PageResult<MonthlyReportDO> selectReporterPage(Long reporterId, MonthlyReportPageReqVO reqVO) { default PageResult<MonthlyReportDO> selectReporterPage(Long reporterId, MonthlyReportPageReqVO reqVO) {
return selectReporterPage(reporterId, reqVO, null); return selectReporterPage(reporterId, reqVO, null);
} }
default PageResult<MonthlyReportDO> selectReporterPage(Long reporterId, MonthlyReportPageReqVO reqVO, default PageResult<MonthlyReportDO> selectReporterPage(Long reporterId, MonthlyReportPageReqVO reqVO,
Collection<String> allowedStatusCodes) { Collection<String> allowedStatusCodes) {
if (allowedStatusCodes != null && allowedStatusCodes.isEmpty()) { if (allowedStatusCodes != null && allowedStatusCodes.isEmpty()) {
return new PageResult<>(List.of(), 0L); return new PageResult<>(List.of(), 0L);
} }
@@ -60,8 +83,9 @@ public interface MonthlyReportMapper extends BaseMapperX<MonthlyReportDO> {
} }
default PageResult<MonthlyReportDO> selectReporterPage(Collection<Long> reporterIds, MonthlyReportPageReqVO reqVO, default PageResult<MonthlyReportDO> selectReporterPage(Collection<Long> reporterIds, MonthlyReportPageReqVO reqVO,
Collection<String> allowedStatusCodes) { Collection<String> allowedStatusCodes) {
if (reporterIds == null || reporterIds.isEmpty() || (allowedStatusCodes != null && allowedStatusCodes.isEmpty())) { if (reporterIds == null || reporterIds.isEmpty()
|| (allowedStatusCodes != null && allowedStatusCodes.isEmpty())) {
return new PageResult<>(List.of(), 0L); return new PageResult<>(List.of(), 0L);
} }
LambdaQueryWrapperX<MonthlyReportDO> wrapper = buildPageQuery(reqVO) LambdaQueryWrapperX<MonthlyReportDO> wrapper = buildPageQuery(reqVO)
@@ -90,9 +114,9 @@ public interface MonthlyReportMapper extends BaseMapperX<MonthlyReportDO> {
} }
default int updateSubmitFieldsByIdAndStatus(Long id, String fromStatus, String reporterDeptName, default int updateSubmitFieldsByIdAndStatus(Long id, String fromStatus, String reporterDeptName,
String reporterPostName, Long supervisorUserId, String reporterPostName, Long supervisorUserId,
String supervisorName, String toStatus, LocalDateTime submitTime, String supervisorName, String toStatus, LocalDateTime submitTime,
String updater) { String updater) {
return update(null, new LambdaUpdateWrapper<MonthlyReportDO>() return update(null, new LambdaUpdateWrapper<MonthlyReportDO>()
.set(MonthlyReportDO::getReporterDeptName, reporterDeptName) .set(MonthlyReportDO::getReporterDeptName, reporterDeptName)
.set(MonthlyReportDO::getReporterPostName, reporterPostName) .set(MonthlyReportDO::getReporterPostName, reporterPostName)
@@ -110,8 +134,8 @@ public interface MonthlyReportMapper extends BaseMapperX<MonthlyReportDO> {
} }
default int updateApprovalFieldsByIdAndStatus(Long id, String fromStatus, String toStatus, default int updateApprovalFieldsByIdAndStatus(Long id, String fromStatus, String toStatus,
LocalDateTime approvalTime, String approvalComment, LocalDateTime approvalTime, String approvalComment,
String lastStatusReason, String updater) { String lastStatusReason, String updater) {
return update(null, new LambdaUpdateWrapper<MonthlyReportDO>() return update(null, new LambdaUpdateWrapper<MonthlyReportDO>()
.set(MonthlyReportDO::getStatusCode, toStatus) .set(MonthlyReportDO::getStatusCode, toStatus)
.set(MonthlyReportDO::getApprovalTime, approvalTime) .set(MonthlyReportDO::getApprovalTime, approvalTime)
@@ -124,7 +148,7 @@ public interface MonthlyReportMapper extends BaseMapperX<MonthlyReportDO> {
} }
default int updateByIdAndStatusesAndReporterId(MonthlyReportDO update, Long id, Collection<String> statuses, default int updateByIdAndStatusesAndReporterId(MonthlyReportDO update, Long id, Collection<String> statuses,
Long reporterId) { Long reporterId) {
return update(update, new LambdaQueryWrapperX<MonthlyReportDO>() return update(update, new LambdaQueryWrapperX<MonthlyReportDO>()
.eq(MonthlyReportDO::getId, id) .eq(MonthlyReportDO::getId, id)
.eq(MonthlyReportDO::getReporterId, reporterId) .eq(MonthlyReportDO::getReporterId, reporterId)

View File

@@ -12,6 +12,7 @@ import com.njcn.rdms.module.project.dal.dataobject.workreport.project.ProjectRep
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@@ -22,7 +23,7 @@ public interface ProjectReportMapper extends BaseMapperX<ProjectReportDO> {
String JACKSON_TYPE_HANDLER_MAPPING = "typeHandler=" + JacksonTypeHandler.class.getCanonicalName(); String JACKSON_TYPE_HANDLER_MAPPING = "typeHandler=" + JacksonTypeHandler.class.getCanonicalName();
default ProjectReportDO selectByProjectIdAndPeriodKeyAndProjectOwnerId(Long projectId, String periodKey, default ProjectReportDO selectByProjectIdAndPeriodKeyAndProjectOwnerId(Long projectId, String periodKey,
Long projectOwnerId) { Long projectOwnerId) {
return selectOne(new LambdaQueryWrapperX<ProjectReportDO>() return selectOne(new LambdaQueryWrapperX<ProjectReportDO>()
.eq(ProjectReportDO::getProjectId, projectId) .eq(ProjectReportDO::getProjectId, projectId)
.eq(ProjectReportDO::getPeriodKey, periodKey) .eq(ProjectReportDO::getPeriodKey, periodKey)
@@ -30,8 +31,8 @@ public interface ProjectReportMapper extends BaseMapperX<ProjectReportDO> {
} }
default List<ProjectReportDO> selectListByProjectOwnerIdsAndPeriodKey(Collection<Long> projectOwnerIds, default List<ProjectReportDO> selectListByProjectOwnerIdsAndPeriodKey(Collection<Long> projectOwnerIds,
String periodKey, String periodKey,
Collection<String> allowedStatusCodes) { Collection<String> allowedStatusCodes) {
if (projectOwnerIds == null || projectOwnerIds.isEmpty() || !StringUtils.hasText(periodKey)) { if (projectOwnerIds == null || projectOwnerIds.isEmpty() || !StringUtils.hasText(periodKey)) {
return List.of(); return List.of();
} }
@@ -47,12 +48,34 @@ public interface ProjectReportMapper extends BaseMapperX<ProjectReportDO> {
return selectList(wrapper); return selectList(wrapper);
} }
/**
* 按项目负责人 ID 列表与周期日期区间查询项目半月报periodStartDate 落在 [startDate, endDate] 内)。
*/
default List<ProjectReportDO> selectListByProjectOwnerIdsAndPeriodDateRange(Collection<Long> projectOwnerIds,
LocalDate startDate, LocalDate endDate,
Collection<String> allowedStatusCodes) {
if (projectOwnerIds == null || projectOwnerIds.isEmpty()) {
return List.of();
}
LambdaQueryWrapperX<ProjectReportDO> wrapper = new LambdaQueryWrapperX<ProjectReportDO>()
.in(ProjectReportDO::getProjectOwnerId, projectOwnerIds)
.geIfPresent(ProjectReportDO::getPeriodStartDate, startDate)
.leIfPresent(ProjectReportDO::getPeriodStartDate, endDate);
if (allowedStatusCodes != null) {
if (allowedStatusCodes.isEmpty()) {
return List.of();
}
wrapper.in(ProjectReportDO::getStatusCode, allowedStatusCodes);
}
return selectList(wrapper);
}
default PageResult<ProjectReportDO> selectReporterPage(Long reporterId, ProjectReportPageReqVO reqVO) { default PageResult<ProjectReportDO> selectReporterPage(Long reporterId, ProjectReportPageReqVO reqVO) {
return selectReporterPage(reporterId, reqVO, null); return selectReporterPage(reporterId, reqVO, null);
} }
default PageResult<ProjectReportDO> selectReporterPage(Long reporterId, ProjectReportPageReqVO reqVO, default PageResult<ProjectReportDO> selectReporterPage(Long reporterId, ProjectReportPageReqVO reqVO,
Collection<String> allowedStatusCodes) { Collection<String> allowedStatusCodes) {
if (allowedStatusCodes != null && allowedStatusCodes.isEmpty()) { if (allowedStatusCodes != null && allowedStatusCodes.isEmpty()) {
return new PageResult<>(List.of(), 0L); return new PageResult<>(List.of(), 0L);
} }
@@ -67,8 +90,9 @@ public interface ProjectReportMapper extends BaseMapperX<ProjectReportDO> {
} }
default PageResult<ProjectReportDO> selectReporterPage(Collection<Long> reporterIds, ProjectReportPageReqVO reqVO, default PageResult<ProjectReportDO> selectReporterPage(Collection<Long> reporterIds, ProjectReportPageReqVO reqVO,
Collection<String> allowedStatusCodes) { Collection<String> allowedStatusCodes) {
if (reporterIds == null || reporterIds.isEmpty() || (allowedStatusCodes != null && allowedStatusCodes.isEmpty())) { if (reporterIds == null || reporterIds.isEmpty()
|| (allowedStatusCodes != null && allowedStatusCodes.isEmpty())) {
return new PageResult<>(List.of(), 0L); return new PageResult<>(List.of(), 0L);
} }
LambdaQueryWrapperX<ProjectReportDO> wrapper = buildPageQuery(reqVO) LambdaQueryWrapperX<ProjectReportDO> wrapper = buildPageQuery(reqVO)
@@ -97,10 +121,10 @@ public interface ProjectReportMapper extends BaseMapperX<ProjectReportDO> {
} }
default int updateSubmitFieldsByIdAndStatus(Long id, String fromStatus, String projectName, default int updateSubmitFieldsByIdAndStatus(Long id, String fromStatus, String projectName,
Long projectOwnerId, String projectOwnerName, Long projectOwnerId, String projectOwnerName,
List<WorkReportMemberSnapshotItem> projectMemberSnapshot, List<WorkReportMemberSnapshotItem> projectMemberSnapshot,
Long supervisorUserId, String supervisorName, String toStatus, Long supervisorUserId, String supervisorName, String toStatus,
LocalDateTime submitTime, String updater) { LocalDateTime submitTime, String updater) {
return update(null, new LambdaUpdateWrapper<ProjectReportDO>() return update(null, new LambdaUpdateWrapper<ProjectReportDO>()
.set(ProjectReportDO::getProjectName, projectName) .set(ProjectReportDO::getProjectName, projectName)
.set(ProjectReportDO::getProjectOwnerId, projectOwnerId) .set(ProjectReportDO::getProjectOwnerId, projectOwnerId)
@@ -120,8 +144,8 @@ public interface ProjectReportMapper extends BaseMapperX<ProjectReportDO> {
} }
default int updateApprovalFieldsByIdAndStatus(Long id, String fromStatus, String toStatus, default int updateApprovalFieldsByIdAndStatus(Long id, String fromStatus, String toStatus,
LocalDateTime approvalTime, String approvalComment, LocalDateTime approvalTime, String approvalComment,
String lastStatusReason, String updater) { String lastStatusReason, String updater) {
return update(null, new LambdaUpdateWrapper<ProjectReportDO>() return update(null, new LambdaUpdateWrapper<ProjectReportDO>()
.set(ProjectReportDO::getStatusCode, toStatus) .set(ProjectReportDO::getStatusCode, toStatus)
.set(ProjectReportDO::getApprovalTime, approvalTime) .set(ProjectReportDO::getApprovalTime, approvalTime)
@@ -134,7 +158,7 @@ public interface ProjectReportMapper extends BaseMapperX<ProjectReportDO> {
} }
default int updateByIdAndStatusesAndReporterId(ProjectReportDO update, Long id, Collection<String> statuses, default int updateByIdAndStatusesAndReporterId(ProjectReportDO update, Long id, Collection<String> statuses,
Long reporterId) { Long reporterId) {
return update(update, new LambdaQueryWrapperX<ProjectReportDO>() return update(update, new LambdaQueryWrapperX<ProjectReportDO>()
.eq(ProjectReportDO::getId, id) .eq(ProjectReportDO::getId, id)
.eq(ProjectReportDO::getProjectOwnerId, reporterId) .eq(ProjectReportDO::getProjectOwnerId, reporterId)

View File

@@ -10,6 +10,7 @@ import com.njcn.rdms.module.project.dal.dataobject.workreport.weekly.WeeklyRepor
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@@ -24,7 +25,7 @@ public interface WeeklyReportMapper extends BaseMapperX<WeeklyReportDO> {
} }
default List<WeeklyReportDO> selectListByReporterIdsAndPeriodKey(Collection<Long> reporterIds, String periodKey, default List<WeeklyReportDO> selectListByReporterIdsAndPeriodKey(Collection<Long> reporterIds, String periodKey,
Collection<String> allowedStatusCodes) { Collection<String> allowedStatusCodes) {
if (reporterIds == null || reporterIds.isEmpty() || !StringUtils.hasText(periodKey)) { if (reporterIds == null || reporterIds.isEmpty() || !StringUtils.hasText(periodKey)) {
return List.of(); return List.of();
} }
@@ -40,12 +41,34 @@ public interface WeeklyReportMapper extends BaseMapperX<WeeklyReportDO> {
return selectList(wrapper); return selectList(wrapper);
} }
/**
* 按报告人 ID 列表与周期日期区间查询周报periodStartDate 落在 [startDate, endDate] 内)。
*/
default List<WeeklyReportDO> selectListByReporterIdsAndPeriodDateRange(Collection<Long> reporterIds,
LocalDate startDate, LocalDate endDate,
Collection<String> allowedStatusCodes) {
if (reporterIds == null || reporterIds.isEmpty()) {
return List.of();
}
LambdaQueryWrapperX<WeeklyReportDO> wrapper = new LambdaQueryWrapperX<WeeklyReportDO>()
.in(WeeklyReportDO::getReporterId, reporterIds)
.geIfPresent(WeeklyReportDO::getPeriodStartDate, startDate)
.leIfPresent(WeeklyReportDO::getPeriodStartDate, endDate);
if (allowedStatusCodes != null) {
if (allowedStatusCodes.isEmpty()) {
return List.of();
}
wrapper.in(WeeklyReportDO::getStatusCode, allowedStatusCodes);
}
return selectList(wrapper);
}
default PageResult<WeeklyReportDO> selectReporterPage(Long reporterId, WeeklyReportPageReqVO reqVO) { default PageResult<WeeklyReportDO> selectReporterPage(Long reporterId, WeeklyReportPageReqVO reqVO) {
return selectReporterPage(reporterId, reqVO, null); return selectReporterPage(reporterId, reqVO, null);
} }
default PageResult<WeeklyReportDO> selectReporterPage(Long reporterId, WeeklyReportPageReqVO reqVO, default PageResult<WeeklyReportDO> selectReporterPage(Long reporterId, WeeklyReportPageReqVO reqVO,
Collection<String> allowedStatusCodes) { Collection<String> allowedStatusCodes) {
if (allowedStatusCodes != null && allowedStatusCodes.isEmpty()) { if (allowedStatusCodes != null && allowedStatusCodes.isEmpty()) {
return new PageResult<>(List.of(), 0L); return new PageResult<>(List.of(), 0L);
} }
@@ -60,8 +83,9 @@ public interface WeeklyReportMapper extends BaseMapperX<WeeklyReportDO> {
} }
default PageResult<WeeklyReportDO> selectReporterPage(Collection<Long> reporterIds, WeeklyReportPageReqVO reqVO, default PageResult<WeeklyReportDO> selectReporterPage(Collection<Long> reporterIds, WeeklyReportPageReqVO reqVO,
Collection<String> allowedStatusCodes) { Collection<String> allowedStatusCodes) {
if (reporterIds == null || reporterIds.isEmpty() || (allowedStatusCodes != null && allowedStatusCodes.isEmpty())) { if (reporterIds == null || reporterIds.isEmpty()
|| (allowedStatusCodes != null && allowedStatusCodes.isEmpty())) {
return new PageResult<>(List.of(), 0L); return new PageResult<>(List.of(), 0L);
} }
LambdaQueryWrapperX<WeeklyReportDO> wrapper = buildPageQuery(reqVO) LambdaQueryWrapperX<WeeklyReportDO> wrapper = buildPageQuery(reqVO)
@@ -90,9 +114,9 @@ public interface WeeklyReportMapper extends BaseMapperX<WeeklyReportDO> {
} }
default int updateSubmitFieldsByIdAndStatus(Long id, String fromStatus, String reporterDeptName, default int updateSubmitFieldsByIdAndStatus(Long id, String fromStatus, String reporterDeptName,
String reporterPostName, Long supervisorUserId, String reporterPostName, Long supervisorUserId,
String supervisorName, String toStatus, LocalDateTime submitTime, String supervisorName, String toStatus, LocalDateTime submitTime,
String updater) { String updater) {
return update(null, new LambdaUpdateWrapper<WeeklyReportDO>() return update(null, new LambdaUpdateWrapper<WeeklyReportDO>()
.set(WeeklyReportDO::getReporterDeptName, reporterDeptName) .set(WeeklyReportDO::getReporterDeptName, reporterDeptName)
.set(WeeklyReportDO::getReporterPostName, reporterPostName) .set(WeeklyReportDO::getReporterPostName, reporterPostName)
@@ -110,8 +134,8 @@ public interface WeeklyReportMapper extends BaseMapperX<WeeklyReportDO> {
} }
default int updateApprovalFieldsByIdAndStatus(Long id, String fromStatus, String toStatus, default int updateApprovalFieldsByIdAndStatus(Long id, String fromStatus, String toStatus,
LocalDateTime approvalTime, String approvalComment, LocalDateTime approvalTime, String approvalComment,
String lastStatusReason, String updater) { String lastStatusReason, String updater) {
return update(null, new LambdaUpdateWrapper<WeeklyReportDO>() return update(null, new LambdaUpdateWrapper<WeeklyReportDO>()
.set(WeeklyReportDO::getStatusCode, toStatus) .set(WeeklyReportDO::getStatusCode, toStatus)
.set(WeeklyReportDO::getApprovalTime, approvalTime) .set(WeeklyReportDO::getApprovalTime, approvalTime)
@@ -124,7 +148,7 @@ public interface WeeklyReportMapper extends BaseMapperX<WeeklyReportDO> {
} }
default int updateByIdAndStatusesAndReporterId(WeeklyReportDO update, Long id, Collection<String> statuses, default int updateByIdAndStatusesAndReporterId(WeeklyReportDO update, Long id, Collection<String> statuses,
Long reporterId) { Long reporterId) {
return update(update, new LambdaQueryWrapperX<WeeklyReportDO>() return update(update, new LambdaQueryWrapperX<WeeklyReportDO>()
.eq(WeeklyReportDO::getId, id) .eq(WeeklyReportDO::getId, id)
.eq(WeeklyReportDO::getReporterId, reporterId) .eq(WeeklyReportDO::getReporterId, reporterId)

View File

@@ -11,21 +11,14 @@ import com.njcn.rdms.module.project.service.overtime.OvertimeApplicationService;
import com.njcn.rdms.module.project.service.team.TeamDashboardAccessService; import com.njcn.rdms.module.project.service.team.TeamDashboardAccessService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.YearMonth; import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.List; import java.util.List;
import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
@Service @Service
public class TeamOvertimeServiceImpl implements TeamOvertimeService { public class TeamOvertimeServiceImpl implements TeamOvertimeService {
private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM");
@Resource @Resource
private TeamDashboardAccessService teamDashboardAccessService; private TeamDashboardAccessService teamDashboardAccessService;
@Resource @Resource
@@ -36,10 +29,15 @@ public class TeamOvertimeServiceImpl implements TeamOvertimeService {
teamDashboardAccessService.validateTeamDashboardPermission( teamDashboardAccessService.validateTeamDashboardPermission(
OvertimeApplicationConstants.PERMISSION_TEAM_DASHBOARD); OvertimeApplicationConstants.PERMISSION_TEAM_DASHBOARD);
List<Long> subordinateIds = teamDashboardAccessService.getAllSubordinateUserIds(); List<Long> subordinateIds = teamDashboardAccessService.getAllSubordinateUserIds();
YearMonth month = parseMonth(reqVO == null ? null : reqVO.getMonth()); LocalDate[] dateRange = normalizeDateRange(
reqVO == null ? null : reqVO.getOvertimeDateStart(),
reqVO == null ? null : reqVO.getOvertimeDateEnd());
LocalDate startDate = dateRange[0];
LocalDate endDate = dateRange[1];
TeamOvertimeSummaryRespVO respVO = new TeamOvertimeSummaryRespVO(); TeamOvertimeSummaryRespVO respVO = new TeamOvertimeSummaryRespVO();
respVO.setMonth(month.format(MONTH_FORMATTER)); respVO.setOvertimeDateStart(startDate);
respVO.setOvertimeDateEnd(endDate);
if (subordinateIds.isEmpty()) { if (subordinateIds.isEmpty()) {
respVO.setTotalApplicationCount(0); respVO.setTotalApplicationCount(0);
respVO.setPendingCount(0); respVO.setPendingCount(0);
@@ -52,7 +50,7 @@ public class TeamOvertimeServiceImpl implements TeamOvertimeService {
pageReqVO.setApplicantIds(subordinateIds); pageReqVO.setApplicantIds(subordinateIds);
pageReqVO.setPageNo(1); pageReqVO.setPageNo(1);
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
pageReqVO.setOvertimeDate(new LocalDate[]{month.atDay(1), month.atEndOfMonth()}); pageReqVO.setOvertimeDate(new LocalDate[] { startDate, endDate });
PageResult<OvertimeApplicationRespVO> page = overtimeApplicationService.getMyPage(pageReqVO); PageResult<OvertimeApplicationRespVO> page = overtimeApplicationService.getMyPage(pageReqVO);
int pendingCount = 0; int pendingCount = 0;
@@ -74,14 +72,20 @@ public class TeamOvertimeServiceImpl implements TeamOvertimeService {
return respVO; return respVO;
} }
private YearMonth parseMonth(String month) { /**
if (!StringUtils.hasText(month)) { * 规范化日期区间:两者都不传时默认当月 [月初, 月末];支持半开区间。
return YearMonth.now(); */
private LocalDate[] normalizeDateRange(LocalDate start, LocalDate end) {
if (start == null && end == null) {
YearMonth currentMonth = YearMonth.now();
return new LocalDate[] { currentMonth.atDay(1), currentMonth.atEndOfMonth() };
} }
try { if (start == null) {
return YearMonth.parse(month, MONTH_FORMATTER); start = end.withDayOfMonth(1);
} catch (DateTimeParseException ex) {
throw invalidParamException("统计月份格式不正确,应为 yyyy-MM");
} }
if (end == null) {
end = start.withDayOfMonth(start.lengthOfMonth());
}
return new LocalDate[] { start, end };
} }
} }

View File

@@ -28,6 +28,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@@ -70,12 +71,28 @@ public class TeamWorkReportServiceImpl implements TeamWorkReportService {
@Override @Override
public TeamReportSummaryRespVO getSummary(TeamReportSummaryReqVO reqVO) { public TeamReportSummaryRespVO getSummary(TeamReportSummaryReqVO reqVO) {
teamDashboardAccessService.validateTeamDashboardPermission(WorkReportConstants.PERMISSION_TEAM_DASHBOARD); teamDashboardAccessService.validateTeamDashboardPermission(WorkReportConstants.PERMISSION_TEAM_DASHBOARD);
ReportContext context = buildReportContext(normalizeReportType(reqVO.getReportType()), reqVO.getPeriodKey()); String reportType = normalizeReportType(reqVO.getReportType());
boolean useDateRange = reqVO.getPeriodStartDate() != null || reqVO.getPeriodEndDate() != null;
ReportContext context;
LocalDate respStartDate;
LocalDate respEndDate;
if (useDateRange) {
respStartDate = reqVO.getPeriodStartDate();
respEndDate = reqVO.getPeriodEndDate();
context = buildReportContextByDateRange(reportType, respStartDate, respEndDate);
} else {
context = buildReportContext(reportType, reqVO.getPeriodKey());
respStartDate = null;
respEndDate = null;
}
TeamReportSummaryRespVO respVO = new TeamReportSummaryRespVO(); TeamReportSummaryRespVO respVO = new TeamReportSummaryRespVO();
respVO.setPeriodStartDate(respStartDate);
respVO.setPeriodEndDate(respEndDate);
respVO.setTotalShouldSubmit(context.expectedUserIds().size()); respVO.setTotalShouldSubmit(context.expectedUserIds().size());
respVO.setSubmittedCount(context.submittedUserIds().size()); respVO.setSubmittedCount(context.submittedUserIds().size());
respVO.setPendingApprovalCount(context.pendingApprovalUserIds().size()); respVO.setPendingApprovalCount(context.pendingApprovalUserIds().size());
List<TeamReportSummaryRespVO.PendingUser> unsubmittedUsers = buildPendingUsers(context.expectedUserIds(), context.submittedUserIds()); List<TeamReportSummaryRespVO.PendingUser> unsubmittedUsers = buildPendingUsers(context.expectedUserIds(),
context.submittedUserIds());
respVO.setUnsubmittedUsers(unsubmittedUsers); respVO.setUnsubmittedUsers(unsubmittedUsers);
respVO.setUnsubmittedCount(unsubmittedUsers.size()); respVO.setUnsubmittedCount(unsubmittedUsers.size());
return respVO; return respVO;
@@ -205,7 +222,8 @@ public class TeamWorkReportServiceImpl implements TeamWorkReportService {
return Collections.emptyList(); return Collections.emptyList();
} }
List<String> terminalStatusCodes = objectStatusModelMapper List<String> terminalStatusCodes = objectStatusModelMapper
.selectTerminalStatusCodesByObjectTypeEnabled(com.njcn.rdms.module.project.constant.ProjectObjectConstants.OBJECT_TYPE); .selectTerminalStatusCodesByObjectTypeEnabled(
com.njcn.rdms.module.project.constant.ProjectObjectConstants.OBJECT_TYPE);
List<ProjectDO> allProjects = projectMapper.selectListByManagerUserIdsAndStatusCodesNotIn( List<ProjectDO> allProjects = projectMapper.selectListByManagerUserIdsAndStatusCodesNotIn(
subordinateIds, terminalStatusCodes); subordinateIds, terminalStatusCodes);
if (allProjects.isEmpty()) { if (allProjects.isEmpty()) {
@@ -231,7 +249,7 @@ public class TeamWorkReportServiceImpl implements TeamWorkReportService {
} }
private List<TeamReportSummaryRespVO.PendingUser> buildPendingUsers(List<Long> expectedUserIds, private List<TeamReportSummaryRespVO.PendingUser> buildPendingUsers(List<Long> expectedUserIds,
Set<Long> submittedUserIds) { Set<Long> submittedUserIds) {
LinkedHashSet<Long> pendingIds = new LinkedHashSet<>(expectedUserIds); LinkedHashSet<Long> pendingIds = new LinkedHashSet<>(expectedUserIds);
pendingIds.removeAll(submittedUserIds); pendingIds.removeAll(submittedUserIds);
if (pendingIds.isEmpty()) { if (pendingIds.isEmpty()) {
@@ -245,7 +263,8 @@ public class TeamWorkReportServiceImpl implements TeamWorkReportService {
Map<Long, AdminUserRespDTO> userMap = users.stream() Map<Long, AdminUserRespDTO> userMap = users.stream()
.filter(Objects::nonNull) .filter(Objects::nonNull)
.filter(user -> user.getId() != null) .filter(user -> user.getId() != null)
.collect(Collectors.toMap(AdminUserRespDTO::getId, user -> user, (left, right) -> left, LinkedHashMap::new)); .collect(Collectors.toMap(AdminUserRespDTO::getId, user -> user, (left, right) -> left,
LinkedHashMap::new));
List<TeamReportSummaryRespVO.PendingUser> respList = new ArrayList<>(); List<TeamReportSummaryRespVO.PendingUser> respList = new ArrayList<>();
for (Long pendingId : pendingIds) { for (Long pendingId : pendingIds) {
AdminUserRespDTO user = userMap.get(pendingId); AdminUserRespDTO user = userMap.get(pendingId);
@@ -279,6 +298,103 @@ public class TeamWorkReportServiceImpl implements TeamWorkReportService {
return StringUtils.hasText(text) ? text.trim() : ""; return StringUtils.hasText(text) ? text.trim() : "";
} }
private record ReportContext(List<Long> expectedUserIds, Set<Long> submittedUserIds, Set<Long> pendingApprovalUserIds) { private ReportContext buildReportContextByDateRange(String reportType, LocalDate startDate, LocalDate endDate) {
if (WorkReportConstants.REPORT_TYPE_PROJECT.equals(reportType)) {
return buildProjectContextByDateRange(startDate, endDate);
}
List<Long> subordinateIds = teamDashboardAccessService.getAllSubordinateUserIds();
if (subordinateIds.isEmpty()) {
return new ReportContext(Collections.emptyList(), Collections.emptySet(), Collections.emptySet());
}
if (WorkReportConstants.REPORT_TYPE_WEEKLY.equals(reportType)) {
return buildWeeklyContextByDateRange(startDate, endDate, subordinateIds);
}
return buildMonthlyContextByDateRange(startDate, endDate, subordinateIds);
}
private ReportContext buildWeeklyContextByDateRange(LocalDate startDate, LocalDate endDate,
List<Long> subordinateIds) {
List<WeeklyReportDO> reports = weeklyReportMapper.selectListByReporterIdsAndPeriodDateRange(
subordinateIds, startDate, endDate, SUBMITTED_STATUS_CODES);
Set<Long> submittedUserIds = new LinkedHashSet<>();
Set<Long> pendingApprovalUserIds = new LinkedHashSet<>();
for (WeeklyReportDO report : reports) {
if (report == null || report.getReporterId() == null) {
continue;
}
submittedUserIds.add(report.getReporterId());
if (WorkReportConstants.STATUS_PENDING_APPROVAL.equals(report.getStatusCode())) {
pendingApprovalUserIds.add(report.getReporterId());
}
}
return new ReportContext(subordinateIds, submittedUserIds, pendingApprovalUserIds);
}
private ReportContext buildMonthlyContextByDateRange(LocalDate startDate, LocalDate endDate,
List<Long> subordinateIds) {
List<MonthlyReportDO> reports = monthlyReportMapper.selectListByReporterIdsAndPeriodDateRange(
subordinateIds, startDate, endDate, SUBMITTED_STATUS_CODES);
Set<Long> submittedUserIds = new LinkedHashSet<>();
Set<Long> pendingApprovalUserIds = new LinkedHashSet<>();
for (MonthlyReportDO report : reports) {
if (report == null || report.getReporterId() == null) {
continue;
}
submittedUserIds.add(report.getReporterId());
if (WorkReportConstants.STATUS_PENDING_APPROVAL.equals(report.getStatusCode())) {
pendingApprovalUserIds.add(report.getReporterId());
}
}
return new ReportContext(subordinateIds, submittedUserIds, pendingApprovalUserIds);
}
private ReportContext buildProjectContextByDateRange(LocalDate startDate, LocalDate endDate) {
List<Long> subordinateIds = teamDashboardAccessService.getAllSubordinateUserIds();
if (subordinateIds.isEmpty()) {
return new ReportContext(Collections.emptyList(), Collections.emptySet(), Collections.emptySet());
}
List<ProjectDO> activeProjects = loadActiveProjectsForSubordinates(subordinateIds);
if (activeProjects.isEmpty()) {
return new ReportContext(Collections.emptyList(), Collections.emptySet(), Collections.emptySet());
}
Map<Long, List<ProjectDO>> projectsByOwner = activeProjects.stream()
.filter(Objects::nonNull)
.filter(project -> project.getManagerUserId() != null)
.collect(Collectors.groupingBy(ProjectDO::getManagerUserId, LinkedHashMap::new, Collectors.toList()));
LinkedHashSet<Long> expectedUserIds = new LinkedHashSet<>(projectsByOwner.keySet());
List<ProjectReportDO> reports = projectReportMapper.selectListByProjectOwnerIdsAndPeriodDateRange(
expectedUserIds, startDate, endDate, SUBMITTED_STATUS_CODES);
Map<Long, Set<Long>> submittedProjectsByOwner = new HashMap<>();
Set<Long> submittedUserIds = new LinkedHashSet<>();
Set<Long> pendingApprovalUserIds = new LinkedHashSet<>();
for (ProjectReportDO report : reports) {
if (report == null || report.getProjectOwnerId() == null || report.getProjectId() == null) {
continue;
}
Long ownerId = report.getProjectOwnerId();
if (!expectedUserIds.contains(ownerId)) {
continue;
}
if (WorkReportConstants.STATUS_PENDING_APPROVAL.equals(report.getStatusCode())) {
pendingApprovalUserIds.add(ownerId);
}
submittedProjectsByOwner.computeIfAbsent(ownerId, key -> new LinkedHashSet<>()).add(report.getProjectId());
}
for (Map.Entry<Long, List<ProjectDO>> entry : projectsByOwner.entrySet()) {
Long ownerId = entry.getKey();
Set<Long> submittedProjectIds = submittedProjectsByOwner.getOrDefault(ownerId, Collections.emptySet());
boolean allSubmitted = entry.getValue().stream()
.map(ProjectDO::getId)
.filter(Objects::nonNull)
.allMatch(submittedProjectIds::contains);
if (allSubmitted) {
submittedUserIds.add(ownerId);
}
}
return new ReportContext(new ArrayList<>(expectedUserIds), submittedUserIds, pendingApprovalUserIds);
}
private record ReportContext(List<Long> expectedUserIds, Set<Long> submittedUserIds,
Set<Long> pendingApprovalUserIds) {
} }
} }

View File

@@ -18,7 +18,11 @@ import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success; import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@@ -90,4 +94,24 @@ public class DeptController {
return success(BeanUtils.toBean(dept, DeptRespVO.class)); return success(BeanUtils.toBean(dept, DeptRespVO.class));
} }
@GetMapping("/list-self-and-children")
@Operation(summary = "获取部门自身及全部子部门")
@Parameter(name = "id", description = "部门编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:dept:query')")
public CommonResult<List<DeptSimpleRespVO>> getDeptSelfAndChildren(@RequestParam("id") Long id) {
DeptDO self = deptService.getDept(id);
if (self == null) {
return success(List.of());
}
List<DeptDO> combined = new ArrayList<>();
combined.add(self);
combined.addAll(deptService.getChildDeptList(id));
Map<Long, DeptDO> distinctMap = new LinkedHashMap<>();
combined.forEach(dept -> distinctMap.putIfAbsent(dept.getId(), dept));
List<DeptDO> result = new ArrayList<>(distinctMap.values());
result.sort(Comparator.comparing(DeptDO::getSort, Comparator.nullsLast(Integer::compareTo))
.thenComparing(DeptDO::getId, Comparator.nullsLast(Long::compareTo)));
return success(BeanUtils.toBean(result, DeptSimpleRespVO.class));
}
} }

View File

@@ -15,6 +15,7 @@ import com.njcn.rdms.module.system.dal.dataobject.dept.DeptDO;
import com.njcn.rdms.module.system.dal.dataobject.user.AdminUserDO; import com.njcn.rdms.module.system.dal.dataobject.user.AdminUserDO;
import com.njcn.rdms.module.system.dal.dataobject.user.UserManagementRelationDO; import com.njcn.rdms.module.system.dal.dataobject.user.UserManagementRelationDO;
import com.njcn.rdms.module.system.service.dept.DeptService; import com.njcn.rdms.module.system.service.dept.DeptService;
import com.njcn.rdms.module.system.service.user.AdminUserService;
import com.njcn.rdms.module.system.service.user.UserManagementRelationService; import com.njcn.rdms.module.system.service.user.UserManagementRelationService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
@@ -27,9 +28,13 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import static com.njcn.rdms.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static com.njcn.rdms.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success; import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@@ -58,6 +63,9 @@ public class UserManagementRelationController {
@Resource @Resource
private UserManagementRelationService userManagementRelationService; private UserManagementRelationService userManagementRelationService;
@Resource
private AdminUserService adminUserService;
/** /**
* 创建用户管理链路 * 创建用户管理链路
* *
@@ -192,6 +200,47 @@ public class UserManagementRelationController {
return success(UserConvert.INSTANCE.convertSimpleList(users, deptMap)); return success(UserConvert.INSTANCE.convertSimpleList(users, deptMap));
} }
/**
* 获取某用户当前生效的直属下级列表。
*
* 口径:只返回直接下级,不递归孙级;仅返回当前生效的管理链路。
*/
@GetMapping("/direct-subordinates")
@Operation(summary = "获取某用户当前生效的直属下级列表")
@Parameter(name = "userId", description = "用户ID", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:user-management-relation:query')")
public CommonResult<List<UserSimpleRespVO>> getDirectSubordinates(@RequestParam("userId") Long userId) {
List<UserManagementRelationDO> relations = userManagementRelationService.getRelationListByManagerUserId(userId);
if (relations.isEmpty()) {
return success(Collections.emptyList());
}
LocalDateTime now = LocalDateTime.now();
Set<Long> subordinateIds = new LinkedHashSet<>();
relations.stream()
.filter(relation -> relation.getSubordinateUserId() != null)
.filter(relation -> relation.getEffectiveFrom() == null || !relation.getEffectiveFrom().isAfter(now))
.filter(relation -> relation.getEffectiveUntil() == null || relation.getEffectiveUntil().isAfter(now))
.map(UserManagementRelationDO::getSubordinateUserId)
.forEach(subordinateIds::add);
if (subordinateIds.isEmpty()) {
return success(Collections.emptyList());
}
List<AdminUserDO> users = adminUserService.getUserList(subordinateIds).stream()
.filter(adminUserService::isUserAvailable)
.sorted(Comparator.comparing(AdminUserDO::getSort, Comparator.nullsLast(Integer::compareTo))
.thenComparing(AdminUserDO::getId, Comparator.nullsLast(Long::compareTo)))
.toList();
if (users.isEmpty()) {
return success(Collections.emptyList());
}
Map<Long, DeptDO> deptMap = deptService.getDeptMap(convertList(users, AdminUserDO::getDeptId));
List<UserSimpleRespVO> result = UserConvert.INSTANCE.convertSimpleList(users, deptMap).stream()
.sorted(Comparator.comparing(UserSimpleRespVO::getSort, Comparator.nullsLast(Integer::compareTo))
.thenComparing(UserSimpleRespVO::getId, Comparator.nullsLast(Long::compareTo)))
.toList();
return success(result);
}
/** /**
* 获取用户管理链路树形结构 * 获取用户管理链路树形结构
* *