feat(工作报告团队视角): 工作报告现在可以查看团队视角了(查看下属)。
fix(工作报告定时生成): 修复工作报告定时生成带来的一些问题。
This commit is contained in:
@@ -241,6 +241,8 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode OVERTIME_APPLICATION_APPROVER_SELF_FORBIDDEN = new ErrorCode(1_008_009_009, "审核人不能选择申请人本人");
|
ErrorCode OVERTIME_APPLICATION_APPROVER_SELF_FORBIDDEN = new ErrorCode(1_008_009_009, "审核人不能选择申请人本人");
|
||||||
ErrorCode OVERTIME_APPLICATION_READ_FORBIDDEN = new ErrorCode(1_008_009_010, "无权查看该加班申请");
|
ErrorCode OVERTIME_APPLICATION_READ_FORBIDDEN = new ErrorCode(1_008_009_010, "无权查看该加班申请");
|
||||||
ErrorCode OVERTIME_APPLICATION_DELETE_ONLY_REJECTED = new ErrorCode(1_008_009_011, "仅已退回的加班申请允许删除");
|
ErrorCode OVERTIME_APPLICATION_DELETE_ONLY_REJECTED = new ErrorCode(1_008_009_011, "仅已退回的加班申请允许删除");
|
||||||
|
ErrorCode TEAM_DASHBOARD_PERMISSION_REQUIRED = new ErrorCode(1_008_009_012, "当前用户无团队视角权限");
|
||||||
|
ErrorCode TEAM_DASHBOARD_SUBORDINATE_SCOPE_INVALID = new ErrorCode(1_008_009_013, "查询目标超出当前用户下属范围");
|
||||||
// ========== 工作报告 1_008_010_xxx ==========
|
// ========== 工作报告 1_008_010_xxx ==========
|
||||||
ErrorCode WORK_REPORT_NOT_EXISTS = new ErrorCode(1_008_010_001, "工作报告不存在");
|
ErrorCode WORK_REPORT_NOT_EXISTS = new ErrorCode(1_008_010_001, "工作报告不存在");
|
||||||
ErrorCode WORK_REPORT_STATUS_MODEL_NOT_EXISTS_OR_DISABLED = new ErrorCode(1_008_010_002, "工作报告状态定义不存在或已停用");
|
ErrorCode WORK_REPORT_STATUS_MODEL_NOT_EXISTS_OR_DISABLED = new ErrorCode(1_008_010_002, "工作报告状态定义不存在或已停用");
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.njcn.rdms.module.project.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 团队视角常量。
|
||||||
|
*/
|
||||||
|
public final class TeamDashboardConstants {
|
||||||
|
|
||||||
|
private TeamDashboardConstants() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String PERMISSION = "project:work-report:team-dashboard";
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.njcn.rdms.module.project.controller.admin.overtime.team;
|
||||||
|
|
||||||
|
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||||
|
import com.njcn.rdms.module.project.constant.TeamDashboardConstants;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.overtime.team.vo.TeamOvertimeSummaryReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.overtime.team.vo.TeamOvertimeSummaryRespVO;
|
||||||
|
import com.njcn.rdms.module.project.service.overtime.team.TeamOvertimeService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
|
@Tag(name = "管理后台 - 团队加班申请")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/project/overtime-applications/team")
|
||||||
|
@Validated
|
||||||
|
public class TeamOvertimeController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TeamOvertimeService teamOvertimeService;
|
||||||
|
|
||||||
|
@GetMapping("/summary")
|
||||||
|
@Operation(summary = "获取团队加班申请统计")
|
||||||
|
@PreAuthorize("@ss.hasPermission('" + TeamDashboardConstants.PERMISSION + "')")
|
||||||
|
public CommonResult<TeamOvertimeSummaryRespVO> getSummary(@Valid TeamOvertimeSummaryReqVO reqVO) {
|
||||||
|
return success(teamOvertimeService.getSummary(reqVO));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.njcn.rdms.module.project.controller.admin.overtime.team.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 团队加班申请统计 Request VO")
|
||||||
|
@Data
|
||||||
|
public class TeamOvertimeSummaryReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "统计月份,不传默认当前月", example = "2026-06")
|
||||||
|
private String month;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.njcn.rdms.module.project.controller.admin.overtime.team.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 团队加班申请统计 Response VO")
|
||||||
|
@Data
|
||||||
|
public class TeamOvertimeSummaryRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "统计月份", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026-06")
|
||||||
|
private String month;
|
||||||
|
|
||||||
|
@Schema(description = "申请总数", requiredMode = Schema.RequiredMode.REQUIRED, example = "12")
|
||||||
|
private Integer totalApplicationCount;
|
||||||
|
|
||||||
|
@Schema(description = "待审批数", requiredMode = Schema.RequiredMode.REQUIRED, example = "3")
|
||||||
|
private Integer pendingCount;
|
||||||
|
|
||||||
|
@Schema(description = "已通过数", requiredMode = Schema.RequiredMode.REQUIRED, example = "7")
|
||||||
|
private Integer approvedCount;
|
||||||
|
|
||||||
|
@Schema(description = "已退回数", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||||
|
private Integer rejectedCount;
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import org.springframework.format.annotation.DateTimeFormat;
|
|||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
|
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
|
||||||
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
@@ -18,6 +19,9 @@ import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MON
|
|||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class OvertimeApplicationPageReqVO extends PageParam {
|
public class OvertimeApplicationPageReqVO extends PageParam {
|
||||||
|
|
||||||
|
@Schema(description = "团队视角下的申请人用户编号列表")
|
||||||
|
private List<Long> applicantIds;
|
||||||
|
|
||||||
@Schema(description = "关键词,匹配加班原因或加班内容", example = "上线")
|
@Schema(description = "关键词,匹配加班原因或加班内容", example = "上线")
|
||||||
private String keyword;
|
private String keyword;
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,13 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 月报分页 Request VO")
|
@Schema(description = "管理后台 - 月报分页 Request VO")
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class MonthlyReportPageReqVO extends WorkReportBasePageReqVO {
|
public class MonthlyReportPageReqVO extends WorkReportBasePageReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "团队视角下的填报人用户编号列表")
|
||||||
|
private List<Long> reporterIds;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,16 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 项目半月报分页 Request VO")
|
@Schema(description = "管理后台 - 项目半月报分页 Request VO")
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class ProjectReportPageReqVO extends WorkReportBasePageReqVO {
|
public class ProjectReportPageReqVO extends WorkReportBasePageReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "团队视角下的项目负责人用户编号列表")
|
||||||
|
private List<Long> projectOwnerIds;
|
||||||
|
|
||||||
@Schema(description = "项目编号")
|
@Schema(description = "项目编号")
|
||||||
private Long projectId;
|
private Long projectId;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package com.njcn.rdms.module.project.controller.admin.workreport.team;
|
||||||
|
|
||||||
|
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||||
|
import com.njcn.rdms.module.project.constant.TeamDashboardConstants;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.team.vo.TeamReportRemindReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.team.vo.TeamReportRemindRespVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.team.vo.TeamReportSummaryReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.team.vo.TeamReportSummaryRespVO;
|
||||||
|
import com.njcn.rdms.module.project.service.workreport.team.TeamWorkReportService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
|
@Tag(name = "管理后台 - 团队工作报告")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/project/work-reports/team")
|
||||||
|
@Validated
|
||||||
|
public class TeamWorkReportController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TeamWorkReportService teamWorkReportService;
|
||||||
|
|
||||||
|
@GetMapping("/summary")
|
||||||
|
@Operation(summary = "获取团队工作报告统计")
|
||||||
|
@PreAuthorize("@ss.hasPermission('" + TeamDashboardConstants.PERMISSION + "')")
|
||||||
|
public CommonResult<TeamReportSummaryRespVO> getSummary(@Valid TeamReportSummaryReqVO reqVO) {
|
||||||
|
return success(teamWorkReportService.getSummary(reqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/remind")
|
||||||
|
@Operation(summary = "催办团队工作报告")
|
||||||
|
@PreAuthorize("@ss.hasPermission('" + TeamDashboardConstants.PERMISSION + "')")
|
||||||
|
public CommonResult<TeamReportRemindRespVO> remind(@Valid @RequestBody TeamReportRemindReqVO reqVO) {
|
||||||
|
return success(teamWorkReportService.remind(reqVO));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.njcn.rdms.module.project.controller.admin.workreport.team.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 团队工作报告催办 Request VO")
|
||||||
|
@Data
|
||||||
|
public class TeamReportRemindReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "报告类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "weekly")
|
||||||
|
@NotBlank(message = "报告类型不能为空")
|
||||||
|
private String reportType;
|
||||||
|
|
||||||
|
@Schema(description = "周期主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "weekly-2026-06-08-2026-06-14")
|
||||||
|
@NotBlank(message = "周期主键不能为空")
|
||||||
|
private String periodKey;
|
||||||
|
|
||||||
|
@Schema(description = "催办用户 ID 列表;不传则催办全部待提交用户")
|
||||||
|
private List<Long> userIds;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.njcn.rdms.module.project.controller.admin.workreport.team.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 团队工作报告催办 Response VO")
|
||||||
|
@Data
|
||||||
|
public class TeamReportRemindRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "实际催办人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "4")
|
||||||
|
private Integer remindedCount;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.njcn.rdms.module.project.controller.admin.workreport.team.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 团队工作报告统计 Request VO")
|
||||||
|
@Data
|
||||||
|
public class TeamReportSummaryReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "报告类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "weekly")
|
||||||
|
@NotBlank(message = "报告类型不能为空")
|
||||||
|
private String reportType;
|
||||||
|
|
||||||
|
@Schema(description = "周期主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "weekly-2026-06-08-2026-06-14")
|
||||||
|
@NotBlank(message = "周期主键不能为空")
|
||||||
|
private String periodKey;
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.njcn.rdms.module.project.controller.admin.workreport.team.vo;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 团队工作报告统计 Response VO")
|
||||||
|
@Data
|
||||||
|
public class TeamReportSummaryRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "应填人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "18")
|
||||||
|
private Integer totalShouldSubmit;
|
||||||
|
|
||||||
|
@Schema(description = "已提交人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "12")
|
||||||
|
private Integer submittedCount;
|
||||||
|
|
||||||
|
@Schema(description = "未提交人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "6")
|
||||||
|
private Integer unsubmittedCount;
|
||||||
|
|
||||||
|
@Schema(description = "待审批人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
|
||||||
|
private Integer pendingApprovalCount;
|
||||||
|
|
||||||
|
@Schema(description = "未提交人员列表")
|
||||||
|
private List<PendingUser> unsubmittedUsers;
|
||||||
|
|
||||||
|
@Schema(description = "未提交人员")
|
||||||
|
@Data
|
||||||
|
public static class PendingUser {
|
||||||
|
|
||||||
|
@Schema(description = "用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2042074259501088770")
|
||||||
|
@com.fasterxml.jackson.databind.annotation.JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "戴坤")
|
||||||
|
private String userNickname;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,11 +5,16 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 周报分页 Request VO")
|
@Schema(description = "管理后台 - 周报分页 Request VO")
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class WeeklyReportPageReqVO extends WorkReportBasePageReqVO {
|
public class WeeklyReportPageReqVO extends WorkReportBasePageReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "团队视角下的填报人用户编号列表")
|
||||||
|
private List<Long> reporterIds;
|
||||||
|
|
||||||
@Schema(description = "是否出差")
|
@Schema(description = "是否出差")
|
||||||
private Boolean isBusinessTrip;
|
private Boolean isBusinessTrip;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.apache.ibatis.annotations.Mapper;
|
|||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface OvertimeApplicationMapper extends BaseMapperX<OvertimeApplicationDO> {
|
public interface OvertimeApplicationMapper extends BaseMapperX<OvertimeApplicationDO> {
|
||||||
@@ -22,6 +23,22 @@ public interface OvertimeApplicationMapper extends BaseMapperX<OvertimeApplicati
|
|||||||
return selectPage(reqVO, queryWrapper);
|
return selectPage(reqVO, queryWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default PageResult<OvertimeApplicationDO> selectMyPage(Collection<Long> applicantIds,
|
||||||
|
OvertimeApplicationPageReqVO reqVO,
|
||||||
|
Collection<String> allowedStatusCodes) {
|
||||||
|
if (applicantIds == null || applicantIds.isEmpty() || (allowedStatusCodes != null && allowedStatusCodes.isEmpty())) {
|
||||||
|
return new PageResult<>(List.of(), 0L);
|
||||||
|
}
|
||||||
|
LambdaQueryWrapperX<OvertimeApplicationDO> queryWrapper = buildPageQuery(reqVO);
|
||||||
|
queryWrapper.in(OvertimeApplicationDO::getApplicantId, applicantIds);
|
||||||
|
if (allowedStatusCodes != null) {
|
||||||
|
queryWrapper.in(OvertimeApplicationDO::getStatusCode, allowedStatusCodes);
|
||||||
|
}
|
||||||
|
queryWrapper.orderByDesc(OvertimeApplicationDO::getSubmitTime)
|
||||||
|
.orderByDesc(OvertimeApplicationDO::getId);
|
||||||
|
return selectPage(reqVO, queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
default PageResult<OvertimeApplicationDO> selectApprovalPage(Long approverId, OvertimeApplicationPageReqVO reqVO) {
|
default PageResult<OvertimeApplicationDO> selectApprovalPage(Long approverId, OvertimeApplicationPageReqVO reqVO) {
|
||||||
LambdaQueryWrapperX<OvertimeApplicationDO> queryWrapper = buildPageQuery(reqVO);
|
LambdaQueryWrapperX<OvertimeApplicationDO> queryWrapper = buildPageQuery(reqVO);
|
||||||
queryWrapper.eq(OvertimeApplicationDO::getApproverId, approverId);
|
queryWrapper.eq(OvertimeApplicationDO::getApproverId, approverId);
|
||||||
|
|||||||
@@ -75,6 +75,20 @@ public interface ProjectMapper extends BaseMapperX<ProjectDO> {
|
|||||||
return selectList(queryWrapper);
|
return selectList(queryWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default List<ProjectDO> selectListByManagerUserIdsAndStatusCodesNotIn(Collection<Long> managerUserIds,
|
||||||
|
Collection<String> statusCodes) {
|
||||||
|
if (managerUserIds == null || managerUserIds.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
LambdaQueryWrapperX<ProjectDO> queryWrapper = new LambdaQueryWrapperX<ProjectDO>()
|
||||||
|
.in(ProjectDO::getManagerUserId, managerUserIds)
|
||||||
|
.orderByDesc(BaseDO::getCreateTime);
|
||||||
|
if (statusCodes != null && !statusCodes.isEmpty()) {
|
||||||
|
queryWrapper.notIn(ProjectDO::getStatusCode, statusCodes);
|
||||||
|
}
|
||||||
|
return selectList(queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
default int updateStatusByIdAndStatus(Long id, String fromStatus, String toStatus, String lastStatusReason) {
|
default int updateStatusByIdAndStatus(Long id, String fromStatus, String toStatus, String lastStatusReason) {
|
||||||
ProjectDO update = new ProjectDO();
|
ProjectDO update = new ProjectDO();
|
||||||
update.setStatusCode(toStatus);
|
update.setStatusCode(toStatus);
|
||||||
|
|||||||
@@ -23,6 +23,23 @@ public interface MonthlyReportMapper extends BaseMapperX<MonthlyReportDO> {
|
|||||||
.eq(MonthlyReportDO::getPeriodKey, periodKey));
|
.eq(MonthlyReportDO::getPeriodKey, periodKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default List<MonthlyReportDO> selectListByReporterIdsAndPeriodKey(Collection<Long> reporterIds, String periodKey,
|
||||||
|
Collection<String> allowedStatusCodes) {
|
||||||
|
if (reporterIds == null || reporterIds.isEmpty() || !StringUtils.hasText(periodKey)) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
LambdaQueryWrapperX<MonthlyReportDO> wrapper = new LambdaQueryWrapperX<MonthlyReportDO>()
|
||||||
|
.in(MonthlyReportDO::getReporterId, reporterIds)
|
||||||
|
.eq(MonthlyReportDO::getPeriodKey, periodKey);
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
@@ -42,6 +59,21 @@ public interface MonthlyReportMapper extends BaseMapperX<MonthlyReportDO> {
|
|||||||
return selectPage(reqVO, wrapper);
|
return selectPage(reqVO, wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default PageResult<MonthlyReportDO> selectReporterPage(Collection<Long> reporterIds, MonthlyReportPageReqVO reqVO,
|
||||||
|
Collection<String> allowedStatusCodes) {
|
||||||
|
if (reporterIds == null || reporterIds.isEmpty() || (allowedStatusCodes != null && allowedStatusCodes.isEmpty())) {
|
||||||
|
return new PageResult<>(List.of(), 0L);
|
||||||
|
}
|
||||||
|
LambdaQueryWrapperX<MonthlyReportDO> wrapper = buildPageQuery(reqVO)
|
||||||
|
.in(MonthlyReportDO::getReporterId, reporterIds)
|
||||||
|
.orderByDesc(MonthlyReportDO::getPeriodStartDate)
|
||||||
|
.orderByDesc(MonthlyReportDO::getId);
|
||||||
|
if (allowedStatusCodes != null) {
|
||||||
|
wrapper.in(MonthlyReportDO::getStatusCode, allowedStatusCodes);
|
||||||
|
}
|
||||||
|
return selectPage(reqVO, wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
default PageResult<MonthlyReportDO> selectApprovalPage(Long supervisorUserId, MonthlyReportPageReqVO reqVO) {
|
default PageResult<MonthlyReportDO> selectApprovalPage(Long supervisorUserId, MonthlyReportPageReqVO reqVO) {
|
||||||
LambdaQueryWrapperX<MonthlyReportDO> wrapper = buildPageQuery(reqVO)
|
LambdaQueryWrapperX<MonthlyReportDO> wrapper = buildPageQuery(reqVO)
|
||||||
.eq(MonthlyReportDO::getSupervisorUserId, supervisorUserId)
|
.eq(MonthlyReportDO::getSupervisorUserId, supervisorUserId)
|
||||||
|
|||||||
@@ -29,6 +29,24 @@ public interface ProjectReportMapper extends BaseMapperX<ProjectReportDO> {
|
|||||||
.eq(ProjectReportDO::getProjectOwnerId, projectOwnerId));
|
.eq(ProjectReportDO::getProjectOwnerId, projectOwnerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default List<ProjectReportDO> selectListByProjectOwnerIdsAndPeriodKey(Collection<Long> projectOwnerIds,
|
||||||
|
String periodKey,
|
||||||
|
Collection<String> allowedStatusCodes) {
|
||||||
|
if (projectOwnerIds == null || projectOwnerIds.isEmpty() || !StringUtils.hasText(periodKey)) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
LambdaQueryWrapperX<ProjectReportDO> wrapper = new LambdaQueryWrapperX<ProjectReportDO>()
|
||||||
|
.in(ProjectReportDO::getProjectOwnerId, projectOwnerIds)
|
||||||
|
.eq(ProjectReportDO::getPeriodKey, periodKey);
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
@@ -48,6 +66,21 @@ public interface ProjectReportMapper extends BaseMapperX<ProjectReportDO> {
|
|||||||
return selectPage(reqVO, wrapper);
|
return selectPage(reqVO, wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default PageResult<ProjectReportDO> selectReporterPage(Collection<Long> reporterIds, ProjectReportPageReqVO reqVO,
|
||||||
|
Collection<String> allowedStatusCodes) {
|
||||||
|
if (reporterIds == null || reporterIds.isEmpty() || (allowedStatusCodes != null && allowedStatusCodes.isEmpty())) {
|
||||||
|
return new PageResult<>(List.of(), 0L);
|
||||||
|
}
|
||||||
|
LambdaQueryWrapperX<ProjectReportDO> wrapper = buildPageQuery(reqVO)
|
||||||
|
.in(ProjectReportDO::getProjectOwnerId, reporterIds)
|
||||||
|
.orderByDesc(ProjectReportDO::getPeriodStartDate)
|
||||||
|
.orderByDesc(ProjectReportDO::getId);
|
||||||
|
if (allowedStatusCodes != null) {
|
||||||
|
wrapper.in(ProjectReportDO::getStatusCode, allowedStatusCodes);
|
||||||
|
}
|
||||||
|
return selectPage(reqVO, wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
default PageResult<ProjectReportDO> selectApprovalPage(Long supervisorUserId, ProjectReportPageReqVO reqVO) {
|
default PageResult<ProjectReportDO> selectApprovalPage(Long supervisorUserId, ProjectReportPageReqVO reqVO) {
|
||||||
LambdaQueryWrapperX<ProjectReportDO> wrapper = buildPageQuery(reqVO)
|
LambdaQueryWrapperX<ProjectReportDO> wrapper = buildPageQuery(reqVO)
|
||||||
.eq(ProjectReportDO::getSupervisorUserId, supervisorUserId)
|
.eq(ProjectReportDO::getSupervisorUserId, supervisorUserId)
|
||||||
|
|||||||
@@ -23,6 +23,23 @@ public interface WeeklyReportMapper extends BaseMapperX<WeeklyReportDO> {
|
|||||||
.eq(WeeklyReportDO::getPeriodKey, periodKey));
|
.eq(WeeklyReportDO::getPeriodKey, periodKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default List<WeeklyReportDO> selectListByReporterIdsAndPeriodKey(Collection<Long> reporterIds, String periodKey,
|
||||||
|
Collection<String> allowedStatusCodes) {
|
||||||
|
if (reporterIds == null || reporterIds.isEmpty() || !StringUtils.hasText(periodKey)) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
LambdaQueryWrapperX<WeeklyReportDO> wrapper = new LambdaQueryWrapperX<WeeklyReportDO>()
|
||||||
|
.in(WeeklyReportDO::getReporterId, reporterIds)
|
||||||
|
.eq(WeeklyReportDO::getPeriodKey, periodKey);
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
@@ -42,6 +59,21 @@ public interface WeeklyReportMapper extends BaseMapperX<WeeklyReportDO> {
|
|||||||
return selectPage(reqVO, wrapper);
|
return selectPage(reqVO, wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default PageResult<WeeklyReportDO> selectReporterPage(Collection<Long> reporterIds, WeeklyReportPageReqVO reqVO,
|
||||||
|
Collection<String> allowedStatusCodes) {
|
||||||
|
if (reporterIds == null || reporterIds.isEmpty() || (allowedStatusCodes != null && allowedStatusCodes.isEmpty())) {
|
||||||
|
return new PageResult<>(List.of(), 0L);
|
||||||
|
}
|
||||||
|
LambdaQueryWrapperX<WeeklyReportDO> wrapper = buildPageQuery(reqVO)
|
||||||
|
.in(WeeklyReportDO::getReporterId, reporterIds)
|
||||||
|
.orderByDesc(WeeklyReportDO::getPeriodStartDate)
|
||||||
|
.orderByDesc(WeeklyReportDO::getId);
|
||||||
|
if (allowedStatusCodes != null) {
|
||||||
|
wrapper.in(WeeklyReportDO::getStatusCode, allowedStatusCodes);
|
||||||
|
}
|
||||||
|
return selectPage(reqVO, wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
default PageResult<WeeklyReportDO> selectApprovalPage(Long supervisorUserId, WeeklyReportPageReqVO reqVO) {
|
default PageResult<WeeklyReportDO> selectApprovalPage(Long supervisorUserId, WeeklyReportPageReqVO reqVO) {
|
||||||
LambdaQueryWrapperX<WeeklyReportDO> wrapper = buildPageQuery(reqVO)
|
LambdaQueryWrapperX<WeeklyReportDO> wrapper = buildPageQuery(reqVO)
|
||||||
.eq(WeeklyReportDO::getSupervisorUserId, supervisorUserId)
|
.eq(WeeklyReportDO::getSupervisorUserId, supervisorUserId)
|
||||||
|
|||||||
@@ -25,4 +25,7 @@ public class NotifyTemplateCodeConstants {
|
|||||||
/** 逾期提醒-协办人:等级低一等的弱化文案 */
|
/** 逾期提醒-协办人:等级低一等的弱化文案 */
|
||||||
public static final String DUE_ALERT_OVERDUE_ASSIGNEE = "due_alert_overdue_assignee";
|
public static final String DUE_ALERT_OVERDUE_ASSIGNEE = "due_alert_overdue_assignee";
|
||||||
|
|
||||||
|
/** 工作报告团队催办:主管催办下属提交指定周期工作报告 */
|
||||||
|
public static final String WORK_REPORT_TEAM_REMIND = "work_report_team_remind";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusModelMapper;
|
|||||||
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusTransitionMapper;
|
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusTransitionMapper;
|
||||||
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
|
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
|
||||||
import com.njcn.rdms.module.project.service.status.StatusActionTextResolver;
|
import com.njcn.rdms.module.project.service.status.StatusActionTextResolver;
|
||||||
|
import com.njcn.rdms.module.project.service.team.TeamDashboardAccessService;
|
||||||
import com.njcn.rdms.module.system.api.user.AdminUserApi;
|
import com.njcn.rdms.module.system.api.user.AdminUserApi;
|
||||||
import com.njcn.rdms.module.system.api.user.dto.AdminUserRespDTO;
|
import com.njcn.rdms.module.system.api.user.dto.AdminUserRespDTO;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
@@ -46,6 +47,7 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -55,6 +57,11 @@ import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil
|
|||||||
@Service
|
@Service
|
||||||
public class OvertimeApplicationServiceImpl implements OvertimeApplicationService {
|
public class OvertimeApplicationServiceImpl implements OvertimeApplicationService {
|
||||||
|
|
||||||
|
private static final List<String> TEAM_VISIBLE_STATUS_CODES = List.of(
|
||||||
|
OvertimeApplicationConstants.STATUS_PENDING,
|
||||||
|
OvertimeApplicationConstants.STATUS_APPROVED,
|
||||||
|
OvertimeApplicationConstants.STATUS_REJECTED);
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private OvertimeApplicationMapper overtimeApplicationMapper;
|
private OvertimeApplicationMapper overtimeApplicationMapper;
|
||||||
@Resource
|
@Resource
|
||||||
@@ -71,6 +78,8 @@ public class OvertimeApplicationServiceImpl implements OvertimeApplicationServic
|
|||||||
private StatusActionTextResolver statusActionTextResolver;
|
private StatusActionTextResolver statusActionTextResolver;
|
||||||
@Resource
|
@Resource
|
||||||
private AdminUserApi adminUserApi;
|
private AdminUserApi adminUserApi;
|
||||||
|
@Resource
|
||||||
|
private TeamDashboardAccessService teamDashboardAccessService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@@ -185,7 +194,13 @@ public class OvertimeApplicationServiceImpl implements OvertimeApplicationServic
|
|||||||
@Override
|
@Override
|
||||||
public PageResult<OvertimeApplicationRespVO> getMyPage(OvertimeApplicationPageReqVO reqVO) {
|
public PageResult<OvertimeApplicationRespVO> getMyPage(OvertimeApplicationPageReqVO reqVO) {
|
||||||
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
PageResult<OvertimeApplicationDO> page = overtimeApplicationMapper.selectMyPage(loginUserId, reqVO);
|
PageResult<OvertimeApplicationDO> page;
|
||||||
|
if (reqVO.getApplicantIds() != null) {
|
||||||
|
List<Long> applicantIds = teamDashboardAccessService.resolveRequestedSubordinateUserIds(reqVO.getApplicantIds());
|
||||||
|
page = overtimeApplicationMapper.selectMyPage(applicantIds, reqVO, TEAM_VISIBLE_STATUS_CODES);
|
||||||
|
} else {
|
||||||
|
page = overtimeApplicationMapper.selectMyPage(loginUserId, reqVO);
|
||||||
|
}
|
||||||
return BeanUtils.toBean(page, OvertimeApplicationRespVO.class, this::applyStatusView);
|
return BeanUtils.toBean(page, OvertimeApplicationRespVO.class, this::applyStatusView);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,7 +383,8 @@ public class OvertimeApplicationServiceImpl implements OvertimeApplicationServic
|
|||||||
OvertimeApplicationDO application = validateApplicationExists(id);
|
OvertimeApplicationDO application = validateApplicationExists(id);
|
||||||
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
if (!Objects.equals(application.getApplicantId(), loginUserId)
|
if (!Objects.equals(application.getApplicantId(), loginUserId)
|
||||||
&& !Objects.equals(application.getApproverId(), loginUserId)) {
|
&& !Objects.equals(application.getApproverId(), loginUserId)
|
||||||
|
&& !teamDashboardAccessService.canReadSubordinateUser(application.getApplicantId())) {
|
||||||
throw exception(ErrorCodeConstants.OVERTIME_APPLICATION_READ_FORBIDDEN);
|
throw exception(ErrorCodeConstants.OVERTIME_APPLICATION_READ_FORBIDDEN);
|
||||||
}
|
}
|
||||||
return application;
|
return application;
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.njcn.rdms.module.project.service.overtime.team;
|
||||||
|
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.overtime.team.vo.TeamOvertimeSummaryReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.overtime.team.vo.TeamOvertimeSummaryRespVO;
|
||||||
|
|
||||||
|
public interface TeamOvertimeService {
|
||||||
|
|
||||||
|
TeamOvertimeSummaryRespVO getSummary(TeamOvertimeSummaryReqVO reqVO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package com.njcn.rdms.module.project.service.overtime.team;
|
||||||
|
|
||||||
|
import com.njcn.rdms.framework.common.pojo.PageParam;
|
||||||
|
import com.njcn.rdms.framework.common.pojo.PageResult;
|
||||||
|
import com.njcn.rdms.module.project.constant.OvertimeApplicationConstants;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.overtime.team.vo.TeamOvertimeSummaryReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.overtime.team.vo.TeamOvertimeSummaryRespVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationPageReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationRespVO;
|
||||||
|
import com.njcn.rdms.module.project.service.overtime.OvertimeApplicationService;
|
||||||
|
import com.njcn.rdms.module.project.service.team.TeamDashboardAccessService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.YearMonth;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class TeamOvertimeServiceImpl implements TeamOvertimeService {
|
||||||
|
|
||||||
|
private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM");
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TeamDashboardAccessService teamDashboardAccessService;
|
||||||
|
@Resource
|
||||||
|
private OvertimeApplicationService overtimeApplicationService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TeamOvertimeSummaryRespVO getSummary(TeamOvertimeSummaryReqVO reqVO) {
|
||||||
|
teamDashboardAccessService.validateTeamDashboardPermission();
|
||||||
|
List<Long> subordinateIds = teamDashboardAccessService.getAllSubordinateUserIds();
|
||||||
|
YearMonth month = parseMonth(reqVO == null ? null : reqVO.getMonth());
|
||||||
|
|
||||||
|
TeamOvertimeSummaryRespVO respVO = new TeamOvertimeSummaryRespVO();
|
||||||
|
respVO.setMonth(month.format(MONTH_FORMATTER));
|
||||||
|
if (subordinateIds.isEmpty()) {
|
||||||
|
respVO.setTotalApplicationCount(0);
|
||||||
|
respVO.setPendingCount(0);
|
||||||
|
respVO.setApprovedCount(0);
|
||||||
|
respVO.setRejectedCount(0);
|
||||||
|
return respVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
OvertimeApplicationPageReqVO pageReqVO = new OvertimeApplicationPageReqVO();
|
||||||
|
pageReqVO.setApplicantIds(subordinateIds);
|
||||||
|
pageReqVO.setPageNo(1);
|
||||||
|
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||||
|
pageReqVO.setOvertimeDate(new LocalDate[]{month.atDay(1), month.atEndOfMonth()});
|
||||||
|
PageResult<OvertimeApplicationRespVO> page = overtimeApplicationService.getMyPage(pageReqVO);
|
||||||
|
|
||||||
|
int pendingCount = 0;
|
||||||
|
int approvedCount = 0;
|
||||||
|
int rejectedCount = 0;
|
||||||
|
for (OvertimeApplicationRespVO item : page.getList()) {
|
||||||
|
if (OvertimeApplicationConstants.STATUS_PENDING.equals(item.getStatusCode())) {
|
||||||
|
pendingCount++;
|
||||||
|
} else if (OvertimeApplicationConstants.STATUS_APPROVED.equals(item.getStatusCode())) {
|
||||||
|
approvedCount++;
|
||||||
|
} else if (OvertimeApplicationConstants.STATUS_REJECTED.equals(item.getStatusCode())) {
|
||||||
|
rejectedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
respVO.setTotalApplicationCount(page.getList().size());
|
||||||
|
respVO.setPendingCount(pendingCount);
|
||||||
|
respVO.setApprovedCount(approvedCount);
|
||||||
|
respVO.setRejectedCount(rejectedCount);
|
||||||
|
return respVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private YearMonth parseMonth(String month) {
|
||||||
|
if (!StringUtils.hasText(month)) {
|
||||||
|
return YearMonth.now();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return YearMonth.parse(month, MONTH_FORMATTER);
|
||||||
|
} catch (DateTimeParseException ex) {
|
||||||
|
throw invalidParamException("统计月份格式不正确,应为 yyyy-MM");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.njcn.rdms.module.project.service.team;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public interface TeamDashboardAccessService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验当前用户具备团队视角权限。
|
||||||
|
*/
|
||||||
|
void validateTeamDashboardPermission();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前登录用户全部有效下属(不含本人)。
|
||||||
|
*
|
||||||
|
* @return 下属 ID 列表
|
||||||
|
*/
|
||||||
|
List<Long> getAllSubordinateUserIds();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验并解析团队查询的目标用户 ID。
|
||||||
|
*
|
||||||
|
* @param candidateUserIds 前端传入的目标用户 ID;为空表示全部下属
|
||||||
|
* @return 校验后的目标用户 ID(不含本人)
|
||||||
|
*/
|
||||||
|
List<Long> resolveRequestedSubordinateUserIds(Collection<Long> candidateUserIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断当前登录用户是否可读取指定工作报告/加班申请所属人员的数据。
|
||||||
|
*
|
||||||
|
* @param userId 目标人员 ID
|
||||||
|
* @return 是否可读
|
||||||
|
*/
|
||||||
|
boolean canReadSubordinateUser(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前登录用户下属集合。
|
||||||
|
*
|
||||||
|
* @return 下属集合
|
||||||
|
*/
|
||||||
|
Set<Long> getSubordinateUserIdSet();
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package com.njcn.rdms.module.project.service.team;
|
||||||
|
|
||||||
|
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||||
|
import com.njcn.rdms.framework.security.core.service.SecurityFrameworkService;
|
||||||
|
import com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
|
import com.njcn.rdms.module.project.constant.TeamDashboardConstants;
|
||||||
|
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
|
||||||
|
import com.njcn.rdms.module.system.api.user.AdminUserApi;
|
||||||
|
import com.njcn.rdms.module.system.api.user.UserManagementRelationApi;
|
||||||
|
import com.njcn.rdms.module.system.api.user.dto.AdminUserRespDTO;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class TeamDashboardAccessServiceImpl implements TeamDashboardAccessService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserManagementRelationApi userManagementRelationApi;
|
||||||
|
@Resource
|
||||||
|
private AdminUserApi adminUserApi;
|
||||||
|
@Resource
|
||||||
|
private SecurityFrameworkService securityFrameworkService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateTeamDashboardPermission() {
|
||||||
|
if (!securityFrameworkService.hasPermission(TeamDashboardConstants.PERMISSION)) {
|
||||||
|
throw exception(ErrorCodeConstants.TEAM_DASHBOARD_PERMISSION_REQUIRED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Long> getAllSubordinateUserIds() {
|
||||||
|
return new ArrayList<>(getSubordinateUserIdSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Long> resolveRequestedSubordinateUserIds(Collection<Long> candidateUserIds) {
|
||||||
|
validateTeamDashboardPermission();
|
||||||
|
Set<Long> allSubordinates = getSubordinateUserIdSet();
|
||||||
|
if (allSubordinates.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
if (candidateUserIds == null || candidateUserIds.isEmpty()) {
|
||||||
|
return new ArrayList<>(allSubordinates);
|
||||||
|
}
|
||||||
|
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
|
LinkedHashSet<Long> resolved = new LinkedHashSet<>();
|
||||||
|
for (Long candidateUserId : candidateUserIds) {
|
||||||
|
if (candidateUserId == null || Objects.equals(candidateUserId, loginUserId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!allSubordinates.contains(candidateUserId)) {
|
||||||
|
throw exception(ErrorCodeConstants.TEAM_DASHBOARD_SUBORDINATE_SCOPE_INVALID);
|
||||||
|
}
|
||||||
|
resolved.add(candidateUserId);
|
||||||
|
}
|
||||||
|
return new ArrayList<>(resolved);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canReadSubordinateUser(Long userId) {
|
||||||
|
if (userId == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!securityFrameworkService.hasPermission(TeamDashboardConstants.PERMISSION)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return getSubordinateUserIdSet().contains(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Long> getSubordinateUserIdSet() {
|
||||||
|
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
|
if (loginUserId == null) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
CommonResult<Set<Long>> result = userManagementRelationApi.getAllSubordinateUserIds(loginUserId);
|
||||||
|
Set<Long> rawIds = result == null || result.getCheckedData() == null
|
||||||
|
? Collections.emptySet()
|
||||||
|
: result.getCheckedData();
|
||||||
|
if (rawIds.isEmpty()) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
LinkedHashSet<Long> uniqueIds = new LinkedHashSet<>(rawIds);
|
||||||
|
uniqueIds.remove(loginUserId);
|
||||||
|
if (uniqueIds.isEmpty()) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
CommonResult<List<AdminUserRespDTO>> userResult = adminUserApi.getUserList(uniqueIds);
|
||||||
|
List<AdminUserRespDTO> users = userResult == null || userResult.getCheckedData() == null
|
||||||
|
? Collections.emptyList()
|
||||||
|
: userResult.getCheckedData();
|
||||||
|
LinkedHashSet<Long> availableIds = new LinkedHashSet<>();
|
||||||
|
for (AdminUserRespDTO user : users) {
|
||||||
|
if (user == null || user.getId() == null || !Objects.equals(user.getStatus(), 0)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
availableIds.add(user.getId());
|
||||||
|
}
|
||||||
|
return availableIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,9 +7,23 @@ import com.njcn.rdms.framework.common.util.json.JsonUtils;
|
|||||||
import com.njcn.rdms.framework.security.core.LoginUser;
|
import com.njcn.rdms.framework.security.core.LoginUser;
|
||||||
import com.njcn.rdms.module.project.constant.ProjectObjectConstants;
|
import com.njcn.rdms.module.project.constant.ProjectObjectConstants;
|
||||||
import com.njcn.rdms.module.project.constant.WorkReportConstants;
|
import com.njcn.rdms.module.project.constant.WorkReportConstants;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.PersonalReportPlanItemReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.PersonalReportPlanItemRespVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.PersonalReportReviewItemReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.PersonalReportReviewItemRespVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportDefaultDraftReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportSaveReqVO;
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportSaveReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportDefaultDraftReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportItemReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportItemRespVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportSaveReqVO;
|
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportSaveReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportDefaultDraftReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportSaveReqVO;
|
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportSaveReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportTravelSegmentReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportTravelSegmentRespVO;
|
||||||
import com.njcn.rdms.module.project.dal.dataobject.job.JobRunLogDO;
|
import com.njcn.rdms.module.project.dal.dataobject.job.JobRunLogDO;
|
||||||
import com.njcn.rdms.module.project.dal.dataobject.project.ProjectDO;
|
import com.njcn.rdms.module.project.dal.dataobject.project.ProjectDO;
|
||||||
import com.njcn.rdms.module.project.dal.mysql.job.JobRunLogMapper;
|
import com.njcn.rdms.module.project.dal.mysql.job.JobRunLogMapper;
|
||||||
@@ -20,6 +34,7 @@ import com.njcn.rdms.module.project.dal.mysql.workreport.project.ProjectReportMa
|
|||||||
import com.njcn.rdms.module.project.dal.mysql.workreport.weekly.WeeklyReportMapper;
|
import com.njcn.rdms.module.project.dal.mysql.workreport.weekly.WeeklyReportMapper;
|
||||||
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
|
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
|
||||||
import com.njcn.rdms.module.project.service.workreport.common.WorkReportCommonService;
|
import com.njcn.rdms.module.project.service.workreport.common.WorkReportCommonService;
|
||||||
|
import com.njcn.rdms.module.project.service.workreport.defaultdraft.WorkReportDefaultDraftService;
|
||||||
import com.njcn.rdms.module.system.api.dept.DeptApi;
|
import com.njcn.rdms.module.system.api.dept.DeptApi;
|
||||||
import com.njcn.rdms.module.system.api.dept.dto.DeptRespDTO;
|
import com.njcn.rdms.module.system.api.dept.dto.DeptRespDTO;
|
||||||
import com.njcn.rdms.module.system.api.user.AdminUserApi;
|
import com.njcn.rdms.module.system.api.user.AdminUserApi;
|
||||||
@@ -73,6 +88,8 @@ public class WorkReportAutoGenerateService {
|
|||||||
@Resource
|
@Resource
|
||||||
private WorkReportCommonService workReportCommonService;
|
private WorkReportCommonService workReportCommonService;
|
||||||
@Resource
|
@Resource
|
||||||
|
private WorkReportDefaultDraftService workReportDefaultDraftService;
|
||||||
|
@Resource
|
||||||
private WeeklyReportMapper weeklyReportMapper;
|
private WeeklyReportMapper weeklyReportMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private MonthlyReportMapper monthlyReportMapper;
|
private MonthlyReportMapper monthlyReportMapper;
|
||||||
@@ -179,15 +196,7 @@ public class WorkReportAutoGenerateService {
|
|||||||
result.setSkipCount(result.getSkipCount() + 1);
|
result.setSkipCount(result.getSkipCount() + 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
WeeklyReportSaveReqVO reqVO = new WeeklyReportSaveReqVO();
|
WeeklyReportSaveReqVO reqVO = runAs(buildLoginUser(user), () -> buildWeeklySaveReqVOFromDefaultDraft(period));
|
||||||
reqVO.setPeriodKey(period.getPeriodKey());
|
|
||||||
reqVO.setPeriodLabel(period.getPeriodLabel());
|
|
||||||
reqVO.setPeriodStartDate(period.getPeriodStartDate());
|
|
||||||
reqVO.setPeriodEndDate(period.getPeriodEndDate());
|
|
||||||
reqVO.setIsBusinessTrip(Boolean.FALSE);
|
|
||||||
reqVO.setReviewItems(Collections.emptyList());
|
|
||||||
reqVO.setPlanItems(Collections.emptyList());
|
|
||||||
reqVO.setTravelSegments(Collections.emptyList());
|
|
||||||
runAs(buildLoginUser(user), () -> workReportCommonService.createWeeklyReport(reqVO, user.getId()));
|
runAs(buildLoginUser(user), () -> workReportCommonService.createWeeklyReport(reqVO, user.getId()));
|
||||||
result.setSuccessCount(result.getSuccessCount() + 1);
|
result.setSuccessCount(result.getSuccessCount() + 1);
|
||||||
}, () -> "userId=" + user.getId());
|
}, () -> "userId=" + user.getId());
|
||||||
@@ -200,13 +209,7 @@ public class WorkReportAutoGenerateService {
|
|||||||
result.setSkipCount(result.getSkipCount() + 1);
|
result.setSkipCount(result.getSkipCount() + 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MonthlyReportSaveReqVO reqVO = new MonthlyReportSaveReqVO();
|
MonthlyReportSaveReqVO reqVO = runAs(buildLoginUser(user), () -> buildMonthlySaveReqVOFromDefaultDraft(period));
|
||||||
reqVO.setPeriodKey(period.getPeriodKey());
|
|
||||||
reqVO.setPeriodLabel(period.getPeriodLabel());
|
|
||||||
reqVO.setPeriodStartDate(period.getPeriodStartDate());
|
|
||||||
reqVO.setPeriodEndDate(period.getPeriodEndDate());
|
|
||||||
reqVO.setReviewItems(Collections.emptyList());
|
|
||||||
reqVO.setPlanItems(Collections.emptyList());
|
|
||||||
runAs(buildLoginUser(user), () -> workReportCommonService.createMonthlyReport(reqVO, user.getId()));
|
runAs(buildLoginUser(user), () -> workReportCommonService.createMonthlyReport(reqVO, user.getId()));
|
||||||
result.setSuccessCount(result.getSuccessCount() + 1);
|
result.setSuccessCount(result.getSuccessCount() + 1);
|
||||||
}, () -> "userId=" + user.getId());
|
}, () -> "userId=" + user.getId());
|
||||||
@@ -220,20 +223,156 @@ public class WorkReportAutoGenerateService {
|
|||||||
result.setSkipCount(result.getSkipCount() + 1);
|
result.setSkipCount(result.getSkipCount() + 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ProjectReportSaveReqVO reqVO = new ProjectReportSaveReqVO();
|
ProjectReportSaveReqVO reqVO = runAs(buildLoginUser(candidate.user()),
|
||||||
reqVO.setProjectId(candidate.projectId());
|
() -> buildProjectSaveReqVOFromDefaultDraft(candidate.projectId(), period));
|
||||||
reqVO.setPeriodKey(period.getPeriodKey());
|
|
||||||
reqVO.setPeriodLabel(period.getPeriodLabel());
|
|
||||||
reqVO.setPeriodStartDate(period.getPeriodStartDate());
|
|
||||||
reqVO.setPeriodEndDate(period.getPeriodEndDate());
|
|
||||||
reqVO.setFlag(period.getFlag());
|
|
||||||
reqVO.setCurrentItems(Collections.emptyList());
|
|
||||||
reqVO.setNextItems(Collections.emptyList());
|
|
||||||
runAs(buildLoginUser(candidate.user()), () -> workReportCommonService.createProjectReport(reqVO, candidate.user().getId()));
|
runAs(buildLoginUser(candidate.user()), () -> workReportCommonService.createProjectReport(reqVO, candidate.user().getId()));
|
||||||
result.setSuccessCount(result.getSuccessCount() + 1);
|
result.setSuccessCount(result.getSuccessCount() + 1);
|
||||||
}, () -> "projectId=" + candidate.projectId() + ", userId=" + candidate.user().getId());
|
}, () -> "projectId=" + candidate.projectId() + ", userId=" + candidate.user().getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WeeklyReportSaveReqVO buildWeeklySaveReqVOFromDefaultDraft(AutoGenPeriod period) {
|
||||||
|
WeeklyReportDefaultDraftReqVO draftReqVO = new WeeklyReportDefaultDraftReqVO();
|
||||||
|
draftReqVO.setPeriodKey(period.getPeriodKey());
|
||||||
|
draftReqVO.setPeriodLabel(period.getPeriodLabel());
|
||||||
|
draftReqVO.setPeriodStartDate(period.getPeriodStartDate());
|
||||||
|
draftReqVO.setPeriodEndDate(period.getPeriodEndDate());
|
||||||
|
WeeklyReportRespVO draft = workReportDefaultDraftService.previewWeeklyDefaultDraft(draftReqVO);
|
||||||
|
|
||||||
|
WeeklyReportSaveReqVO reqVO = new WeeklyReportSaveReqVO();
|
||||||
|
reqVO.setPeriodKey(draft.getPeriodKey());
|
||||||
|
reqVO.setPeriodLabel(draft.getPeriodLabel());
|
||||||
|
reqVO.setPeriodStartDate(draft.getPeriodStartDate());
|
||||||
|
reqVO.setPeriodEndDate(draft.getPeriodEndDate());
|
||||||
|
reqVO.setIsBusinessTrip(Boolean.TRUE.equals(draft.getIsBusinessTrip()));
|
||||||
|
reqVO.setReviewItems(toReviewItemReqList(draft.getReviewItems()));
|
||||||
|
reqVO.setPlanItems(toPlanItemReqList(draft.getPlanItems()));
|
||||||
|
reqVO.setTravelSegments(toTravelSegmentReqList(draft.getTravelSegments()));
|
||||||
|
return reqVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MonthlyReportSaveReqVO buildMonthlySaveReqVOFromDefaultDraft(AutoGenPeriod period) {
|
||||||
|
MonthlyReportDefaultDraftReqVO draftReqVO = new MonthlyReportDefaultDraftReqVO();
|
||||||
|
draftReqVO.setPeriodKey(period.getPeriodKey());
|
||||||
|
draftReqVO.setPeriodLabel(period.getPeriodLabel());
|
||||||
|
draftReqVO.setPeriodStartDate(period.getPeriodStartDate());
|
||||||
|
draftReqVO.setPeriodEndDate(period.getPeriodEndDate());
|
||||||
|
MonthlyReportRespVO draft = workReportDefaultDraftService.previewMonthlyDefaultDraft(draftReqVO);
|
||||||
|
|
||||||
|
MonthlyReportSaveReqVO reqVO = new MonthlyReportSaveReqVO();
|
||||||
|
reqVO.setPeriodKey(draft.getPeriodKey());
|
||||||
|
reqVO.setPeriodLabel(draft.getPeriodLabel());
|
||||||
|
reqVO.setPeriodStartDate(draft.getPeriodStartDate());
|
||||||
|
reqVO.setPeriodEndDate(draft.getPeriodEndDate());
|
||||||
|
reqVO.setReviewItems(toReviewItemReqList(draft.getReviewItems()));
|
||||||
|
reqVO.setPlanItems(toPlanItemReqList(draft.getPlanItems()));
|
||||||
|
return reqVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProjectReportSaveReqVO buildProjectSaveReqVOFromDefaultDraft(Long projectId, AutoGenPeriod period) {
|
||||||
|
ProjectReportDefaultDraftReqVO draftReqVO = new ProjectReportDefaultDraftReqVO();
|
||||||
|
draftReqVO.setPeriodKey(period.getPeriodKey());
|
||||||
|
draftReqVO.setPeriodLabel(period.getPeriodLabel());
|
||||||
|
draftReqVO.setPeriodStartDate(period.getPeriodStartDate());
|
||||||
|
draftReqVO.setPeriodEndDate(period.getPeriodEndDate());
|
||||||
|
draftReqVO.setFlag(period.getFlag());
|
||||||
|
ProjectReportRespVO draft = workReportDefaultDraftService.previewProjectDefaultDraft(projectId, draftReqVO);
|
||||||
|
|
||||||
|
ProjectReportSaveReqVO reqVO = new ProjectReportSaveReqVO();
|
||||||
|
reqVO.setProjectId(projectId);
|
||||||
|
reqVO.setPeriodKey(draft.getPeriodKey());
|
||||||
|
reqVO.setPeriodLabel(draft.getPeriodLabel());
|
||||||
|
reqVO.setPeriodStartDate(draft.getPeriodStartDate());
|
||||||
|
reqVO.setPeriodEndDate(draft.getPeriodEndDate());
|
||||||
|
reqVO.setFlag(draft.getFlag());
|
||||||
|
reqVO.setProjectStatusDesc(draft.getProjectStatusDesc());
|
||||||
|
reqVO.setProjectProgressPlan(draft.getProjectProgressPlan());
|
||||||
|
reqVO.setProjectKeyPoints(draft.getProjectKeyPoints());
|
||||||
|
reqVO.setProjectProblems(draft.getProjectProblems());
|
||||||
|
reqVO.setCurrentItems(toProjectItemReqList(draft.getCurrentItems()));
|
||||||
|
reqVO.setNextItems(toProjectItemReqList(draft.getNextItems()));
|
||||||
|
return reqVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<PersonalReportReviewItemReqVO> toReviewItemReqList(List<PersonalReportReviewItemRespVO> source) {
|
||||||
|
if (source == null || source.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
List<PersonalReportReviewItemReqVO> result = new ArrayList<>(source.size());
|
||||||
|
for (PersonalReportReviewItemRespVO item : source) {
|
||||||
|
if (item == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PersonalReportReviewItemReqVO target = new PersonalReportReviewItemReqVO();
|
||||||
|
target.setItemNumber(item.getItemNumber());
|
||||||
|
target.setItemTitle(item.getItemTitle());
|
||||||
|
target.setWorkHours(item.getWorkHours());
|
||||||
|
target.setContentText(item.getContentText());
|
||||||
|
target.setContentJson(item.getContentJson());
|
||||||
|
target.setReflectionText(item.getReflectionText());
|
||||||
|
result.add(target);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<PersonalReportPlanItemReqVO> toPlanItemReqList(List<PersonalReportPlanItemRespVO> source) {
|
||||||
|
if (source == null || source.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
List<PersonalReportPlanItemReqVO> result = new ArrayList<>(source.size());
|
||||||
|
for (PersonalReportPlanItemRespVO item : source) {
|
||||||
|
if (item == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PersonalReportPlanItemReqVO target = new PersonalReportPlanItemReqVO();
|
||||||
|
target.setItemNumber(item.getItemNumber());
|
||||||
|
target.setItemTitle(item.getItemTitle());
|
||||||
|
target.setTargetText(item.getTargetText());
|
||||||
|
target.setTargetJson(item.getTargetJson());
|
||||||
|
target.setSupportNeed(item.getSupportNeed());
|
||||||
|
result.add(target);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ProjectReportItemReqVO> toProjectItemReqList(List<ProjectReportItemRespVO> source) {
|
||||||
|
if (source == null || source.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
List<ProjectReportItemReqVO> result = new ArrayList<>(source.size());
|
||||||
|
for (ProjectReportItemRespVO item : source) {
|
||||||
|
if (item == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ProjectReportItemReqVO target = new ProjectReportItemReqVO();
|
||||||
|
target.setItemTitle(item.getItemTitle());
|
||||||
|
target.setWorkHours(item.getWorkHours());
|
||||||
|
target.setPriorityCode(item.getPriorityCode());
|
||||||
|
target.setProgressRate(item.getProgressRate());
|
||||||
|
result.add(target);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<WeeklyReportTravelSegmentReqVO> toTravelSegmentReqList(List<WeeklyReportTravelSegmentRespVO> source) {
|
||||||
|
if (source == null || source.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
List<WeeklyReportTravelSegmentReqVO> result = new ArrayList<>(source.size());
|
||||||
|
for (WeeklyReportTravelSegmentRespVO item : source) {
|
||||||
|
if (item == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
WeeklyReportTravelSegmentReqVO target = new WeeklyReportTravelSegmentReqVO();
|
||||||
|
target.setSort(item.getSort());
|
||||||
|
target.setStartDate(item.getStartDate());
|
||||||
|
target.setEndDate(item.getEndDate());
|
||||||
|
target.setTravelDays(item.getTravelDays());
|
||||||
|
target.setLocation(item.getLocation());
|
||||||
|
result.add(target);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private void executeWithLock(String reportType, String periodKey, String subjectKey, AutoGenResult result,
|
private void executeWithLock(String reportType, String periodKey, String subjectKey, AutoGenResult result,
|
||||||
Runnable action, Supplier<String> failContextSupplier) {
|
Runnable action, Supplier<String> failContextSupplier) {
|
||||||
RLock lock = redissonClient.getLock(String.format(LOCK_KEY_TEMPLATE, reportType, periodKey, subjectKey));
|
RLock lock = redissonClient.getLock(String.format(LOCK_KEY_TEMPLATE, reportType, periodKey, subjectKey));
|
||||||
@@ -346,29 +485,31 @@ public class WorkReportAutoGenerateService {
|
|||||||
private AutoGenPeriod buildWeeklyPeriod(LocalDate today) {
|
private AutoGenPeriod buildWeeklyPeriod(LocalDate today) {
|
||||||
LocalDate periodStartDate = today.minusDays(today.getDayOfWeek().getValue() - 1L);
|
LocalDate periodStartDate = today.minusDays(today.getDayOfWeek().getValue() - 1L);
|
||||||
LocalDate periodEndDate = periodStartDate.plusDays(6);
|
LocalDate periodEndDate = periodStartDate.plusDays(6);
|
||||||
int week = periodStartDate.get(java.time.temporal.IsoFields.WEEK_OF_WEEK_BASED_YEAR);
|
|
||||||
int year = periodStartDate.get(java.time.temporal.IsoFields.WEEK_BASED_YEAR);
|
|
||||||
return new AutoGenPeriod()
|
return new AutoGenPeriod()
|
||||||
.setPeriodKey(String.format("%d-W%02d", year, week))
|
.setPeriodKey(String.format("weekly-%s-%s", periodStartDate, periodEndDate))
|
||||||
.setPeriodLabel(String.format("%d 年第 %02d 周", year, week))
|
.setPeriodLabel(String.format("%s 至 %s", periodStartDate, periodEndDate))
|
||||||
.setPeriodStartDate(periodStartDate)
|
.setPeriodStartDate(periodStartDate)
|
||||||
.setPeriodEndDate(periodEndDate);
|
.setPeriodEndDate(periodEndDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private AutoGenPeriod buildMonthlyPeriod(LocalDate today) {
|
private AutoGenPeriod buildMonthlyPeriod(LocalDate today) {
|
||||||
|
LocalDate periodStartDate = today.withDayOfMonth(1);
|
||||||
|
LocalDate periodEndDate = today.withDayOfMonth(today.lengthOfMonth());
|
||||||
return new AutoGenPeriod()
|
return new AutoGenPeriod()
|
||||||
.setPeriodKey(String.format("%d-%02d", today.getYear(), today.getMonthValue()))
|
.setPeriodKey(String.format("monthly-%s-%s", periodStartDate, periodEndDate))
|
||||||
.setPeriodLabel(String.format("%d 年 %02d 月", today.getYear(), today.getMonthValue()))
|
.setPeriodLabel(String.format("%d-%02d", today.getYear(), today.getMonthValue()))
|
||||||
.setPeriodStartDate(today.withDayOfMonth(1))
|
.setPeriodStartDate(periodStartDate)
|
||||||
.setPeriodEndDate(today.withDayOfMonth(today.lengthOfMonth()));
|
.setPeriodEndDate(periodEndDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private AutoGenPeriod buildProjectFirstHalfPeriod(LocalDate today) {
|
private AutoGenPeriod buildProjectFirstHalfPeriod(LocalDate today) {
|
||||||
|
LocalDate periodStartDate = today.withDayOfMonth(1);
|
||||||
|
LocalDate periodEndDate = today.withDayOfMonth(15);
|
||||||
return new AutoGenPeriod()
|
return new AutoGenPeriod()
|
||||||
.setPeriodKey(String.format("%d-%02d-01", today.getYear(), today.getMonthValue()))
|
.setPeriodKey(String.format("project-%s-%s-1", periodStartDate, periodEndDate))
|
||||||
.setPeriodLabel(String.format("%d 年 %02d 月 上半月", today.getYear(), today.getMonthValue()))
|
.setPeriodLabel(String.format("%d-%02d 上半月", today.getYear(), today.getMonthValue()))
|
||||||
.setPeriodStartDate(today.withDayOfMonth(1))
|
.setPeriodStartDate(periodStartDate)
|
||||||
.setPeriodEndDate(today.withDayOfMonth(15))
|
.setPeriodEndDate(periodEndDate)
|
||||||
.setFlag(1);
|
.setFlag(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import com.njcn.rdms.module.project.dal.mysql.workreport.weekly.WeeklyReportMapp
|
|||||||
import com.njcn.rdms.module.project.dal.mysql.workreport.weekly.WeeklyReportTravelSegmentMapper;
|
import com.njcn.rdms.module.project.dal.mysql.workreport.weekly.WeeklyReportTravelSegmentMapper;
|
||||||
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
|
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
|
||||||
import com.njcn.rdms.module.project.service.status.StatusActionTextResolver;
|
import com.njcn.rdms.module.project.service.status.StatusActionTextResolver;
|
||||||
|
import com.njcn.rdms.module.project.service.team.TeamDashboardAccessService;
|
||||||
import com.njcn.rdms.module.system.api.dept.DeptApi;
|
import com.njcn.rdms.module.system.api.dept.DeptApi;
|
||||||
import com.njcn.rdms.module.system.api.dept.PostApi;
|
import com.njcn.rdms.module.system.api.dept.PostApi;
|
||||||
import com.njcn.rdms.module.system.api.dept.dto.DeptRespDTO;
|
import com.njcn.rdms.module.system.api.dept.dto.DeptRespDTO;
|
||||||
@@ -77,6 +78,10 @@ public class WorkReportCommonService {
|
|||||||
private static final List<String> ALLOW_DELETE_STATUSES = List.of(
|
private static final List<String> ALLOW_DELETE_STATUSES = List.of(
|
||||||
WorkReportConstants.STATUS_DRAFT,
|
WorkReportConstants.STATUS_DRAFT,
|
||||||
WorkReportConstants.STATUS_REJECTED);
|
WorkReportConstants.STATUS_REJECTED);
|
||||||
|
private static final List<String> TEAM_VISIBLE_STATUS_CODES = List.of(
|
||||||
|
WorkReportConstants.STATUS_PENDING_APPROVAL,
|
||||||
|
WorkReportConstants.STATUS_APPROVED,
|
||||||
|
WorkReportConstants.STATUS_REJECTED);
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private WeeklyReportMapper weeklyReportMapper;
|
private WeeklyReportMapper weeklyReportMapper;
|
||||||
@@ -124,6 +129,8 @@ public class WorkReportCommonService {
|
|||||||
private ProjectMapper projectMapper;
|
private ProjectMapper projectMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private UserObjectRoleMapper userObjectRoleMapper;
|
private UserObjectRoleMapper userObjectRoleMapper;
|
||||||
|
@Resource
|
||||||
|
private TeamDashboardAccessService teamDashboardAccessService;
|
||||||
|
|
||||||
public List<WorkReportStatusDictRespVO> getStatusDict() {
|
public List<WorkReportStatusDictRespVO> getStatusDict() {
|
||||||
return objectStatusModelMapper.selectListByObjectTypeEnabled(WorkReportConstants.STATUS_OBJECT_TYPE).stream()
|
return objectStatusModelMapper.selectListByObjectTypeEnabled(WorkReportConstants.STATUS_OBJECT_TYPE).stream()
|
||||||
@@ -233,8 +240,13 @@ public class WorkReportCommonService {
|
|||||||
|
|
||||||
public PageResult<WeeklyReportRespVO> getWeeklyReportPage(WeeklyReportPageReqVO reqVO) {
|
public PageResult<WeeklyReportRespVO> getWeeklyReportPage(WeeklyReportPageReqVO reqVO) {
|
||||||
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
PageResult<WeeklyReportDO> pageResult = weeklyReportMapper.selectReporterPage(loginUserId, reqVO,
|
PageResult<WeeklyReportDO> pageResult;
|
||||||
getEnabledStatusCodes());
|
if (reqVO.getReporterIds() != null) {
|
||||||
|
List<Long> reporterIds = teamDashboardAccessService.resolveRequestedSubordinateUserIds(reqVO.getReporterIds());
|
||||||
|
pageResult = weeklyReportMapper.selectReporterPage(reporterIds, reqVO, TEAM_VISIBLE_STATUS_CODES);
|
||||||
|
} else {
|
||||||
|
pageResult = weeklyReportMapper.selectReporterPage(loginUserId, reqVO, getEnabledStatusCodes());
|
||||||
|
}
|
||||||
return new PageResult<>(pageResult.getList().stream()
|
return new PageResult<>(pageResult.getList().stream()
|
||||||
.map(report -> toWeeklyRespVO(report, false))
|
.map(report -> toWeeklyRespVO(report, false))
|
||||||
.collect(Collectors.toList()), pageResult.getTotal());
|
.collect(Collectors.toList()), pageResult.getTotal());
|
||||||
@@ -392,8 +404,13 @@ public class WorkReportCommonService {
|
|||||||
|
|
||||||
public PageResult<MonthlyReportRespVO> getMonthlyReportPage(MonthlyReportPageReqVO reqVO) {
|
public PageResult<MonthlyReportRespVO> getMonthlyReportPage(MonthlyReportPageReqVO reqVO) {
|
||||||
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
PageResult<MonthlyReportDO> pageResult = monthlyReportMapper.selectReporterPage(loginUserId, reqVO,
|
PageResult<MonthlyReportDO> pageResult;
|
||||||
getEnabledStatusCodes());
|
if (reqVO.getReporterIds() != null) {
|
||||||
|
List<Long> reporterIds = teamDashboardAccessService.resolveRequestedSubordinateUserIds(reqVO.getReporterIds());
|
||||||
|
pageResult = monthlyReportMapper.selectReporterPage(reporterIds, reqVO, TEAM_VISIBLE_STATUS_CODES);
|
||||||
|
} else {
|
||||||
|
pageResult = monthlyReportMapper.selectReporterPage(loginUserId, reqVO, getEnabledStatusCodes());
|
||||||
|
}
|
||||||
return new PageResult<>(pageResult.getList().stream()
|
return new PageResult<>(pageResult.getList().stream()
|
||||||
.map(report -> toMonthlyRespVO(report, false))
|
.map(report -> toMonthlyRespVO(report, false))
|
||||||
.collect(Collectors.toList()), pageResult.getTotal());
|
.collect(Collectors.toList()), pageResult.getTotal());
|
||||||
@@ -570,8 +587,13 @@ public class WorkReportCommonService {
|
|||||||
|
|
||||||
public PageResult<ProjectReportRespVO> getProjectReportPage(ProjectReportPageReqVO reqVO) {
|
public PageResult<ProjectReportRespVO> getProjectReportPage(ProjectReportPageReqVO reqVO) {
|
||||||
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
PageResult<ProjectReportDO> pageResult = projectReportMapper.selectReporterPage(loginUserId, reqVO,
|
PageResult<ProjectReportDO> pageResult;
|
||||||
getEnabledStatusCodes());
|
if (reqVO.getProjectOwnerIds() != null) {
|
||||||
|
List<Long> projectOwnerIds = teamDashboardAccessService.resolveRequestedSubordinateUserIds(reqVO.getProjectOwnerIds());
|
||||||
|
pageResult = projectReportMapper.selectReporterPage(projectOwnerIds, reqVO, TEAM_VISIBLE_STATUS_CODES);
|
||||||
|
} else {
|
||||||
|
pageResult = projectReportMapper.selectReporterPage(loginUserId, reqVO, getEnabledStatusCodes());
|
||||||
|
}
|
||||||
return new PageResult<>(pageResult.getList().stream()
|
return new PageResult<>(pageResult.getList().stream()
|
||||||
.map(report -> toProjectRespVO(report, false))
|
.map(report -> toProjectRespVO(report, false))
|
||||||
.collect(Collectors.toList()), pageResult.getTotal());
|
.collect(Collectors.toList()), pageResult.getTotal());
|
||||||
@@ -764,7 +786,9 @@ public class WorkReportCommonService {
|
|||||||
|
|
||||||
private void validateReadable(Long reporterId, Long supervisorUserId) {
|
private void validateReadable(Long reporterId, Long supervisorUserId) {
|
||||||
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
if (!Objects.equals(loginUserId, reporterId) && !Objects.equals(loginUserId, supervisorUserId)) {
|
if (!Objects.equals(loginUserId, reporterId)
|
||||||
|
&& !Objects.equals(loginUserId, supervisorUserId)
|
||||||
|
&& !teamDashboardAccessService.canReadSubordinateUser(reporterId)) {
|
||||||
throw exception(ErrorCodeConstants.WORK_REPORT_READ_FORBIDDEN);
|
throw exception(ErrorCodeConstants.WORK_REPORT_READ_FORBIDDEN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.njcn.rdms.module.project.service.workreport.team;
|
||||||
|
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.team.vo.TeamReportRemindReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.team.vo.TeamReportRemindRespVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.team.vo.TeamReportSummaryReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.team.vo.TeamReportSummaryRespVO;
|
||||||
|
|
||||||
|
public interface TeamWorkReportService {
|
||||||
|
|
||||||
|
TeamReportSummaryRespVO getSummary(TeamReportSummaryReqVO reqVO);
|
||||||
|
|
||||||
|
TeamReportRemindRespVO remind(TeamReportRemindReqVO reqVO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,283 @@
|
|||||||
|
package com.njcn.rdms.module.project.service.workreport.team;
|
||||||
|
|
||||||
|
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||||
|
import com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
|
import com.njcn.rdms.module.project.constant.WorkReportConstants;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.team.vo.TeamReportRemindReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.team.vo.TeamReportRemindRespVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.team.vo.TeamReportSummaryReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.team.vo.TeamReportSummaryRespVO;
|
||||||
|
import com.njcn.rdms.module.project.dal.dataobject.project.ProjectDO;
|
||||||
|
import com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportDO;
|
||||||
|
import com.njcn.rdms.module.project.dal.dataobject.workreport.project.ProjectReportDO;
|
||||||
|
import com.njcn.rdms.module.project.dal.dataobject.workreport.weekly.WeeklyReportDO;
|
||||||
|
import com.njcn.rdms.module.project.dal.mysql.project.ProjectMapper;
|
||||||
|
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusModelMapper;
|
||||||
|
import com.njcn.rdms.module.project.dal.mysql.workreport.monthly.MonthlyReportMapper;
|
||||||
|
import com.njcn.rdms.module.project.dal.mysql.workreport.project.ProjectReportMapper;
|
||||||
|
import com.njcn.rdms.module.project.dal.mysql.workreport.weekly.WeeklyReportMapper;
|
||||||
|
import com.njcn.rdms.module.project.framework.notify.NotifySendEvent;
|
||||||
|
import com.njcn.rdms.module.project.framework.notify.NotifyTemplateCodeConstants;
|
||||||
|
import com.njcn.rdms.module.project.service.team.TeamDashboardAccessService;
|
||||||
|
import com.njcn.rdms.module.system.api.user.AdminUserApi;
|
||||||
|
import com.njcn.rdms.module.system.api.user.dto.AdminUserRespDTO;
|
||||||
|
import com.njcn.rdms.module.system.enums.notify.NotifyMessageLevelConstants;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class TeamWorkReportServiceImpl implements TeamWorkReportService {
|
||||||
|
|
||||||
|
private static final List<String> SUBMITTED_STATUS_CODES = List.of(
|
||||||
|
WorkReportConstants.STATUS_PENDING_APPROVAL,
|
||||||
|
WorkReportConstants.STATUS_APPROVED,
|
||||||
|
WorkReportConstants.STATUS_REJECTED);
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TeamDashboardAccessService teamDashboardAccessService;
|
||||||
|
@Resource
|
||||||
|
private AdminUserApi adminUserApi;
|
||||||
|
@Resource
|
||||||
|
private WeeklyReportMapper weeklyReportMapper;
|
||||||
|
@Resource
|
||||||
|
private MonthlyReportMapper monthlyReportMapper;
|
||||||
|
@Resource
|
||||||
|
private ProjectReportMapper projectReportMapper;
|
||||||
|
@Resource
|
||||||
|
private ProjectMapper projectMapper;
|
||||||
|
@Resource
|
||||||
|
private ObjectStatusModelMapper objectStatusModelMapper;
|
||||||
|
@Resource
|
||||||
|
private ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TeamReportSummaryRespVO getSummary(TeamReportSummaryReqVO reqVO) {
|
||||||
|
teamDashboardAccessService.validateTeamDashboardPermission();
|
||||||
|
ReportContext context = buildReportContext(normalizeReportType(reqVO.getReportType()), reqVO.getPeriodKey());
|
||||||
|
TeamReportSummaryRespVO respVO = new TeamReportSummaryRespVO();
|
||||||
|
respVO.setTotalShouldSubmit(context.expectedUserIds().size());
|
||||||
|
respVO.setSubmittedCount(context.submittedUserIds().size());
|
||||||
|
respVO.setPendingApprovalCount(context.pendingApprovalUserIds().size());
|
||||||
|
List<TeamReportSummaryRespVO.PendingUser> unsubmittedUsers = buildPendingUsers(context.expectedUserIds(), context.submittedUserIds());
|
||||||
|
respVO.setUnsubmittedUsers(unsubmittedUsers);
|
||||||
|
respVO.setUnsubmittedCount(unsubmittedUsers.size());
|
||||||
|
return respVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public TeamReportRemindRespVO remind(TeamReportRemindReqVO reqVO) {
|
||||||
|
teamDashboardAccessService.validateTeamDashboardPermission();
|
||||||
|
String reportType = normalizeReportType(reqVO.getReportType());
|
||||||
|
ReportContext context = buildReportContext(reportType, reqVO.getPeriodKey());
|
||||||
|
List<Long> remindUserIds = resolveRemindUserIds(reqVO.getUserIds(), context);
|
||||||
|
|
||||||
|
if (!remindUserIds.isEmpty()) {
|
||||||
|
Map<String, Object> params = new HashMap<>();
|
||||||
|
params.put("reportTypeName", reportTypeDisplayName(reportType));
|
||||||
|
params.put("periodKey", reqVO.getPeriodKey());
|
||||||
|
params.put("managerName", defaultText(SecurityFrameworkUtils.getLoginUserNickname()));
|
||||||
|
applicationEventPublisher.publishEvent(NotifySendEvent.of(remindUserIds,
|
||||||
|
NotifyTemplateCodeConstants.WORK_REPORT_TEAM_REMIND, params, NotifyMessageLevelConstants.REMIND));
|
||||||
|
}
|
||||||
|
|
||||||
|
TeamReportRemindRespVO respVO = new TeamReportRemindRespVO();
|
||||||
|
respVO.setRemindedCount(remindUserIds.size());
|
||||||
|
return respVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReportContext buildReportContext(String reportType, String periodKey) {
|
||||||
|
if (!StringUtils.hasText(periodKey)) {
|
||||||
|
throw invalidParamException("周期主键不能为空");
|
||||||
|
}
|
||||||
|
if (WorkReportConstants.REPORT_TYPE_PROJECT.equals(reportType)) {
|
||||||
|
return buildProjectContext(periodKey);
|
||||||
|
}
|
||||||
|
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 buildWeeklyContext(periodKey, subordinateIds);
|
||||||
|
}
|
||||||
|
return buildMonthlyContext(periodKey, subordinateIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReportContext buildWeeklyContext(String periodKey, List<Long> subordinateIds) {
|
||||||
|
List<WeeklyReportDO> reports = weeklyReportMapper.selectListByReporterIdsAndPeriodKey(
|
||||||
|
subordinateIds, periodKey, 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 buildMonthlyContext(String periodKey, List<Long> subordinateIds) {
|
||||||
|
List<MonthlyReportDO> reports = monthlyReportMapper.selectListByReporterIdsAndPeriodKey(
|
||||||
|
subordinateIds, periodKey, 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 buildProjectContext(String periodKey) {
|
||||||
|
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.selectListByProjectOwnerIdsAndPeriodKey(
|
||||||
|
expectedUserIds, periodKey, 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 List<ProjectDO> loadActiveProjectsForSubordinates(Collection<Long> subordinateIds) {
|
||||||
|
if (subordinateIds == null || subordinateIds.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
List<String> terminalStatusCodes = objectStatusModelMapper
|
||||||
|
.selectTerminalStatusCodesByObjectTypeEnabled(com.njcn.rdms.module.project.constant.ProjectObjectConstants.OBJECT_TYPE);
|
||||||
|
List<ProjectDO> allProjects = projectMapper.selectListByManagerUserIdsAndStatusCodesNotIn(
|
||||||
|
subordinateIds, terminalStatusCodes);
|
||||||
|
if (allProjects.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return allProjects.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.filter(project -> project.getManagerUserId() != null)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Long> resolveRemindUserIds(List<Long> requestedUserIds, ReportContext context) {
|
||||||
|
LinkedHashSet<Long> unsubmittedUserIds = new LinkedHashSet<>(context.expectedUserIds());
|
||||||
|
unsubmittedUserIds.removeAll(context.submittedUserIds());
|
||||||
|
if (requestedUserIds == null) {
|
||||||
|
return new ArrayList<>(unsubmittedUserIds);
|
||||||
|
}
|
||||||
|
List<Long> validatedIds = teamDashboardAccessService.resolveRequestedSubordinateUserIds(requestedUserIds);
|
||||||
|
return validatedIds.stream()
|
||||||
|
.filter(unsubmittedUserIds::contains)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<TeamReportSummaryRespVO.PendingUser> buildPendingUsers(List<Long> expectedUserIds,
|
||||||
|
Set<Long> submittedUserIds) {
|
||||||
|
LinkedHashSet<Long> pendingIds = new LinkedHashSet<>(expectedUserIds);
|
||||||
|
pendingIds.removeAll(submittedUserIds);
|
||||||
|
if (pendingIds.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
CommonResult<List<AdminUserRespDTO>> result = adminUserApi.getUserList(pendingIds);
|
||||||
|
List<AdminUserRespDTO> users = result == null ? null : result.getCheckedData();
|
||||||
|
if (users == null || users.isEmpty()) {
|
||||||
|
users = Collections.emptyList();
|
||||||
|
}
|
||||||
|
Map<Long, AdminUserRespDTO> userMap = users.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.filter(user -> user.getId() != null)
|
||||||
|
.collect(Collectors.toMap(AdminUserRespDTO::getId, user -> user, (left, right) -> left, LinkedHashMap::new));
|
||||||
|
List<TeamReportSummaryRespVO.PendingUser> respList = new ArrayList<>();
|
||||||
|
for (Long pendingId : pendingIds) {
|
||||||
|
AdminUserRespDTO user = userMap.get(pendingId);
|
||||||
|
TeamReportSummaryRespVO.PendingUser item = new TeamReportSummaryRespVO.PendingUser();
|
||||||
|
item.setUserId(pendingId);
|
||||||
|
item.setUserNickname(user == null ? "" : defaultText(user.getNickname()));
|
||||||
|
respList.add(item);
|
||||||
|
}
|
||||||
|
return respList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeReportType(String reportType) {
|
||||||
|
if (WorkReportConstants.REPORT_TYPE_WEEKLY.equals(reportType)
|
||||||
|
|| WorkReportConstants.REPORT_TYPE_MONTHLY.equals(reportType)
|
||||||
|
|| WorkReportConstants.REPORT_TYPE_PROJECT.equals(reportType)) {
|
||||||
|
return reportType;
|
||||||
|
}
|
||||||
|
throw invalidParamException("报告类型不合法");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String reportTypeDisplayName(String reportType) {
|
||||||
|
return switch (reportType) {
|
||||||
|
case WorkReportConstants.REPORT_TYPE_WEEKLY -> "周报";
|
||||||
|
case WorkReportConstants.REPORT_TYPE_MONTHLY -> "月报";
|
||||||
|
case WorkReportConstants.REPORT_TYPE_PROJECT -> "项目半月报";
|
||||||
|
default -> reportType;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private String defaultText(String text) {
|
||||||
|
return StringUtils.hasText(text) ? text.trim() : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private record ReportContext(List<Long> expectedUserIds, Set<Long> submittedUserIds, Set<Long> pendingApprovalUserIds) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -119,6 +119,6 @@ rdms:
|
|||||||
enabled: true
|
enabled: true
|
||||||
cron: "0 0 12 1-31 * ?"
|
cron: "0 0 12 1-31 * ?"
|
||||||
scope:
|
scope:
|
||||||
dept-ids: [101]
|
dept-ids: [100]
|
||||||
|
|
||||||
debug: false
|
debug: false
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@FeignClient(name = ApiConstants.NAME)
|
@FeignClient(name = ApiConstants.NAME)
|
||||||
@Tag(name = "RPC 服务 - 用户管理链路")
|
@Tag(name = "RPC 服务 - 用户管理链路")
|
||||||
@@ -44,6 +45,11 @@ public interface UserManagementRelationApi {
|
|||||||
@Parameter(name = "ids", description = "关系编号数组", example = "1,2", required = true)
|
@Parameter(name = "ids", description = "关系编号数组", example = "1,2", required = true)
|
||||||
CommonResult<List<UserManagementRelationRespDTO>> getRelationList(@RequestParam("ids") Collection<Long> ids);
|
CommonResult<List<UserManagementRelationRespDTO>> getRelationList(@RequestParam("ids") Collection<Long> ids);
|
||||||
|
|
||||||
|
@GetMapping(PREFIX + "/all-subordinate-user-ids")
|
||||||
|
@Operation(summary = "获取某管理者全部下属用户 ID")
|
||||||
|
@Parameter(name = "managerUserId", description = "管理者用户 ID", example = "1", required = true)
|
||||||
|
CommonResult<Set<Long>> getAllSubordinateUserIds(@RequestParam("managerUserId") Long managerUserId);
|
||||||
|
|
||||||
default Map<Long, UserManagementRelationRespDTO> getRelationMap(Collection<Long> ids) {
|
default Map<Long, UserManagementRelationRespDTO> getRelationMap(Collection<Long> ids) {
|
||||||
if (CollUtil.isEmpty(ids)) {
|
if (CollUtil.isEmpty(ids)) {
|
||||||
return MapUtil.empty();
|
return MapUtil.empty();
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
|
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
@@ -56,4 +57,9 @@ public class UserManagementRelationApiImpl implements UserManagementRelationApi
|
|||||||
return success(BeanUtils.toBean(list, UserManagementRelationRespDTO.class));
|
return success(BeanUtils.toBean(list, UserManagementRelationRespDTO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonResult<Set<Long>> getAllSubordinateUserIds(Long managerUserId) {
|
||||||
|
return success(userManagementRelationService.getAllSubordinateUserIds(managerUserId));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.njcn.rdms.framework.common.pojo.CommonResult;
|
|||||||
import com.njcn.rdms.framework.common.util.object.BeanUtils;
|
import com.njcn.rdms.framework.common.util.object.BeanUtils;
|
||||||
import com.njcn.rdms.framework.excel.core.util.ExcelUtils;
|
import com.njcn.rdms.framework.excel.core.util.ExcelUtils;
|
||||||
import com.njcn.rdms.module.system.controller.admin.user.vo.user.UserSimpleRespVO;
|
import com.njcn.rdms.module.system.controller.admin.user.vo.user.UserSimpleRespVO;
|
||||||
|
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.MySubordinateTreeRespVO;
|
||||||
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationQueryReqVO;
|
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationQueryReqVO;
|
||||||
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationRespVO;
|
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationRespVO;
|
||||||
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationSaveReqVO;
|
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationSaveReqVO;
|
||||||
@@ -211,6 +212,13 @@ public class UserManagementRelationController {
|
|||||||
return success(userManagementRelationService.getRelationTree(reqVO));
|
return success(userManagementRelationService.getRelationTree(reqVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/my-subordinate-tree")
|
||||||
|
@Operation(summary = "获取当前用户下属树")
|
||||||
|
@PreAuthorize("@ss.hasPermission('project:work-report:team-dashboard')")
|
||||||
|
public CommonResult<MySubordinateTreeRespVO> getMySubordinateTree() {
|
||||||
|
return success(userManagementRelationService.getMySubordinateTree(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出用户管理链路 Excel
|
* 导出用户管理链路 Excel
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 我的下属树 Response VO")
|
||||||
|
@Data
|
||||||
|
public class MySubordinateTreeRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2042074259501088770")
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "戴坤")
|
||||||
|
private String userNickname;
|
||||||
|
|
||||||
|
@Schema(description = "是否为根节点", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||||
|
private Boolean isRoot;
|
||||||
|
|
||||||
|
@Schema(description = "下属总人数(递归)", requiredMode = Schema.RequiredMode.REQUIRED, example = "18")
|
||||||
|
private Integer subordinateCount;
|
||||||
|
|
||||||
|
@Schema(description = "子节点")
|
||||||
|
private List<MySubordinateTreeRespVO> children;
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package com.njcn.rdms.module.system.service.user;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import com.njcn.rdms.framework.common.util.collection.CollectionUtils;
|
import com.njcn.rdms.framework.common.util.collection.CollectionUtils;
|
||||||
|
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.MySubordinateTreeRespVO;
|
||||||
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationQueryReqVO;
|
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationQueryReqVO;
|
||||||
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationSaveReqVO;
|
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationSaveReqVO;
|
||||||
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationTreeRespVO;
|
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationTreeRespVO;
|
||||||
@@ -12,6 +13,7 @@ import java.util.Collection;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户管理链路 Service 接口
|
* 用户管理链路 Service 接口
|
||||||
@@ -108,6 +110,14 @@ public interface UserManagementRelationService {
|
|||||||
*/
|
*/
|
||||||
List<UserManagementRelationTreeRespVO> getRelationTree(UserManagementRelationQueryReqVO reqVO);
|
List<UserManagementRelationTreeRespVO> getRelationTree(UserManagementRelationQueryReqVO reqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前用户为根节点的下属树。
|
||||||
|
*
|
||||||
|
* @param rootUserId 根用户 ID;为空时默认当前登录用户
|
||||||
|
* @return 下属树
|
||||||
|
*/
|
||||||
|
MySubordinateTreeRespVO getMySubordinateTree(Long rootUserId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取还未绑定直属上级的候选下级用户列表
|
* 获取还未绑定直属上级的候选下级用户列表
|
||||||
*
|
*
|
||||||
@@ -115,6 +125,14 @@ public interface UserManagementRelationService {
|
|||||||
*/
|
*/
|
||||||
List<AdminUserDO> getCandidateSubordinateUsers();
|
List<AdminUserDO> getCandidateSubordinateUsers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取管理者全部直接/间接下属 ID(不含本人)。
|
||||||
|
*
|
||||||
|
* @param managerUserId 管理者用户 ID
|
||||||
|
* @return 全部下属用户 ID
|
||||||
|
*/
|
||||||
|
Set<Long> getAllSubordinateUserIds(Long managerUserId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得用户管理链路 Map
|
* 获得用户管理链路 Map
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
|
|||||||
import com.njcn.rdms.framework.common.exception.ServiceException;
|
import com.njcn.rdms.framework.common.exception.ServiceException;
|
||||||
import com.njcn.rdms.framework.common.util.object.BeanUtils;
|
import com.njcn.rdms.framework.common.util.object.BeanUtils;
|
||||||
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
|
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.MySubordinateTreeRespVO;
|
||||||
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationQueryReqVO;
|
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationQueryReqVO;
|
||||||
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationSaveReqVO;
|
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationSaveReqVO;
|
||||||
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationTreeRespVO;
|
import com.njcn.rdms.module.system.controller.admin.user.vo.userManagementRelation.UserManagementRelationTreeRespVO;
|
||||||
@@ -349,6 +351,44 @@ public class UserManagementRelationServiceImpl implements UserManagementRelation
|
|||||||
return buildFullTree(context);
|
return buildFullTree(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MySubordinateTreeRespVO getMySubordinateTree(Long rootUserId) {
|
||||||
|
Long resolvedRootUserId = rootUserId != null ? rootUserId : SecurityFrameworkUtils.getLoginUserId();
|
||||||
|
if (resolvedRootUserId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TreeBuildContext context = buildTreeContext(new UserManagementRelationQueryReqVO());
|
||||||
|
if (context == null) {
|
||||||
|
AdminUserDO self = adminUserService.getUser(resolvedRootUserId);
|
||||||
|
if (!adminUserService.isUserAvailable(self)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
MySubordinateTreeRespVO root = new MySubordinateTreeRespVO();
|
||||||
|
root.setUserId(self.getId());
|
||||||
|
root.setUserNickname(self.getNickname());
|
||||||
|
root.setIsRoot(Boolean.TRUE);
|
||||||
|
root.setSubordinateCount(0);
|
||||||
|
root.setChildren(Collections.emptyList());
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
return buildMySubordinateTreeNode(resolvedRootUserId, true, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Long> getAllSubordinateUserIds(Long managerUserId) {
|
||||||
|
if (managerUserId == null) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
TreeBuildContext context = buildTreeContext(new UserManagementRelationQueryReqVO());
|
||||||
|
if (context == null) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
Set<Long> result = new LinkedHashSet<>();
|
||||||
|
collectSubordinateIds(managerUserId, context, result);
|
||||||
|
result.remove(managerUserId);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过某个用户的id,判断管理链路表中是否有该用户的记录
|
* 通过某个用户的id,判断管理链路表中是否有该用户的记录
|
||||||
* 判断原则:
|
* 判断原则:
|
||||||
@@ -636,6 +676,57 @@ public class UserManagementRelationServiceImpl implements UserManagementRelation
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MySubordinateTreeRespVO buildMySubordinateTreeNode(Long userId, boolean root, TreeBuildContext context) {
|
||||||
|
AdminUserDO user = context.getUserMap().get(userId);
|
||||||
|
if (!adminUserService.isUserAvailable(user)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<MySubordinateTreeRespVO> children = new ArrayList<>();
|
||||||
|
for (Long subordinateId : context.getManagerToSubordinatesMap().getOrDefault(userId, Collections.emptyList())) {
|
||||||
|
if (Objects.equals(subordinateId, userId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
MySubordinateTreeRespVO child = buildMySubordinateTreeNode(subordinateId, false, context);
|
||||||
|
if (child != null) {
|
||||||
|
children.add(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MySubordinateTreeRespVO node = new MySubordinateTreeRespVO();
|
||||||
|
node.setUserId(user.getId());
|
||||||
|
node.setUserNickname(user.getNickname());
|
||||||
|
node.setIsRoot(root);
|
||||||
|
node.setChildren(children);
|
||||||
|
node.setSubordinateCount(sumSubordinateCount(children));
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int sumSubordinateCount(List<MySubordinateTreeRespVO> children) {
|
||||||
|
int total = 0;
|
||||||
|
for (MySubordinateTreeRespVO child : children) {
|
||||||
|
if (child == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
total += 1;
|
||||||
|
total += child.getSubordinateCount() == null ? 0 : child.getSubordinateCount();
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectSubordinateIds(Long managerUserId, TreeBuildContext context, Set<Long> result) {
|
||||||
|
for (Long subordinateId : context.getManagerToSubordinatesMap().getOrDefault(managerUserId, Collections.emptyList())) {
|
||||||
|
if (Objects.equals(subordinateId, managerUserId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
AdminUserDO subordinate = context.getUserMap().get(subordinateId);
|
||||||
|
if (!adminUserService.isUserAvailable(subordinate)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (result.add(subordinateId)) {
|
||||||
|
collectSubordinateIds(subordinateId, context, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 统一时间有效性过滤条件:
|
* 统一时间有效性过滤条件:
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
Reference in New Issue
Block a user