fix(加班申请): 去掉撤销相关的状态和动作。

feat(工作报告): 开发工作报告功能,包含导出功能
This commit is contained in:
dk
2026-06-11 09:58:31 +08:00
parent 79591e66be
commit 33239700fd
97 changed files with 7581 additions and 68 deletions

View File

@@ -240,5 +240,21 @@ public interface ErrorCodeConstants {
ErrorCode OVERTIME_APPLICATION_APPROVER_INVALID = new ErrorCode(1_008_009_008, "审核人不是有效系统用户"); ErrorCode OVERTIME_APPLICATION_APPROVER_INVALID = new ErrorCode(1_008_009_008, "审核人不是有效系统用户");
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_CANCELLED = new ErrorCode(1_008_009_011, "仅已撤销的加班申请允许删除"); ErrorCode OVERTIME_APPLICATION_DELETE_ONLY_REJECTED = new ErrorCode(1_008_009_011, "仅已退回的加班申请允许删除");
// ========== 工作报告 1_008_010_xxx ==========
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_ACTION_NOT_ALLOWED = new ErrorCode(1_008_010_003, "当前工作报告状态不支持动作【{}】");
ErrorCode WORK_REPORT_STATUS_ACTION_REASON_REQUIRED = new ErrorCode(1_008_010_004, "动作【{}】必须填写原因");
ErrorCode WORK_REPORT_STATUS_CONCURRENT_MODIFIED = new ErrorCode(1_008_010_005, "工作报告状态已发生变化,请刷新后重试");
ErrorCode WORK_REPORT_REPORTER_ONLY = new ErrorCode(1_008_010_006, "仅填报人可执行该操作");
ErrorCode WORK_REPORT_APPROVER_ONLY = new ErrorCode(1_008_010_007, "仅当前审核人可执行该操作");
ErrorCode WORK_REPORT_READ_FORBIDDEN = new ErrorCode(1_008_010_008, "无权查看该工作报告");
ErrorCode WORK_REPORT_DIRECT_MANAGER_NOT_EXISTS = new ErrorCode(1_008_010_009, "当前用户不存在生效中的直属上级,无法提交工作报告");
ErrorCode WORK_REPORT_PROJECT_NOT_EXISTS = new ErrorCode(1_008_010_010, "项目半月报对应的项目不存在");
ErrorCode WORK_REPORT_STATUS_NOT_ALLOW_EDIT = new ErrorCode(1_008_010_011, "当前工作报告状态不允许编辑");
ErrorCode WORK_REPORT_DELETE_NOT_ALLOWED = new ErrorCode(1_008_010_012, "当前工作报告状态不允许删除");
ErrorCode WORK_REPORT_PERIOD_DUPLICATE = new ErrorCode(1_008_010_013, "当前周期的工作报告已存在,请勿重复创建");
ErrorCode WORK_REPORT_APPROVAL_RECORD_NOT_EXISTS = new ErrorCode(1_008_010_014, "工作报告审核记录不存在");
ErrorCode WORK_REPORT_PROJECT_OWNER_ONLY = new ErrorCode(1_008_010_015, "仅项目负责人可创建或维护该项目的项目半月报");
} }

View File

@@ -65,6 +65,12 @@
<artifactId>rdms-spring-boot-starter-excel</artifactId> <artifactId>rdms-spring-boot-starter-excel</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.4.1</version>
</dependency>
<!-- Registry 注册中心相关 --> <!-- Registry 注册中心相关 -->
<dependency> <dependency>
<groupId>com.alibaba.cloud</groupId> <groupId>com.alibaba.cloud</groupId>

View File

@@ -14,7 +14,6 @@ public final class OvertimeApplicationConstants {
public static final String STATUS_PENDING = "pending"; public static final String STATUS_PENDING = "pending";
public static final String STATUS_APPROVED = "approved"; public static final String STATUS_APPROVED = "approved";
public static final String STATUS_REJECTED = "rejected"; public static final String STATUS_REJECTED = "rejected";
public static final String STATUS_CANCELLED = "cancelled";
/** /**
* 新建即提交的业务日志动作。 * 新建即提交的业务日志动作。
@@ -25,7 +24,6 @@ public final class OvertimeApplicationConstants {
public static final String ACTION_RESUBMIT = "resubmit"; public static final String ACTION_RESUBMIT = "resubmit";
public static final String ACTION_APPROVE = "approve"; public static final String ACTION_APPROVE = "approve";
public static final String ACTION_REJECT = "reject"; public static final String ACTION_REJECT = "reject";
public static final String ACTION_CANCEL = "cancel";
public static final String ACTION_DELETE = "delete"; public static final String ACTION_DELETE = "delete";
public static final String PERMISSION_QUERY = "project:overtime-application:query"; public static final String PERMISSION_QUERY = "project:overtime-application:query";

View File

@@ -0,0 +1,41 @@
package com.njcn.rdms.module.project.constant;
/**
* 工作报告常量。
*/
public final class WorkReportConstants {
private WorkReportConstants() {
}
public static final String STATUS_OBJECT_TYPE = "work_report";
public static final String REPORT_TYPE_WEEKLY = "weekly";
public static final String REPORT_TYPE_MONTHLY = "monthly";
public static final String REPORT_TYPE_PROJECT = "project";
public static final String BIZ_TYPE_WEEKLY = "weekly_report";
public static final String BIZ_TYPE_MONTHLY = "monthly_report";
public static final String BIZ_TYPE_PROJECT = "project_report";
public static final String STATUS_DRAFT = "draft";
public static final String STATUS_PENDING_APPROVAL = "pending_approval";
public static final String STATUS_APPROVED = "approved";
public static final String STATUS_REJECTED = "rejected";
public static final String ACTION_CREATE = "create";
public static final String ACTION_UPDATE = "update";
public static final String ACTION_DELETE = "delete";
public static final String ACTION_SUBMIT = "submit";
public static final String ACTION_RESUBMIT = "resubmit";
public static final String ACTION_APPROVE = "approve";
public static final String ACTION_REJECT = "reject";
public static final String PERMISSION_QUERY = "project:work-report:query";
public static final String PERMISSION_CREATE = "project:work-report:create";
public static final String PERMISSION_UPDATE = "project:work-report:update";
public static final String PERMISSION_DELETE = "project:work-report:delete";
public static final String PERMISSION_APPROVE = "project:work-report:approve";
public static final String PERMISSION_EXPORT = "project:work-report:export";
public static final String PERMISSION_PROJECT_OWNER = "project:work-report:project-owner";
}

View File

@@ -5,6 +5,7 @@ import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageResult; import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.excel.core.util.ExcelUtils; import com.njcn.rdms.framework.excel.core.util.ExcelUtils;
import com.njcn.rdms.module.project.constant.OvertimeApplicationConstants; import com.njcn.rdms.module.project.constant.OvertimeApplicationConstants;
import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationApprovalRecordRespVO;
import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationExportVO; import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationExportVO;
import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationPageReqVO; 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.controller.admin.overtime.vo.OvertimeApplicationRespVO;
@@ -53,7 +54,7 @@ public class OvertimeApplicationController {
} }
@PutMapping("/{id}") @PutMapping("/{id}")
@Operation(summary = "退回或撤销后修改并重新提交加班申请") @Operation(summary = "退回后修改并重新提交加班申请")
@PreAuthorize("@ss.hasPermission('" + OvertimeApplicationConstants.PERMISSION_UPDATE + "')") @PreAuthorize("@ss.hasPermission('" + OvertimeApplicationConstants.PERMISSION_UPDATE + "')")
public CommonResult<Boolean> resubmit(@PathVariable("id") Long id, public CommonResult<Boolean> resubmit(@PathVariable("id") Long id,
@Valid @RequestBody OvertimeApplicationSaveReqVO reqVO) { @Valid @RequestBody OvertimeApplicationSaveReqVO reqVO) {
@@ -107,17 +108,8 @@ public class OvertimeApplicationController {
return success(true); return success(true);
} }
@PostMapping("/{id}/cancel")
@Operation(summary = "撤销加班申请")
@PreAuthorize("@ss.hasPermission('" + OvertimeApplicationConstants.PERMISSION_UPDATE + "')")
public CommonResult<Boolean> cancel(@PathVariable("id") Long id,
@Valid @RequestBody OvertimeApplicationStatusActionReqVO reqVO) {
overtimeApplicationService.cancel(id, reqVO);
return success(true);
}
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
@Operation(summary = "删除已撤销的加班申请") @Operation(summary = "删除已退回的加班申请")
@PreAuthorize("@ss.hasPermission('" + OvertimeApplicationConstants.PERMISSION_DELETE + "')") @PreAuthorize("@ss.hasPermission('" + OvertimeApplicationConstants.PERMISSION_DELETE + "')")
public CommonResult<Boolean> delete(@PathVariable("id") Long id) { public CommonResult<Boolean> delete(@PathVariable("id") Long id) {
overtimeApplicationService.deleteApplication(id); overtimeApplicationService.deleteApplication(id);
@@ -131,6 +123,13 @@ public class OvertimeApplicationController {
return success(overtimeApplicationService.getStatusLogs(id)); return success(overtimeApplicationService.getStatusLogs(id));
} }
@GetMapping("/{id}/approval-records")
@Operation(summary = "获取加班申请审核记录")
@PreAuthorize("@ss.hasPermission('" + OvertimeApplicationConstants.PERMISSION_QUERY + "')")
public CommonResult<List<OvertimeApplicationApprovalRecordRespVO>> approvalRecords(@PathVariable("id") Long id) {
return success(overtimeApplicationService.getApprovalRecords(id));
}
@GetMapping("/export") @GetMapping("/export")
@Operation(summary = "导出我的加班申请") @Operation(summary = "导出我的加班申请")
@PreAuthorize("@ss.hasPermission('" + OvertimeApplicationConstants.PERMISSION_EXPORT + "')") @PreAuthorize("@ss.hasPermission('" + OvertimeApplicationConstants.PERMISSION_EXPORT + "')")

View File

@@ -0,0 +1,29 @@
package com.njcn.rdms.module.project.controller.admin.overtime.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 加班申请审核记录 Response VO")
@Data
public class OvertimeApplicationApprovalRecordRespVO {
private Long id;
private Long overtimeApplicationId;
private Long statusLogId;
private Integer approvalRound;
private String conclusion;
private String opinion;
private Long auditorUserId;
private String auditorName;
private LocalDateTime createTime;
}

View File

@@ -8,7 +8,7 @@ import lombok.Data;
@Data @Data
public class OvertimeApplicationStatusActionReqVO { public class OvertimeApplicationStatusActionReqVO {
@Schema(description = "动作原因或审核意见。是否必填以状态机配置为准;当前退回必填,撤销选填", @Schema(description = "动作原因或审核意见。是否必填以状态机配置为准;当前退回必填",
example = "请补充加班内容") example = "请补充加班内容")
@Size(max = 1000, message = "动作原因长度不能超过 1000 个字符") @Size(max = 1000, message = "动作原因长度不能超过 1000 个字符")
private String reason; private String reason;

View File

@@ -0,0 +1,20 @@
package com.njcn.rdms.module.project.controller.admin.workreport.common;
import com.njcn.rdms.framework.common.util.http.HttpUtils;
import com.njcn.rdms.module.project.service.workreport.export.WorkReportExportFile;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public final class WorkReportExportResponseUtils {
private WorkReportExportResponseUtils() {
}
public static void write(HttpServletResponse response, WorkReportExportFile file) throws IOException {
response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(file.filename()));
response.setContentType(file.contentType());
response.setContentLength(file.content().length);
response.getOutputStream().write(file.content());
}
}

View File

@@ -0,0 +1,35 @@
package com.njcn.rdms.module.project.controller.admin.workreport.common;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.module.project.constant.WorkReportConstants;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusDictRespVO;
import com.njcn.rdms.module.project.service.workreport.common.WorkReportStatusService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
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 java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 工作报告状态")
@RestController
@RequestMapping("/project/work-reports")
@Validated
public class WorkReportStatusController {
@Resource
private WorkReportStatusService workReportStatusService;
@GetMapping("/status/dict")
@Operation(summary = "获取工作报告所有状态字典")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_QUERY + "')")
public CommonResult<List<WorkReportStatusDictRespVO>> getStatusDict() {
return success(workReportStatusService.getStatusDict());
}
}

View File

@@ -0,0 +1,19 @@
package com.njcn.rdms.module.project.controller.admin.workreport.common.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 个人报告计划项 Request VO")
@Data
public class PersonalReportPlanItemReqVO {
private Integer itemNumber;
private String itemTitle;
private String targetText;
private Object targetJson;
private String supportNeed;
}

View File

@@ -0,0 +1,21 @@
package com.njcn.rdms.module.project.controller.admin.workreport.common.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 个人报告计划项 Response VO")
@Data
public class PersonalReportPlanItemRespVO {
private Long id;
private Integer itemNumber;
private String itemTitle;
private String targetText;
private Object targetJson;
private String supportNeed;
}

View File

@@ -0,0 +1,23 @@
package com.njcn.rdms.module.project.controller.admin.workreport.common.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 个人报告回顾项 Request VO")
@Data
public class PersonalReportReviewItemReqVO {
private Integer itemNumber;
private String itemTitle;
private BigDecimal workHours;
private String contentText;
private Object contentJson;
private String reflectionText;
}

View File

@@ -0,0 +1,25 @@
package com.njcn.rdms.module.project.controller.admin.workreport.common.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 个人报告回顾项 Response VO")
@Data
public class PersonalReportReviewItemRespVO {
private Long id;
private Integer itemNumber;
private String itemTitle;
private BigDecimal workHours;
private String contentText;
private Object contentJson;
private String reflectionText;
}

View File

@@ -0,0 +1,27 @@
package com.njcn.rdms.module.project.controller.admin.workreport.common.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 工作报告审核记录 Response VO")
@Data
public class WorkReportApprovalRecordRespVO {
private Long id;
private Long statusLogId;
private Integer approvalRound;
private String conclusion;
private String opinion;
private Long auditorUserId;
private String auditorName;
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,32 @@
package com.njcn.rdms.module.project.controller.admin.workreport.common.vo;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
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;
@Data
@EqualsAndHashCode(callSuper = true)
public class WorkReportBasePageReqVO extends PageParam {
@Schema(description = "关键字")
private String keyword;
@Schema(description = "状态编码")
private String statusCode;
@Schema(description = "周期开始日期范围")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate[] periodStartDate;
@Schema(description = "提交时间范围")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] submitTime;
}

View File

@@ -0,0 +1,13 @@
package com.njcn.rdms.module.project.controller.admin.workreport.common.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 项目成员快照 Response VO")
@Data
public class WorkReportMemberSnapshotRespVO {
private Long userId;
private String userName;
}

View File

@@ -0,0 +1,14 @@
package com.njcn.rdms.module.project.controller.admin.workreport.common.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Size;
import lombok.Data;
@Schema(description = "管理后台 - 工作报告状态动作 Request VO")
@Data
public class WorkReportStatusActionReqVO {
@Schema(description = "原因或审核意见", example = "请补充下周计划")
@Size(max = 1000, message = "原因或审核意见长度不能超过 1000 个字符")
private String reason;
}

View File

@@ -0,0 +1,27 @@
package com.njcn.rdms.module.project.controller.admin.workreport.common.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 工作报告状态字典 Response VO")
@Data
public class WorkReportStatusDictRespVO {
@Schema(description = "状态编码", example = "draft")
private String statusCode;
@Schema(description = "状态名称", example = "待提交")
private String statusName;
@Schema(description = "排序", example = "10")
private Integer sort;
@Schema(description = "是否初始态")
private Boolean initialFlag;
@Schema(description = "是否终态")
private Boolean terminalFlag;
@Schema(description = "是否允许编辑")
private Boolean allowEdit;
}

View File

@@ -0,0 +1,35 @@
package com.njcn.rdms.module.project.controller.admin.workreport.common.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 工作报告状态日志 Response VO")
@Data
public class WorkReportStatusLogRespVO {
private Long id;
private String reportType;
private Long reportId;
private String actionType;
private String fromStatus;
private String toStatus;
private String reason;
private Long operatorUserId;
private String operatorName;
private String periodLabelSnapshot;
private String remark;
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,172 @@
package com.njcn.rdms.module.project.controller.admin.workreport.monthly;
import com.njcn.rdms.framework.apilog.core.annotation.ApiAccessLog;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.excel.core.util.ExcelUtils;
import com.njcn.rdms.module.project.constant.WorkReportConstants;
import com.njcn.rdms.module.project.controller.admin.workreport.common.WorkReportExportResponseUtils;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusActionReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusLogRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportApprovalRecordRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportApproveReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportContentExportReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportDefaultDraftReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportExportVO;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportPageReqVO;
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.service.workreport.export.WorkReportContentExportService;
import com.njcn.rdms.module.project.service.workreport.monthly.MonthlyReportService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.time.LocalDate;
import java.util.List;
import static com.njcn.rdms.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 个人月报")
@RestController
@RequestMapping("/project/work-reports/monthly")
@Validated
public class MonthlyReportController {
@Resource
private MonthlyReportService monthlyReportService;
@Resource
private WorkReportContentExportService workReportContentExportService;
@GetMapping("/init")
@Operation(summary = "获取月报新建默认数据")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_CREATE + "')")
public CommonResult<MonthlyReportRespVO> initMonthlyReport() {
return success(monthlyReportService.initMonthlyReport());
}
@GetMapping("/default-draft")
@Operation(summary = "预览月报默认稿")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_CREATE + "')")
public CommonResult<MonthlyReportRespVO> previewMonthlyDefaultDraft(@Valid MonthlyReportDefaultDraftReqVO reqVO) {
return success(monthlyReportService.previewMonthlyDefaultDraft(reqVO));
}
@PostMapping
@Operation(summary = "新建月报草稿")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_CREATE + "')")
public CommonResult<Long> createMonthlyReport(@Valid @RequestBody MonthlyReportSaveReqVO reqVO) {
return success(monthlyReportService.createMonthlyReport(reqVO));
}
@PutMapping("/{id}")
@Operation(summary = "修改月报草稿")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_UPDATE + "')")
public CommonResult<Boolean> updateMonthlyReport(@PathVariable("id") Long id,
@Valid @RequestBody MonthlyReportSaveReqVO reqVO) {
monthlyReportService.updateMonthlyReport(id, reqVO);
return success(true);
}
@GetMapping("/{id}")
@Operation(summary = "获取月报详情")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_QUERY + "')")
public CommonResult<MonthlyReportRespVO> getMonthlyReport(@PathVariable("id") Long id) {
return success(monthlyReportService.getMonthlyReport(id));
}
@GetMapping("/page")
@Operation(summary = "获取我的月报分页")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_QUERY + "')")
public CommonResult<PageResult<MonthlyReportRespVO>> getMonthlyReportPage(@Valid MonthlyReportPageReqVO reqVO) {
return success(monthlyReportService.getMonthlyReportPage(reqVO));
}
@GetMapping("/approval-page")
@Operation(summary = "获取待我审批的月报分页")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_APPROVE + "')")
public CommonResult<PageResult<MonthlyReportRespVO>> getMonthlyApprovalPage(@Valid MonthlyReportPageReqVO reqVO) {
return success(monthlyReportService.getMonthlyApprovalPage(reqVO));
}
@PostMapping("/{id}/submit")
@Operation(summary = "提交月报")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_UPDATE + "')")
public CommonResult<Boolean> submitMonthlyReport(@PathVariable("id") Long id) {
monthlyReportService.submitMonthlyReport(id);
return success(true);
}
@PostMapping("/{id}/approve")
@Operation(summary = "审批通过月报")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_APPROVE + "')")
public CommonResult<Boolean> approveMonthlyReport(@PathVariable("id") Long id,
@Valid @RequestBody MonthlyReportApproveReqVO reqVO) {
monthlyReportService.approveMonthlyReport(id, reqVO);
return success(true);
}
@PostMapping("/{id}/reject")
@Operation(summary = "退回月报")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_APPROVE + "')")
public CommonResult<Boolean> rejectMonthlyReport(@PathVariable("id") Long id,
@Valid @RequestBody WorkReportStatusActionReqVO reqVO) {
monthlyReportService.rejectMonthlyReport(id, reqVO);
return success(true);
}
@DeleteMapping("/{id}")
@Operation(summary = "删除月报")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_DELETE + "')")
public CommonResult<Boolean> deleteMonthlyReport(@PathVariable("id") Long id) {
monthlyReportService.deleteMonthlyReport(id);
return success(true);
}
@GetMapping("/{id}/status-logs")
@Operation(summary = "获取月报状态日志")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_QUERY + "')")
public CommonResult<List<WorkReportStatusLogRespVO>> getMonthlyStatusLogs(@PathVariable("id") Long id) {
return success(monthlyReportService.getMonthlyStatusLogs(id));
}
@GetMapping("/{id}/approval-records")
@Operation(summary = "获取月报审批记录")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_QUERY + "')")
public CommonResult<List<MonthlyReportApprovalRecordRespVO>> getMonthlyApprovalRecords(@PathVariable("id") Long id) {
return success(monthlyReportService.getMonthlyApprovalRecords(id));
}
@GetMapping("/export")
@Operation(summary = "导出我的月报")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_EXPORT + "')")
@ApiAccessLog(operateType = EXPORT)
public void exportMonthlyReport(@Valid MonthlyReportPageReqVO reqVO, HttpServletResponse response)
throws IOException {
ExcelUtils.write(response, "个人月报_" + LocalDate.now() + ".xls", "个人月报",
MonthlyReportExportVO.class, monthlyReportService.getMonthlyExportList(reqVO));
}
@PostMapping("/content-export")
@Operation(summary = "导出月报内容 Word")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_EXPORT + "')")
@ApiAccessLog(operateType = EXPORT)
public void exportMonthlyReportContent(@Valid @RequestBody MonthlyReportContentExportReqVO reqVO,
HttpServletResponse response) throws IOException {
WorkReportExportResponseUtils.write(response, workReportContentExportService.exportMonthly(reqVO));
}
}

View File

@@ -0,0 +1,50 @@
package com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 月报审核记录 Response VO")
@Data
public class MonthlyReportApprovalRecordRespVO {
private Long id;
private Long statusLogId;
private Integer approvalRound;
private String conclusion;
private String opinion;
private LocalDate meetingDate;
private String strengthDesc;
private String strengthExample;
private String weaknessDesc;
private String weaknessExample;
private String improvementSuggestion;
private String performanceResult;
private String employeeSignName;
private LocalDate employeeSignedDate;
private String supervisorSignName;
private LocalDate supervisorSignedDate;
private Long auditorUserId;
private String auditorName;
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,57 @@
package com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusActionReqVO;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@Schema(description = "管理后台 - 月报审核通过 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class MonthlyReportApproveReqVO extends WorkReportStatusActionReqVO {
@Schema(description = "面谈时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
@NotNull
private LocalDate meetingDate;
@Schema(description = "优势描述")
private String strengthDesc;
@Schema(description = "优势行为事例")
private String strengthExample;
@Schema(description = "劣势描述")
private String weaknessDesc;
@Schema(description = "劣势行为事例")
private String weaknessExample;
@Schema(description = "改进建议")
private String improvementSuggestion;
@Schema(description = "绩效考核结果")
@NotBlank(message = "绩效考核结果不能为空")
private String performanceResult;
@Schema(description = "被考核人签名")
private String employeeSignName;
@Schema(description = "被考核人签字日期")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate employeeSignedDate;
@Schema(description = "上级签名")
private String supervisorSignName;
@Schema(description = "上级签字日期")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate supervisorSignedDate;
}

View File

@@ -0,0 +1,19 @@
package com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Schema(description = "管理后台 - 月报内容导出 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class MonthlyReportContentExportReqVO extends MonthlyReportPageReqVO {
@Schema(description = "是否按当前搜索条件全量导出")
private Boolean exportAll;
@Schema(description = "选中的月报编号列表exportAll=false 时必填")
private List<Long> ids;
}

View File

@@ -0,0 +1,30 @@
package com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@Schema(description = "管理后台 - 月报默认稿预览 Request VO")
@Data
public class MonthlyReportDefaultDraftReqVO {
@NotBlank(message = "周期编码不能为空")
private String periodKey;
@NotBlank(message = "周期名称不能为空")
private String periodLabel;
@NotNull(message = "周期开始日期不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate periodStartDate;
@NotNull(message = "周期结束日期不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate periodEndDate;
}

View File

@@ -0,0 +1,44 @@
package com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@ExcelIgnoreUnannotated
public class MonthlyReportExportVO {
@ExcelProperty("填报人")
private String reporterName;
@ExcelProperty("直属上级")
private String supervisorName;
@ExcelProperty("周期")
private String periodLabel;
@ExcelProperty("开始日期")
private LocalDate periodStartDate;
@ExcelProperty("结束日期")
private LocalDate periodEndDate;
@ExcelProperty("工时")
private BigDecimal totalWorkHours;
@ExcelProperty("状态")
private String statusName;
@ExcelProperty("审核意见")
private String approvalComment;
@ExcelProperty("提交时间")
private LocalDateTime submitTime;
@ExcelProperty("审核时间")
private LocalDateTime approvalTime;
}

View File

@@ -0,0 +1,12 @@
package com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportBasePageReqVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Schema(description = "管理后台 - 月报分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class MonthlyReportPageReqVO extends WorkReportBasePageReqVO {
}

View File

@@ -0,0 +1,41 @@
package com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.PersonalReportPlanItemRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.PersonalReportReviewItemRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - 月报 Response VO")
@Data
public class MonthlyReportRespVO {
private Long id;
private Long reporterId;
private String reporterName;
private String reporterDeptName;
private String reporterPostName;
private Long supervisorUserId;
private String supervisorName;
private String periodKey;
private String periodLabel;
private LocalDate periodStartDate;
private LocalDate periodEndDate;
private String statusCode;
private String statusName;
private Boolean allowEdit;
private Boolean terminal;
private BigDecimal totalWorkHours;
private String approvalComment;
private String lastStatusReason;
private LocalDateTime submitTime;
private LocalDateTime approvalTime;
private LocalDateTime createTime;
private LocalDateTime updateTime;
private List<PersonalReportReviewItemRespVO> reviewItems;
private List<PersonalReportPlanItemRespVO> planItems;
}

View File

@@ -0,0 +1,40 @@
package com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.PersonalReportPlanItemReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.PersonalReportReviewItemReqVO;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import java.util.List;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@Schema(description = "管理后台 - 月报保存 Request VO")
@Data
public class MonthlyReportSaveReqVO {
@NotBlank(message = "周期编码不能为空")
private String periodKey;
@NotBlank(message = "周期名称不能为空")
private String periodLabel;
@NotNull(message = "周期开始日期不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate periodStartDate;
@NotNull(message = "周期结束日期不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate periodEndDate;
@Valid
private List<PersonalReportReviewItemReqVO> reviewItems;
@Valid
private List<PersonalReportPlanItemReqVO> planItems;
}

View File

@@ -0,0 +1,181 @@
package com.njcn.rdms.module.project.controller.admin.workreport.project;
import com.njcn.rdms.framework.apilog.core.annotation.ApiAccessLog;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.excel.core.util.ExcelUtils;
import com.njcn.rdms.module.project.constant.WorkReportConstants;
import com.njcn.rdms.module.project.controller.admin.workreport.common.WorkReportExportResponseUtils;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportApprovalRecordRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusActionReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusLogRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportContentExportReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportDefaultDraftReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportExportVO;
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportOwnerProjectOptionRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportPageReqVO;
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.service.workreport.export.WorkReportContentExportService;
import com.njcn.rdms.module.project.service.workreport.project.ProjectReportService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.time.LocalDate;
import java.util.List;
import static com.njcn.rdms.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 项目半月报")
@RestController
@RequestMapping("/project/work-reports/project")
@Validated
public class ProjectReportController {
@Resource
private ProjectReportService projectReportService;
@Resource
private WorkReportContentExportService workReportContentExportService;
@GetMapping("/owner-project-options")
@Operation(summary = "获取项目半月报负责人可选项目列表")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_PROJECT_OWNER + "')")
public CommonResult<List<ProjectReportOwnerProjectOptionRespVO>> getOwnerProjectOptions() {
return success(projectReportService.getOwnerProjectOptions());
}
@GetMapping("/init")
@Operation(summary = "获取项目半月报新建默认数据")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_PROJECT_OWNER + "')")
public CommonResult<ProjectReportRespVO> initProjectReport(@RequestParam("projectId") Long projectId) {
return success(projectReportService.initProjectReport(projectId));
}
@GetMapping("/{projectId}/default-draft")
@Operation(summary = "预览项目半月报默认稿")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_PROJECT_OWNER + "')")
public CommonResult<ProjectReportRespVO> previewProjectDefaultDraft(@PathVariable("projectId") Long projectId,
@Valid ProjectReportDefaultDraftReqVO reqVO) {
return success(projectReportService.previewProjectDefaultDraft(projectId, reqVO));
}
@PostMapping
@Operation(summary = "新建项目半月报草稿")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_PROJECT_OWNER + "')")
public CommonResult<Long> createProjectReport(@Valid @RequestBody ProjectReportSaveReqVO reqVO) {
return success(projectReportService.createProjectReport(reqVO));
}
@PutMapping("/{id}")
@Operation(summary = "修改项目半月报草稿")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_PROJECT_OWNER + "')")
public CommonResult<Boolean> updateProjectReport(@PathVariable("id") Long id,
@Valid @RequestBody ProjectReportSaveReqVO reqVO) {
projectReportService.updateProjectReport(id, reqVO);
return success(true);
}
@GetMapping("/{id}")
@Operation(summary = "获取项目半月报详情")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_QUERY + "')")
public CommonResult<ProjectReportRespVO> getProjectReport(@PathVariable("id") Long id) {
return success(projectReportService.getProjectReport(id));
}
@GetMapping("/page")
@Operation(summary = "获取我的项目半月报分页")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_QUERY + "')")
public CommonResult<PageResult<ProjectReportRespVO>> getProjectReportPage(@Valid ProjectReportPageReqVO reqVO) {
return success(projectReportService.getProjectReportPage(reqVO));
}
@GetMapping("/approval-page")
@Operation(summary = "获取待我审批的项目半月报分页")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_APPROVE + "')")
public CommonResult<PageResult<ProjectReportRespVO>> getProjectApprovalPage(@Valid ProjectReportPageReqVO reqVO) {
return success(projectReportService.getProjectApprovalPage(reqVO));
}
@PostMapping("/{id}/submit")
@Operation(summary = "提交项目半月报")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_UPDATE + "')")
public CommonResult<Boolean> submitProjectReport(@PathVariable("id") Long id) {
projectReportService.submitProjectReport(id);
return success(true);
}
@PostMapping("/{id}/approve")
@Operation(summary = "审批通过项目半月报")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_APPROVE + "')")
public CommonResult<Boolean> approveProjectReport(@PathVariable("id") Long id,
@Valid @RequestBody WorkReportStatusActionReqVO reqVO) {
projectReportService.approveProjectReport(id, reqVO);
return success(true);
}
@PostMapping("/{id}/reject")
@Operation(summary = "退回项目半月报")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_APPROVE + "')")
public CommonResult<Boolean> rejectProjectReport(@PathVariable("id") Long id,
@Valid @RequestBody WorkReportStatusActionReqVO reqVO) {
projectReportService.rejectProjectReport(id, reqVO);
return success(true);
}
@DeleteMapping("/{id}")
@Operation(summary = "删除项目半月报")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_DELETE + "')")
public CommonResult<Boolean> deleteProjectReport(@PathVariable("id") Long id) {
projectReportService.deleteProjectReport(id);
return success(true);
}
@GetMapping("/{id}/status-logs")
@Operation(summary = "获取项目半月报状态日志")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_QUERY + "')")
public CommonResult<List<WorkReportStatusLogRespVO>> getProjectStatusLogs(@PathVariable("id") Long id) {
return success(projectReportService.getProjectStatusLogs(id));
}
@GetMapping("/{id}/approval-records")
@Operation(summary = "获取项目半月报审批记录")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_QUERY + "')")
public CommonResult<List<WorkReportApprovalRecordRespVO>> getProjectApprovalRecords(@PathVariable("id") Long id) {
return success(projectReportService.getProjectApprovalRecords(id));
}
@GetMapping("/export")
@Operation(summary = "导出我的项目半月报")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_EXPORT + "')")
@ApiAccessLog(operateType = EXPORT)
public void exportProjectReport(@Valid ProjectReportPageReqVO reqVO, HttpServletResponse response)
throws IOException {
ExcelUtils.write(response, "项目半月报_" + LocalDate.now() + ".xls", "项目半月报",
ProjectReportExportVO.class, projectReportService.getProjectExportList(reqVO));
}
@PostMapping("/content-export")
@Operation(summary = "导出项目半月报内容 Word")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_EXPORT + "')")
@ApiAccessLog(operateType = EXPORT)
public void exportProjectReportContent(@Valid @RequestBody ProjectReportContentExportReqVO reqVO,
HttpServletResponse response) throws IOException {
WorkReportExportResponseUtils.write(response, workReportContentExportService.exportProject(reqVO));
}
}

View File

@@ -0,0 +1,19 @@
package com.njcn.rdms.module.project.controller.admin.workreport.project.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Schema(description = "管理后台 - 项目半月报内容导出 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class ProjectReportContentExportReqVO extends ProjectReportPageReqVO {
@Schema(description = "是否按当前搜索条件全量导出")
private Boolean exportAll;
@Schema(description = "选中的项目半月报编号列表exportAll=false 时必填")
private List<Long> ids;
}

View File

@@ -0,0 +1,33 @@
package com.njcn.rdms.module.project.controller.admin.workreport.project.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@Schema(description = "管理后台 - 项目半月报默认稿预览 Request VO")
@Data
public class ProjectReportDefaultDraftReqVO {
@NotBlank(message = "周期编码不能为空")
private String periodKey;
@NotBlank(message = "周期名称不能为空")
private String periodLabel;
@NotNull(message = "周期开始日期不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate periodStartDate;
@NotNull(message = "周期结束日期不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate periodEndDate;
@NotNull(message = "上半月/下半月标记不能为空")
private Integer flag;
}

View File

@@ -0,0 +1,47 @@
package com.njcn.rdms.module.project.controller.admin.workreport.project.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@ExcelIgnoreUnannotated
public class ProjectReportExportVO {
@ExcelProperty("项目名称")
private String projectName;
@ExcelProperty("填报人")
private String projectOwnerName;
@ExcelProperty("直属上级")
private String supervisorName;
@ExcelProperty("周期")
private String periodLabel;
@ExcelProperty("开始日期")
private LocalDate periodStartDate;
@ExcelProperty("结束日期")
private LocalDate periodEndDate;
@ExcelProperty("工时")
private BigDecimal totalWorkHours;
@ExcelProperty("状态")
private String statusName;
@ExcelProperty("审核意见")
private String approvalComment;
@ExcelProperty("提交时间")
private LocalDateTime submitTime;
@ExcelProperty("审核时间")
private LocalDateTime approvalTime;
}

View File

@@ -0,0 +1,19 @@
package com.njcn.rdms.module.project.controller.admin.workreport.project.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 项目半月报工作项 Request VO")
@Data
public class ProjectReportItemReqVO {
private String itemTitle;
private BigDecimal workHours;
private String priorityCode;
private BigDecimal progressRate;
}

View File

@@ -0,0 +1,21 @@
package com.njcn.rdms.module.project.controller.admin.workreport.project.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 项目半月报工作项 Response VO")
@Data
public class ProjectReportItemRespVO {
private Long id;
private String itemTitle;
private BigDecimal workHours;
private String priorityCode;
private BigDecimal progressRate;
}

View File

@@ -0,0 +1,18 @@
package com.njcn.rdms.module.project.controller.admin.workreport.project.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 项目半月报负责人可选项目 Response VO")
@Data
public class ProjectReportOwnerProjectOptionRespVO {
@Schema(description = "项目编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "项目编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "CNPJ2026001")
private String projectCode;
@Schema(description = "项目名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "客户交付项目")
private String projectName;
}

View File

@@ -0,0 +1,18 @@
package com.njcn.rdms.module.project.controller.admin.workreport.project.vo;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportBasePageReqVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Schema(description = "管理后台 - 项目半月报分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class ProjectReportPageReqVO extends WorkReportBasePageReqVO {
@Schema(description = "项目编号")
private Long projectId;
@Schema(description = "上半月/下半月标记")
private Integer flag;
}

View File

@@ -0,0 +1,47 @@
package com.njcn.rdms.module.project.controller.admin.workreport.project.vo;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportMemberSnapshotRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - 项目半月报 Response VO")
@Data
public class ProjectReportRespVO {
private Long id;
private Long projectId;
private String projectName;
private Long projectOwnerId;
private String projectOwnerName;
private String technicalOwnerName;
private List<WorkReportMemberSnapshotRespVO> projectMemberSnapshot;
private Long supervisorUserId;
private String supervisorName;
private String periodKey;
private String periodLabel;
private LocalDate periodStartDate;
private LocalDate periodEndDate;
private Integer flag;
private String statusCode;
private String statusName;
private Boolean allowEdit;
private Boolean terminal;
private String projectStatusDesc;
private String projectProgressPlan;
private String projectKeyPoints;
private String projectProblems;
private BigDecimal totalWorkHours;
private String approvalComment;
private String lastStatusReason;
private LocalDateTime submitTime;
private LocalDateTime approvalTime;
private LocalDateTime createTime;
private LocalDateTime updateTime;
private List<ProjectReportItemRespVO> currentItems;
private List<ProjectReportItemRespVO> nextItems;
}

View File

@@ -0,0 +1,52 @@
package com.njcn.rdms.module.project.controller.admin.workreport.project.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import java.util.List;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@Schema(description = "管理后台 - 项目半月报保存 Request VO")
@Data
public class ProjectReportSaveReqVO {
@NotNull(message = "项目编号不能为空")
private Long projectId;
@NotBlank(message = "周期编码不能为空")
private String periodKey;
@NotBlank(message = "周期名称不能为空")
private String periodLabel;
@NotNull(message = "周期开始日期不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate periodStartDate;
@NotNull(message = "周期结束日期不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate periodEndDate;
@NotNull(message = "上半月/下半月标记不能为空")
private Integer flag;
private String projectStatusDesc;
private String projectProgressPlan;
private String projectKeyPoints;
private String projectProblems;
@Valid
private List<ProjectReportItemReqVO> currentItems;
@Valid
private List<ProjectReportItemReqVO> nextItems;
}

View File

@@ -0,0 +1,171 @@
package com.njcn.rdms.module.project.controller.admin.workreport.weekly;
import com.njcn.rdms.framework.apilog.core.annotation.ApiAccessLog;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.excel.core.util.ExcelUtils;
import com.njcn.rdms.module.project.constant.WorkReportConstants;
import com.njcn.rdms.module.project.controller.admin.workreport.common.WorkReportExportResponseUtils;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportApprovalRecordRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusActionReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusLogRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportContentExportReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportDefaultDraftReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportExportVO;
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportPageReqVO;
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.service.workreport.export.WorkReportContentExportService;
import com.njcn.rdms.module.project.service.workreport.weekly.WeeklyReportService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.time.LocalDate;
import java.util.List;
import static com.njcn.rdms.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 个人周报")
@RestController
@RequestMapping("/project/work-reports/weekly")
@Validated
public class WeeklyReportController {
@Resource
private WeeklyReportService weeklyReportService;
@Resource
private WorkReportContentExportService workReportContentExportService;
@GetMapping("/init")
@Operation(summary = "获取周报新建默认数据")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_CREATE + "')")
public CommonResult<WeeklyReportRespVO> initWeeklyReport() {
return success(weeklyReportService.initWeeklyReport());
}
@GetMapping("/default-draft")
@Operation(summary = "预览周报默认稿")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_CREATE + "')")
public CommonResult<WeeklyReportRespVO> previewWeeklyDefaultDraft(@Valid WeeklyReportDefaultDraftReqVO reqVO) {
return success(weeklyReportService.previewWeeklyDefaultDraft(reqVO));
}
@PostMapping
@Operation(summary = "新建周报草稿")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_CREATE + "')")
public CommonResult<Long> createWeeklyReport(@Valid @RequestBody WeeklyReportSaveReqVO reqVO) {
return success(weeklyReportService.createWeeklyReport(reqVO));
}
@PutMapping("/{id}")
@Operation(summary = "修改周报草稿")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_UPDATE + "')")
public CommonResult<Boolean> updateWeeklyReport(@PathVariable("id") Long id,
@Valid @RequestBody WeeklyReportSaveReqVO reqVO) {
weeklyReportService.updateWeeklyReport(id, reqVO);
return success(true);
}
@GetMapping("/{id}")
@Operation(summary = "获取周报详情")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_QUERY + "')")
public CommonResult<WeeklyReportRespVO> getWeeklyReport(@PathVariable("id") Long id) {
return success(weeklyReportService.getWeeklyReport(id));
}
@GetMapping("/page")
@Operation(summary = "获取我的周报分页")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_QUERY + "')")
public CommonResult<PageResult<WeeklyReportRespVO>> getWeeklyReportPage(@Valid WeeklyReportPageReqVO reqVO) {
return success(weeklyReportService.getWeeklyReportPage(reqVO));
}
@GetMapping("/approval-page")
@Operation(summary = "获取待我审批的周报分页")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_APPROVE + "')")
public CommonResult<PageResult<WeeklyReportRespVO>> getWeeklyApprovalPage(@Valid WeeklyReportPageReqVO reqVO) {
return success(weeklyReportService.getWeeklyApprovalPage(reqVO));
}
@PostMapping("/{id}/submit")
@Operation(summary = "提交周报")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_UPDATE + "')")
public CommonResult<Boolean> submitWeeklyReport(@PathVariable("id") Long id) {
weeklyReportService.submitWeeklyReport(id);
return success(true);
}
@PostMapping("/{id}/approve")
@Operation(summary = "审批通过周报")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_APPROVE + "')")
public CommonResult<Boolean> approveWeeklyReport(@PathVariable("id") Long id,
@Valid @RequestBody WorkReportStatusActionReqVO reqVO) {
weeklyReportService.approveWeeklyReport(id, reqVO);
return success(true);
}
@PostMapping("/{id}/reject")
@Operation(summary = "退回周报")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_APPROVE + "')")
public CommonResult<Boolean> rejectWeeklyReport(@PathVariable("id") Long id,
@Valid @RequestBody WorkReportStatusActionReqVO reqVO) {
weeklyReportService.rejectWeeklyReport(id, reqVO);
return success(true);
}
@DeleteMapping("/{id}")
@Operation(summary = "删除周报")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_DELETE + "')")
public CommonResult<Boolean> deleteWeeklyReport(@PathVariable("id") Long id) {
weeklyReportService.deleteWeeklyReport(id);
return success(true);
}
@GetMapping("/{id}/status-logs")
@Operation(summary = "获取周报状态日志")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_QUERY + "')")
public CommonResult<List<WorkReportStatusLogRespVO>> getWeeklyStatusLogs(@PathVariable("id") Long id) {
return success(weeklyReportService.getWeeklyStatusLogs(id));
}
@GetMapping("/{id}/approval-records")
@Operation(summary = "获取周报审批记录")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_QUERY + "')")
public CommonResult<List<WorkReportApprovalRecordRespVO>> getWeeklyApprovalRecords(@PathVariable("id") Long id) {
return success(weeklyReportService.getWeeklyApprovalRecords(id));
}
@GetMapping("/export")
@Operation(summary = "导出我的周报")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_EXPORT + "')")
@ApiAccessLog(operateType = EXPORT)
public void exportWeeklyReport(@Valid WeeklyReportPageReqVO reqVO, HttpServletResponse response)
throws IOException {
ExcelUtils.write(response, "个人周报_" + LocalDate.now() + ".xls", "个人周报",
WeeklyReportExportVO.class, weeklyReportService.getWeeklyExportList(reqVO));
}
@PostMapping("/content-export")
@Operation(summary = "导出周报内容 Word")
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_EXPORT + "')")
@ApiAccessLog(operateType = EXPORT)
public void exportWeeklyReportContent(@Valid @RequestBody WeeklyReportContentExportReqVO reqVO,
HttpServletResponse response) throws IOException {
WorkReportExportResponseUtils.write(response, workReportContentExportService.exportWeekly(reqVO));
}
}

View File

@@ -0,0 +1,19 @@
package com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Schema(description = "管理后台 - 周报内容导出 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class WeeklyReportContentExportReqVO extends WeeklyReportPageReqVO {
@Schema(description = "是否按当前搜索条件全量导出")
private Boolean exportAll;
@Schema(description = "选中的周报编号列表exportAll=false 时必填")
private List<Long> ids;
}

View File

@@ -0,0 +1,30 @@
package com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@Schema(description = "管理后台 - 周报默认稿预览 Request VO")
@Data
public class WeeklyReportDefaultDraftReqVO {
@NotBlank(message = "周期编码不能为空")
private String periodKey;
@NotBlank(message = "周期名称不能为空")
private String periodLabel;
@NotNull(message = "周期开始日期不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate periodStartDate;
@NotNull(message = "周期结束日期不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate periodEndDate;
}

View File

@@ -0,0 +1,50 @@
package com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@ExcelIgnoreUnannotated
public class WeeklyReportExportVO {
@ExcelProperty("填报人")
private String reporterName;
@ExcelProperty("直属上级")
private String supervisorName;
@ExcelProperty("周期")
private String periodLabel;
@ExcelProperty("开始日期")
private LocalDate periodStartDate;
@ExcelProperty("结束日期")
private LocalDate periodEndDate;
@ExcelProperty("是否出差")
private Boolean isBusinessTrip;
@ExcelProperty("出差天数")
private BigDecimal totalTravelDays;
@ExcelProperty("工时")
private BigDecimal totalWorkHours;
@ExcelProperty("状态")
private String statusName;
@ExcelProperty("审核意见")
private String approvalComment;
@ExcelProperty("提交时间")
private LocalDateTime submitTime;
@ExcelProperty("审核时间")
private LocalDateTime approvalTime;
}

View File

@@ -0,0 +1,15 @@
package com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportBasePageReqVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Schema(description = "管理后台 - 周报分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class WeeklyReportPageReqVO extends WorkReportBasePageReqVO {
@Schema(description = "是否出差")
private Boolean isBusinessTrip;
}

View File

@@ -0,0 +1,44 @@
package com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.PersonalReportPlanItemRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.PersonalReportReviewItemRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - 周报 Response VO")
@Data
public class WeeklyReportRespVO {
private Long id;
private Long reporterId;
private String reporterName;
private String reporterDeptName;
private String reporterPostName;
private Long supervisorUserId;
private String supervisorName;
private String periodKey;
private String periodLabel;
private LocalDate periodStartDate;
private LocalDate periodEndDate;
private String statusCode;
private String statusName;
private Boolean allowEdit;
private Boolean terminal;
private Boolean isBusinessTrip;
private BigDecimal totalTravelDays;
private BigDecimal totalWorkHours;
private String approvalComment;
private String lastStatusReason;
private LocalDateTime submitTime;
private LocalDateTime approvalTime;
private LocalDateTime createTime;
private LocalDateTime updateTime;
private List<PersonalReportReviewItemRespVO> reviewItems;
private List<PersonalReportPlanItemRespVO> planItems;
private List<WeeklyReportTravelSegmentRespVO> travelSegments;
}

View File

@@ -0,0 +1,46 @@
package com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.PersonalReportPlanItemReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.PersonalReportReviewItemReqVO;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import java.util.List;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@Schema(description = "管理后台 - 周报保存 Request VO")
@Data
public class WeeklyReportSaveReqVO {
@NotBlank(message = "周期编码不能为空")
private String periodKey;
@NotBlank(message = "周期名称不能为空")
private String periodLabel;
@NotNull(message = "周期开始日期不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate periodStartDate;
@NotNull(message = "周期结束日期不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate periodEndDate;
@NotNull(message = "是否出差不能为空")
private Boolean isBusinessTrip;
@Valid
private List<PersonalReportReviewItemReqVO> reviewItems;
@Valid
private List<PersonalReportPlanItemReqVO> planItems;
@Valid
private List<WeeklyReportTravelSegmentReqVO> travelSegments;
}

View File

@@ -0,0 +1,27 @@
package com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.time.LocalDate;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@Schema(description = "管理后台 - 周报出差分段 Request VO")
@Data
public class WeeklyReportTravelSegmentReqVO {
private Integer sort;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate startDate;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate endDate;
private BigDecimal travelDays;
private String location;
}

View File

@@ -0,0 +1,24 @@
package com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
@Schema(description = "管理后台 - 周报出差分段 Response VO")
@Data
public class WeeklyReportTravelSegmentRespVO {
private Long id;
private Integer sort;
private LocalDate startDate;
private LocalDate endDate;
private BigDecimal travelDays;
private String location;
}

View File

@@ -0,0 +1,36 @@
package com.njcn.rdms.module.project.dal.dataobject.overtime;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 加班申请审核记录。
*/
@TableName("rdms_overtime_application_approval_record")
@Data
@EqualsAndHashCode(callSuper = true)
public class OvertimeApplicationApprovalRecordDO extends BaseDO {
@TableId
private Long id;
private Long overtimeApplicationId;
private Long statusLogId;
private Integer approvalRound;
private String conclusion;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String opinion;
private Long auditorUserId;
private String auditorName;
}

View File

@@ -0,0 +1,40 @@
package com.njcn.rdms.module.project.dal.dataobject.workreport.common;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 个人周报/月报计划项。
*/
@TableName(value = "rdms_work_report_personal_report_plan_item", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
public class PersonalReportPlanItemDO extends BaseDO {
@TableId
private Long id;
private String reportType;
private Long reportId;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private Integer itemNumber;
private String itemTitle;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String targetText;
@TableField(typeHandler = JacksonTypeHandler.class, updateStrategy = FieldStrategy.ALWAYS)
private Object targetJson;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String supportNeed;
}

View File

@@ -0,0 +1,45 @@
package com.njcn.rdms.module.project.dal.dataobject.workreport.common;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
/**
* 个人周报/月报回顾项。
*/
@TableName(value = "rdms_work_report_personal_report_review_item", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
public class PersonalReportReviewItemDO extends BaseDO {
@TableId
private Long id;
private String reportType;
private Long reportId;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private Integer itemNumber;
private String itemTitle;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private BigDecimal workHours;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String contentText;
@TableField(typeHandler = JacksonTypeHandler.class, updateStrategy = FieldStrategy.ALWAYS)
private Object contentJson;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String reflectionText;
}

View File

@@ -0,0 +1,14 @@
package com.njcn.rdms.module.project.dal.dataobject.workreport.common;
import lombok.Data;
/**
* 项目半月报中的项目成员快照。
*/
@Data
public class WorkReportMemberSnapshotItem {
private Long userId;
private String userName;
}

View File

@@ -0,0 +1,44 @@
package com.njcn.rdms.module.project.dal.dataobject.workreport.common;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 工作报告状态日志。
*/
@TableName("rdms_work_report_status_log")
@Data
@EqualsAndHashCode(callSuper = true)
public class WorkReportStatusLogDO extends BaseDO {
@TableId
private Long id;
private String reportType;
private Long reportId;
private String actionType;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String fromStatus;
private String toStatus;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String reason;
private Long operatorUserId;
private String operatorName;
private String periodLabelSnapshot;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String remark;
}

View File

@@ -0,0 +1,71 @@
package com.njcn.rdms.module.project.dal.dataobject.workreport.monthly;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDate;
/**
* 月报审核记录。
*/
@TableName("rdms_work_report_monthly_report_approval_record")
@Data
@EqualsAndHashCode(callSuper = true)
public class MonthlyReportApprovalRecordDO extends BaseDO {
@TableId
private Long id;
private Long monthlyReportId;
private Long statusLogId;
private Integer approvalRound;
private String conclusion;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String opinion;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private LocalDate meetingDate;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String strengthDesc;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String strengthExample;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String weaknessDesc;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String weaknessExample;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String improvementSuggestion;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String performanceResult;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String employeeSignName;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private LocalDate employeeSignedDate;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String supervisorSignName;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private LocalDate supervisorSignedDate;
private Long auditorUserId;
private String auditorName;
}

View File

@@ -0,0 +1,64 @@
package com.njcn.rdms.module.project.dal.dataobject.workreport.monthly;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* 工作报告-月报主表。
*/
@TableName("rdms_work_report_monthly_report")
@Data
@EqualsAndHashCode(callSuper = true)
public class MonthlyReportDO extends BaseDO {
@TableId
private Long id;
private Long reporterId;
private String reporterName;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String reporterDeptName;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String reporterPostName;
private Long supervisorUserId;
private String supervisorName;
private String periodKey;
private String periodLabel;
private LocalDate periodStartDate;
private LocalDate periodEndDate;
private String statusCode;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private BigDecimal totalWorkHours;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private LocalDateTime submitTime;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private LocalDateTime approvalTime;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String approvalComment;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String lastStatusReason;
}

View File

@@ -0,0 +1,36 @@
package com.njcn.rdms.module.project.dal.dataobject.workreport.project;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 项目半月报审核记录。
*/
@TableName("rdms_work_report_project_report_approval_record")
@Data
@EqualsAndHashCode(callSuper = true)
public class ProjectReportApprovalRecordDO extends BaseDO {
@TableId
private Long id;
private Long projectReportId;
private Long statusLogId;
private Integer approvalRound;
private String conclusion;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String opinion;
private Long auditorUserId;
private String auditorName;
}

View File

@@ -0,0 +1,36 @@
package com.njcn.rdms.module.project.dal.dataobject.workreport.project;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
/**
* 项目半月报本期工作项。
*/
@TableName("rdms_work_report_project_report_current_item")
@Data
@EqualsAndHashCode(callSuper = true)
public class ProjectReportCurrentItemDO extends BaseDO {
@TableId
private Long id;
private Long reportId;
private String itemTitle;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private BigDecimal workHours;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String priorityCode;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private BigDecimal progressRate;
}

View File

@@ -0,0 +1,85 @@
package com.njcn.rdms.module.project.dal.dataobject.workreport.project;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import com.njcn.rdms.module.project.dal.dataobject.workreport.common.WorkReportMemberSnapshotItem;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
/**
* 工作报告-项目半月报主表。
*/
@TableName(value = "rdms_work_report_project_report", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
public class ProjectReportDO extends BaseDO {
@TableId
private Long id;
private Long projectId;
private String projectName;
private Long projectOwnerId;
private String projectOwnerName;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String technicalOwnerName;
@TableField(typeHandler = JacksonTypeHandler.class, updateStrategy = FieldStrategy.ALWAYS)
private List<WorkReportMemberSnapshotItem> projectMemberSnapshot;
private Long supervisorUserId;
private String supervisorName;
private String periodKey;
private String periodLabel;
private LocalDate periodStartDate;
private LocalDate periodEndDate;
private Integer flag;
private String statusCode;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String projectStatusDesc;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String projectProgressPlan;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String projectKeyPoints;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String projectProblems;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private BigDecimal totalWorkHours;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private LocalDateTime submitTime;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private LocalDateTime approvalTime;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String approvalComment;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String lastStatusReason;
}

View File

@@ -0,0 +1,33 @@
package com.njcn.rdms.module.project.dal.dataobject.workreport.project;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
/**
* 项目半月报下期工作项。
*/
@TableName("rdms_work_report_project_report_next_item")
@Data
@EqualsAndHashCode(callSuper = true)
public class ProjectReportNextItemDO extends BaseDO {
@TableId
private Long id;
private Long reportId;
private String itemTitle;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String priorityCode;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private BigDecimal progressRate;
}

View File

@@ -0,0 +1,36 @@
package com.njcn.rdms.module.project.dal.dataobject.workreport.weekly;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 周报审核记录。
*/
@TableName("rdms_work_report_weekly_report_approval_record")
@Data
@EqualsAndHashCode(callSuper = true)
public class WeeklyReportApprovalRecordDO extends BaseDO {
@TableId
private Long id;
private Long weeklyReportId;
private Long statusLogId;
private Integer approvalRound;
private String conclusion;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String opinion;
private Long auditorUserId;
private String auditorName;
}

View File

@@ -0,0 +1,69 @@
package com.njcn.rdms.module.project.dal.dataobject.workreport.weekly;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* 工作报告-周报主表。
*/
@TableName("rdms_work_report_weekly_report")
@Data
@EqualsAndHashCode(callSuper = true)
public class WeeklyReportDO extends BaseDO {
@TableId
private Long id;
private Long reporterId;
private String reporterName;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String reporterDeptName;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String reporterPostName;
private Long supervisorUserId;
private String supervisorName;
private String periodKey;
private String periodLabel;
private LocalDate periodStartDate;
private LocalDate periodEndDate;
private String statusCode;
private Boolean isBusinessTrip;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private BigDecimal totalTravelDays;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private BigDecimal totalWorkHours;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private LocalDateTime submitTime;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private LocalDateTime approvalTime;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String approvalComment;
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String lastStatusReason;
}

View File

@@ -0,0 +1,36 @@
package com.njcn.rdms.module.project.dal.dataobject.workreport.weekly;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* 周报出差分段。
*/
@TableName("rdms_work_report_weekly_report_travel_segment")
@Data
@EqualsAndHashCode(callSuper = true)
public class WeeklyReportTravelSegmentDO extends BaseDO {
@TableId
private Long id;
private Long weeklyReportId;
@TableField("sort")
private Integer sort;
private LocalDate startDate;
private LocalDate endDate;
private BigDecimal travelDays;
private String location;
}

View File

@@ -0,0 +1,24 @@
package com.njcn.rdms.module.project.dal.mysql.overtime;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.project.dal.dataobject.overtime.OvertimeApplicationApprovalRecordDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface OvertimeApplicationApprovalRecordMapper extends BaseMapperX<OvertimeApplicationApprovalRecordDO> {
default List<OvertimeApplicationApprovalRecordDO> selectListByApplicationId(Long applicationId) {
return selectList(new LambdaQueryWrapperX<OvertimeApplicationApprovalRecordDO>()
.eq(OvertimeApplicationApprovalRecordDO::getOvertimeApplicationId, applicationId)
.orderByDesc(OvertimeApplicationApprovalRecordDO::getApprovalRound)
.orderByDesc(OvertimeApplicationApprovalRecordDO::getId));
}
default int countByApplicationId(Long applicationId) {
return Math.toIntExact(selectCount(new LambdaQueryWrapperX<OvertimeApplicationApprovalRecordDO>()
.eq(OvertimeApplicationApprovalRecordDO::getOvertimeApplicationId, applicationId)));
}
}

View File

@@ -9,6 +9,9 @@ import com.njcn.rdms.module.project.dal.dataobject.personal.PersonalItemDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.time.LocalDate;
import java.util.List;
@Mapper @Mapper
public interface PersonalItemMapper extends BaseMapperX<PersonalItemDO> { public interface PersonalItemMapper extends BaseMapperX<PersonalItemDO> {
@@ -45,4 +48,33 @@ public interface PersonalItemMapper extends BaseMapperX<PersonalItemDO> {
.eq(PersonalItemDO::getId, id) .eq(PersonalItemDO::getId, id)
.eq(PersonalItemDO::getStatusCode, fromStatus)); .eq(PersonalItemDO::getStatusCode, fromStatus));
} }
default List<PersonalItemDO> selectPlannedListByOwnerIdAndOverlap(Long ownerId, LocalDate startDate, LocalDate endDate,
String excludedStatusCode) {
LambdaQueryWrapperX<PersonalItemDO> queryWrapper = new LambdaQueryWrapperX<PersonalItemDO>()
.eq(PersonalItemDO::getOwnerId, ownerId);
if (StringUtils.hasText(excludedStatusCode)) {
queryWrapper.ne(PersonalItemDO::getStatusCode, excludedStatusCode);
}
queryWrapper.isNotNull(PersonalItemDO::getPlannedStartDate);
queryWrapper.isNotNull(PersonalItemDO::getPlannedEndDate);
queryWrapper.le(PersonalItemDO::getPlannedStartDate, endDate);
queryWrapper.ge(PersonalItemDO::getPlannedEndDate, startDate);
queryWrapper.orderByAsc(PersonalItemDO::getPlannedStartDate);
queryWrapper.orderByAsc(PersonalItemDO::getId);
return selectList(queryWrapper);
}
default List<PersonalItemDO> selectListByOwnerIdAndStatusNot(Long ownerId, String excludedStatusCode) {
if (ownerId == null) {
return List.of();
}
LambdaQueryWrapperX<PersonalItemDO> queryWrapper = new LambdaQueryWrapperX<PersonalItemDO>()
.eq(PersonalItemDO::getOwnerId, ownerId);
if (StringUtils.hasText(excludedStatusCode)) {
queryWrapper.ne(PersonalItemDO::getStatusCode, excludedStatusCode);
}
queryWrapper.orderByAsc(PersonalItemDO::getId);
return selectList(queryWrapper);
}
} }

View File

@@ -58,6 +58,12 @@ public interface ProjectMapper extends BaseMapperX<ProjectDO> {
.orderByDesc(BaseDO::getCreateTime)); .orderByDesc(BaseDO::getCreateTime));
} }
default List<ProjectDO> selectListByManagerUserId(Long managerUserId) {
return selectList(new LambdaQueryWrapperX<ProjectDO>()
.eq(ProjectDO::getManagerUserId, managerUserId)
.orderByDesc(BaseDO::getCreateTime));
}
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);

View File

@@ -12,6 +12,7 @@ import com.njcn.rdms.module.project.dal.dataobject.project.execution.ProjectExec
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Select;
import org.springframework.util.StringUtils;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.Collection; import java.util.Collection;
@@ -143,18 +144,6 @@ public interface ProjectExecutionMapper extends BaseMapperX<ProjectExecutionDO>
return Math.toIntExact(selectCount(queryWrapper)); return Math.toIntExact(selectCount(queryWrapper));
} }
/**
* 统计指定项目下处于非终态的执行数。用于项目 complete 前置校验TD-015
*/
default Integer countNonTerminalByProjectId(Long projectId, List<String> terminalStatusCodes) {
LambdaQueryWrapperX<ProjectExecutionDO> queryWrapper = new LambdaQueryWrapperX<ProjectExecutionDO>()
.eq(ProjectExecutionDO::getProjectId, projectId);
if (terminalStatusCodes != null && !terminalStatusCodes.isEmpty()) {
queryWrapper.notIn(ProjectExecutionDO::getStatusCode, terminalStatusCodes);
}
return Math.toIntExact(selectCount(queryWrapper));
}
default Integer countByProjectIdAndStatusCode(Long projectId, default Integer countByProjectIdAndStatusCode(Long projectId,
ProjectExecutionStatusBoardReqVO reqVO, ProjectExecutionStatusBoardReqVO reqVO,
String statusCode, String statusCode,
@@ -312,4 +301,45 @@ public interface ProjectExecutionMapper extends BaseMapperX<ProjectExecutionDO>
@Param("projectIds") Collection<Long> projectIds, @Param("projectIds") Collection<Long> projectIds,
@Param("terminalStatusCodes") Collection<String> terminalStatusCodes); @Param("terminalStatusCodes") Collection<String> terminalStatusCodes);
default List<ProjectExecutionDO> selectListByProjectId(Long projectId) {
if (projectId == null) {
return java.util.Collections.emptyList();
}
return selectList(new LambdaQueryWrapperX<ProjectExecutionDO>()
.eq(ProjectExecutionDO::getProjectId, projectId)
.orderByAsc(ProjectExecutionDO::getId));
}
default List<ProjectExecutionDO> selectPlannedListByProjectIdAndOverlap(Long projectId, LocalDate startDate,
LocalDate endDate, String excludedStatusCode) {
if (projectId == null || startDate == null || endDate == null) {
return java.util.Collections.emptyList();
}
LambdaQueryWrapperX<ProjectExecutionDO> queryWrapper = new LambdaQueryWrapperX<ProjectExecutionDO>()
.eq(ProjectExecutionDO::getProjectId, projectId);
if (StringUtils.hasText(excludedStatusCode)) {
queryWrapper.ne(ProjectExecutionDO::getStatusCode, excludedStatusCode);
}
queryWrapper.isNotNull(ProjectExecutionDO::getPlannedStartDate);
queryWrapper.isNotNull(ProjectExecutionDO::getPlannedEndDate);
queryWrapper.le(ProjectExecutionDO::getPlannedStartDate, endDate);
queryWrapper.ge(ProjectExecutionDO::getPlannedEndDate, startDate);
queryWrapper.orderByAsc(ProjectExecutionDO::getPlannedStartDate);
queryWrapper.orderByAsc(ProjectExecutionDO::getId);
return selectList(queryWrapper);
}
default List<ProjectExecutionDO> selectListByProjectIdAndStatusNot(Long projectId, String excludedStatusCode) {
if (projectId == null) {
return java.util.Collections.emptyList();
}
LambdaQueryWrapperX<ProjectExecutionDO> queryWrapper = new LambdaQueryWrapperX<ProjectExecutionDO>()
.eq(ProjectExecutionDO::getProjectId, projectId);
if (StringUtils.hasText(excludedStatusCode)) {
queryWrapper.ne(ProjectExecutionDO::getStatusCode, excludedStatusCode);
}
queryWrapper.orderByAsc(ProjectExecutionDO::getId);
return selectList(queryWrapper);
}
} }

View File

@@ -791,4 +791,72 @@ public interface ProjectTaskMapper extends BaseMapperX<ProjectTaskDO> {
@Param("projectIds") Collection<Long> projectIds, @Param("projectIds") Collection<Long> projectIds,
@Param("terminalStatusCodes") Collection<String> terminalStatusCodes); @Param("terminalStatusCodes") Collection<String> terminalStatusCodes);
default List<ProjectTaskDO> selectListByProjectId(Long projectId) {
if (projectId == null) {
return List.of();
}
return selectList(new LambdaQueryWrapperX<ProjectTaskDO>()
.eq(ProjectTaskDO::getProjectId, projectId)
.orderByAsc(ProjectTaskDO::getExecutionId)
.orderByAsc(ProjectTaskDO::getId));
}
@Select("""
<script>
SELECT t.*
FROM rdms_task t
<where>
t.deleted = b'0'
AND (
t.owner_id = #{userId}
OR EXISTS (
SELECT 1 FROM rdms_task_assignee a
WHERE a.task_id = t.id
AND a.user_id = #{userId}
AND a.removed_at IS NULL
AND a.deleted = b'0'
)
)
AND t.planned_start_date IS NOT NULL
AND t.planned_end_date IS NOT NULL
AND t.planned_start_date &lt;= #{endDate}
AND t.planned_end_date &gt;= #{startDate}
<if test="excludedStatusCode != null and excludedStatusCode != ''">
AND t.status_code != #{excludedStatusCode}
</if>
</where>
ORDER BY t.project_id ASC, t.execution_id ASC, t.priority ASC, t.id ASC
</script>
""")
List<ProjectTaskDO> selectPlannedInvolvedListByUserIdAndOverlap(@Param("userId") Long userId,
@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate,
@Param("excludedStatusCode") String excludedStatusCode);
@Select("""
<script>
SELECT t.*
FROM rdms_task t
<where>
t.deleted = b'0'
AND (
t.owner_id = #{userId}
OR EXISTS (
SELECT 1 FROM rdms_task_assignee a
WHERE a.task_id = t.id
AND a.user_id = #{userId}
AND a.removed_at IS NULL
AND a.deleted = b'0'
)
)
<if test="excludedStatusCode != null and excludedStatusCode != ''">
AND t.status_code != #{excludedStatusCode}
</if>
</where>
ORDER BY t.project_id ASC, t.execution_id ASC, t.priority ASC, t.id ASC
</script>
""")
List<ProjectTaskDO> selectInvolvedListByUserIdAndStatusNot(@Param("userId") Long userId,
@Param("excludedStatusCode") String excludedStatusCode);
} }

View File

@@ -188,4 +188,30 @@ public interface TaskWorklogMapper extends BaseMapperX<TaskWorklogDO> {
.eq(TaskWorklogDO::getTaskId, taskId))); .eq(TaskWorklogDO::getTaskId, taskId)));
} }
default List<TaskWorklogDO> selectListByUserIdAndPeriod(Long userId, LocalDate startDate, LocalDate endDate) {
if (userId == null || startDate == null || endDate == null) {
return List.of();
}
return selectList(new LambdaQueryWrapperX<TaskWorklogDO>()
.eq(TaskWorklogDO::getUserId, userId)
.le(TaskWorklogDO::getStartDate, endDate)
.ge(TaskWorklogDO::getEndDate, startDate)
.orderByAsc(TaskWorklogDO::getTaskId)
.orderByAsc(TaskWorklogDO::getEndDate)
.orderByAsc(TaskWorklogDO::getId));
}
default List<TaskWorklogDO> selectListByTaskIdsAndPeriod(Collection<Long> taskIds, LocalDate startDate, LocalDate endDate) {
if (taskIds == null || taskIds.isEmpty() || startDate == null || endDate == null) {
return List.of();
}
return selectList(new LambdaQueryWrapperX<TaskWorklogDO>()
.in(TaskWorklogDO::getTaskId, taskIds)
.le(TaskWorklogDO::getStartDate, endDate)
.ge(TaskWorklogDO::getEndDate, startDate)
.orderByAsc(TaskWorklogDO::getTaskId)
.orderByAsc(TaskWorklogDO::getEndDate)
.orderByAsc(TaskWorklogDO::getId));
}
} }

View File

@@ -0,0 +1,26 @@
package com.njcn.rdms.module.project.dal.mysql.workreport.common;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.project.dal.dataobject.workreport.common.PersonalReportPlanItemDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface PersonalReportPlanItemMapper extends BaseMapperX<PersonalReportPlanItemDO> {
default List<PersonalReportPlanItemDO> selectListByReport(String reportType, Long reportId) {
return selectList(new LambdaQueryWrapperX<PersonalReportPlanItemDO>()
.eq(PersonalReportPlanItemDO::getReportType, reportType)
.eq(PersonalReportPlanItemDO::getReportId, reportId)
.orderByAsc(PersonalReportPlanItemDO::getItemNumber)
.orderByAsc(PersonalReportPlanItemDO::getId));
}
default int deleteByReport(String reportType, Long reportId) {
return delete(new LambdaQueryWrapperX<PersonalReportPlanItemDO>()
.eq(PersonalReportPlanItemDO::getReportType, reportType)
.eq(PersonalReportPlanItemDO::getReportId, reportId));
}
}

View File

@@ -0,0 +1,26 @@
package com.njcn.rdms.module.project.dal.mysql.workreport.common;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.project.dal.dataobject.workreport.common.PersonalReportReviewItemDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface PersonalReportReviewItemMapper extends BaseMapperX<PersonalReportReviewItemDO> {
default List<PersonalReportReviewItemDO> selectListByReport(String reportType, Long reportId) {
return selectList(new LambdaQueryWrapperX<PersonalReportReviewItemDO>()
.eq(PersonalReportReviewItemDO::getReportType, reportType)
.eq(PersonalReportReviewItemDO::getReportId, reportId)
.orderByAsc(PersonalReportReviewItemDO::getItemNumber)
.orderByAsc(PersonalReportReviewItemDO::getId));
}
default int deleteByReport(String reportType, Long reportId) {
return delete(new LambdaQueryWrapperX<PersonalReportReviewItemDO>()
.eq(PersonalReportReviewItemDO::getReportType, reportType)
.eq(PersonalReportReviewItemDO::getReportId, reportId));
}
}

View File

@@ -0,0 +1,26 @@
package com.njcn.rdms.module.project.dal.mysql.workreport.common;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.project.dal.dataobject.workreport.common.WorkReportStatusLogDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface WorkReportStatusLogMapper extends BaseMapperX<WorkReportStatusLogDO> {
default List<WorkReportStatusLogDO> selectListByReport(String reportType, Long reportId) {
return selectList(new LambdaQueryWrapperX<WorkReportStatusLogDO>()
.eq(WorkReportStatusLogDO::getReportType, reportType)
.eq(WorkReportStatusLogDO::getReportId, reportId)
.orderByDesc(WorkReportStatusLogDO::getCreateTime)
.orderByDesc(WorkReportStatusLogDO::getId));
}
default int deleteByReport(String reportType, Long reportId) {
return delete(new LambdaQueryWrapperX<WorkReportStatusLogDO>()
.eq(WorkReportStatusLogDO::getReportType, reportType)
.eq(WorkReportStatusLogDO::getReportId, reportId));
}
}

View File

@@ -0,0 +1,29 @@
package com.njcn.rdms.module.project.dal.mysql.workreport.monthly;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportApprovalRecordDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface MonthlyReportApprovalRecordMapper extends BaseMapperX<MonthlyReportApprovalRecordDO> {
default List<MonthlyReportApprovalRecordDO> selectListByMonthlyReportId(Long monthlyReportId) {
return selectList(new LambdaQueryWrapperX<MonthlyReportApprovalRecordDO>()
.eq(MonthlyReportApprovalRecordDO::getMonthlyReportId, monthlyReportId)
.orderByDesc(MonthlyReportApprovalRecordDO::getApprovalRound)
.orderByDesc(MonthlyReportApprovalRecordDO::getId));
}
default int countByMonthlyReportId(Long monthlyReportId) {
return Math.toIntExact(selectCount(new LambdaQueryWrapperX<MonthlyReportApprovalRecordDO>()
.eq(MonthlyReportApprovalRecordDO::getMonthlyReportId, monthlyReportId)));
}
default int deleteByMonthlyReportId(Long monthlyReportId) {
return delete(new LambdaQueryWrapperX<MonthlyReportApprovalRecordDO>()
.eq(MonthlyReportApprovalRecordDO::getMonthlyReportId, monthlyReportId));
}
}

View File

@@ -0,0 +1,123 @@
package com.njcn.rdms.module.project.dal.mysql.workreport.monthly;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.project.constant.WorkReportConstants;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportPageReqVO;
import com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportDO;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
@Mapper
public interface MonthlyReportMapper extends BaseMapperX<MonthlyReportDO> {
default MonthlyReportDO selectByReporterIdAndPeriodKey(Long reporterId, String periodKey) {
return selectOne(new LambdaQueryWrapperX<MonthlyReportDO>()
.eq(MonthlyReportDO::getReporterId, reporterId)
.eq(MonthlyReportDO::getPeriodKey, periodKey));
}
default PageResult<MonthlyReportDO> selectReporterPage(Long reporterId, MonthlyReportPageReqVO reqVO) {
return selectReporterPage(reporterId, reqVO, null);
}
default PageResult<MonthlyReportDO> selectReporterPage(Long reporterId, MonthlyReportPageReqVO reqVO,
Collection<String> allowedStatusCodes) {
if (allowedStatusCodes != null && allowedStatusCodes.isEmpty()) {
return new PageResult<>(List.of(), 0L);
}
LambdaQueryWrapperX<MonthlyReportDO> wrapper = buildPageQuery(reqVO)
.eq(MonthlyReportDO::getReporterId, reporterId)
.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) {
LambdaQueryWrapperX<MonthlyReportDO> wrapper = buildPageQuery(reqVO)
.eq(MonthlyReportDO::getSupervisorUserId, supervisorUserId)
.eq(MonthlyReportDO::getStatusCode, WorkReportConstants.STATUS_PENDING_APPROVAL)
.orderByDesc(MonthlyReportDO::getSubmitTime)
.orderByDesc(MonthlyReportDO::getId);
return selectPage(reqVO, wrapper);
}
default int updateByIdAndStatus(MonthlyReportDO update, Long id, String fromStatus) {
return update(update, new LambdaQueryWrapperX<MonthlyReportDO>()
.eq(MonthlyReportDO::getId, id)
.eq(MonthlyReportDO::getStatusCode, fromStatus));
}
default int updateSubmitFieldsByIdAndStatus(Long id, String fromStatus, String reporterDeptName,
String reporterPostName, Long supervisorUserId,
String supervisorName, String toStatus, LocalDateTime submitTime,
String updater) {
return update(null, new LambdaUpdateWrapper<MonthlyReportDO>()
.set(MonthlyReportDO::getReporterDeptName, reporterDeptName)
.set(MonthlyReportDO::getReporterPostName, reporterPostName)
.set(MonthlyReportDO::getSupervisorUserId, supervisorUserId)
.set(MonthlyReportDO::getSupervisorName, supervisorName)
.set(MonthlyReportDO::getStatusCode, toStatus)
.set(MonthlyReportDO::getSubmitTime, submitTime)
.set(MonthlyReportDO::getApprovalTime, null)
.set(MonthlyReportDO::getApprovalComment, null)
.set(MonthlyReportDO::getLastStatusReason, null)
.set(MonthlyReportDO::getUpdateTime, submitTime)
.set(MonthlyReportDO::getUpdater, updater)
.eq(MonthlyReportDO::getId, id)
.eq(MonthlyReportDO::getStatusCode, fromStatus));
}
default int updateApprovalFieldsByIdAndStatus(Long id, String fromStatus, String toStatus,
LocalDateTime approvalTime, String approvalComment,
String lastStatusReason, String updater) {
return update(null, new LambdaUpdateWrapper<MonthlyReportDO>()
.set(MonthlyReportDO::getStatusCode, toStatus)
.set(MonthlyReportDO::getApprovalTime, approvalTime)
.set(MonthlyReportDO::getApprovalComment, approvalComment)
.set(MonthlyReportDO::getLastStatusReason, lastStatusReason)
.set(MonthlyReportDO::getUpdateTime, approvalTime)
.set(MonthlyReportDO::getUpdater, updater)
.eq(MonthlyReportDO::getId, id)
.eq(MonthlyReportDO::getStatusCode, fromStatus));
}
default int updateByIdAndStatusesAndReporterId(MonthlyReportDO update, Long id, Collection<String> statuses,
Long reporterId) {
return update(update, new LambdaQueryWrapperX<MonthlyReportDO>()
.eq(MonthlyReportDO::getId, id)
.eq(MonthlyReportDO::getReporterId, reporterId)
.in(MonthlyReportDO::getStatusCode, statuses));
}
default int deleteByIdAndStatusesAndReporterId(Long id, Collection<String> statuses, Long reporterId) {
return delete(new LambdaQueryWrapperX<MonthlyReportDO>()
.eq(MonthlyReportDO::getId, id)
.eq(MonthlyReportDO::getReporterId, reporterId)
.in(MonthlyReportDO::getStatusCode, statuses));
}
private LambdaQueryWrapperX<MonthlyReportDO> buildPageQuery(MonthlyReportPageReqVO reqVO) {
LambdaQueryWrapperX<MonthlyReportDO> wrapper = new LambdaQueryWrapperX<MonthlyReportDO>()
.eqIfPresent(MonthlyReportDO::getStatusCode, reqVO.getStatusCode())
.betweenIfPresent(MonthlyReportDO::getPeriodStartDate, reqVO.getPeriodStartDate())
.betweenIfPresent(MonthlyReportDO::getSubmitTime, reqVO.getSubmitTime());
if (StringUtils.hasText(reqVO.getKeyword())) {
wrapper.and(w -> w.like(MonthlyReportDO::getPeriodLabel, reqVO.getKeyword())
.or()
.like(MonthlyReportDO::getReporterName, reqVO.getKeyword())
.or()
.like(MonthlyReportDO::getSupervisorName, reqVO.getKeyword()));
}
return wrapper;
}
}

View File

@@ -0,0 +1,29 @@
package com.njcn.rdms.module.project.dal.mysql.workreport.project;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.project.dal.dataobject.workreport.project.ProjectReportApprovalRecordDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface ProjectReportApprovalRecordMapper extends BaseMapperX<ProjectReportApprovalRecordDO> {
default List<ProjectReportApprovalRecordDO> selectListByProjectReportId(Long projectReportId) {
return selectList(new LambdaQueryWrapperX<ProjectReportApprovalRecordDO>()
.eq(ProjectReportApprovalRecordDO::getProjectReportId, projectReportId)
.orderByDesc(ProjectReportApprovalRecordDO::getApprovalRound)
.orderByDesc(ProjectReportApprovalRecordDO::getId));
}
default int countByProjectReportId(Long projectReportId) {
return Math.toIntExact(selectCount(new LambdaQueryWrapperX<ProjectReportApprovalRecordDO>()
.eq(ProjectReportApprovalRecordDO::getProjectReportId, projectReportId)));
}
default int deleteByProjectReportId(Long projectReportId) {
return delete(new LambdaQueryWrapperX<ProjectReportApprovalRecordDO>()
.eq(ProjectReportApprovalRecordDO::getProjectReportId, projectReportId));
}
}

View File

@@ -0,0 +1,23 @@
package com.njcn.rdms.module.project.dal.mysql.workreport.project;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.project.dal.dataobject.workreport.project.ProjectReportCurrentItemDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface ProjectReportCurrentItemMapper extends BaseMapperX<ProjectReportCurrentItemDO> {
default List<ProjectReportCurrentItemDO> selectListByReportId(Long reportId) {
return selectList(new LambdaQueryWrapperX<ProjectReportCurrentItemDO>()
.eq(ProjectReportCurrentItemDO::getReportId, reportId)
.orderByAsc(ProjectReportCurrentItemDO::getId));
}
default int deleteByReportId(Long reportId) {
return delete(new LambdaQueryWrapperX<ProjectReportCurrentItemDO>()
.eq(ProjectReportCurrentItemDO::getReportId, reportId));
}
}

View File

@@ -0,0 +1,136 @@
package com.njcn.rdms.module.project.dal.mysql.workreport.project;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.project.constant.WorkReportConstants;
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportPageReqVO;
import com.njcn.rdms.module.project.dal.dataobject.workreport.common.WorkReportMemberSnapshotItem;
import com.njcn.rdms.module.project.dal.dataobject.workreport.project.ProjectReportDO;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
@Mapper
public interface ProjectReportMapper extends BaseMapperX<ProjectReportDO> {
String JACKSON_TYPE_HANDLER_MAPPING = "typeHandler=" + JacksonTypeHandler.class.getCanonicalName();
default ProjectReportDO selectByProjectIdAndPeriodKeyAndProjectOwnerId(Long projectId, String periodKey,
Long projectOwnerId) {
return selectOne(new LambdaQueryWrapperX<ProjectReportDO>()
.eq(ProjectReportDO::getProjectId, projectId)
.eq(ProjectReportDO::getPeriodKey, periodKey)
.eq(ProjectReportDO::getProjectOwnerId, projectOwnerId));
}
default PageResult<ProjectReportDO> selectReporterPage(Long reporterId, ProjectReportPageReqVO reqVO) {
return selectReporterPage(reporterId, reqVO, null);
}
default PageResult<ProjectReportDO> selectReporterPage(Long reporterId, ProjectReportPageReqVO reqVO,
Collection<String> allowedStatusCodes) {
if (allowedStatusCodes != null && allowedStatusCodes.isEmpty()) {
return new PageResult<>(List.of(), 0L);
}
LambdaQueryWrapperX<ProjectReportDO> wrapper = buildPageQuery(reqVO)
.eq(ProjectReportDO::getProjectOwnerId, reporterId)
.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) {
LambdaQueryWrapperX<ProjectReportDO> wrapper = buildPageQuery(reqVO)
.eq(ProjectReportDO::getSupervisorUserId, supervisorUserId)
.eq(ProjectReportDO::getStatusCode, WorkReportConstants.STATUS_PENDING_APPROVAL)
.orderByDesc(ProjectReportDO::getSubmitTime)
.orderByDesc(ProjectReportDO::getId);
return selectPage(reqVO, wrapper);
}
default int updateByIdAndStatus(ProjectReportDO update, Long id, String fromStatus) {
return update(update, new LambdaQueryWrapperX<ProjectReportDO>()
.eq(ProjectReportDO::getId, id)
.eq(ProjectReportDO::getStatusCode, fromStatus));
}
default int updateSubmitFieldsByIdAndStatus(Long id, String fromStatus, String projectName,
Long projectOwnerId, String projectOwnerName,
List<WorkReportMemberSnapshotItem> projectMemberSnapshot,
Long supervisorUserId, String supervisorName, String toStatus,
LocalDateTime submitTime, String updater) {
return update(null, new LambdaUpdateWrapper<ProjectReportDO>()
.set(ProjectReportDO::getProjectName, projectName)
.set(ProjectReportDO::getProjectOwnerId, projectOwnerId)
.set(ProjectReportDO::getProjectOwnerName, projectOwnerName)
.set(ProjectReportDO::getProjectMemberSnapshot, projectMemberSnapshot, JACKSON_TYPE_HANDLER_MAPPING)
.set(ProjectReportDO::getSupervisorUserId, supervisorUserId)
.set(ProjectReportDO::getSupervisorName, supervisorName)
.set(ProjectReportDO::getStatusCode, toStatus)
.set(ProjectReportDO::getSubmitTime, submitTime)
.set(ProjectReportDO::getApprovalTime, null)
.set(ProjectReportDO::getApprovalComment, null)
.set(ProjectReportDO::getLastStatusReason, null)
.set(ProjectReportDO::getUpdateTime, submitTime)
.set(ProjectReportDO::getUpdater, updater)
.eq(ProjectReportDO::getId, id)
.eq(ProjectReportDO::getStatusCode, fromStatus));
}
default int updateApprovalFieldsByIdAndStatus(Long id, String fromStatus, String toStatus,
LocalDateTime approvalTime, String approvalComment,
String lastStatusReason, String updater) {
return update(null, new LambdaUpdateWrapper<ProjectReportDO>()
.set(ProjectReportDO::getStatusCode, toStatus)
.set(ProjectReportDO::getApprovalTime, approvalTime)
.set(ProjectReportDO::getApprovalComment, approvalComment)
.set(ProjectReportDO::getLastStatusReason, lastStatusReason)
.set(ProjectReportDO::getUpdateTime, approvalTime)
.set(ProjectReportDO::getUpdater, updater)
.eq(ProjectReportDO::getId, id)
.eq(ProjectReportDO::getStatusCode, fromStatus));
}
default int updateByIdAndStatusesAndReporterId(ProjectReportDO update, Long id, Collection<String> statuses,
Long reporterId) {
return update(update, new LambdaQueryWrapperX<ProjectReportDO>()
.eq(ProjectReportDO::getId, id)
.eq(ProjectReportDO::getProjectOwnerId, reporterId)
.in(ProjectReportDO::getStatusCode, statuses));
}
default int deleteByIdAndStatusesAndReporterId(Long id, Collection<String> statuses, Long reporterId) {
return delete(new LambdaQueryWrapperX<ProjectReportDO>()
.eq(ProjectReportDO::getId, id)
.eq(ProjectReportDO::getProjectOwnerId, reporterId)
.in(ProjectReportDO::getStatusCode, statuses));
}
private LambdaQueryWrapperX<ProjectReportDO> buildPageQuery(ProjectReportPageReqVO reqVO) {
LambdaQueryWrapperX<ProjectReportDO> wrapper = new LambdaQueryWrapperX<ProjectReportDO>()
.eqIfPresent(ProjectReportDO::getProjectId, reqVO.getProjectId())
.eqIfPresent(ProjectReportDO::getFlag, reqVO.getFlag())
.eqIfPresent(ProjectReportDO::getStatusCode, reqVO.getStatusCode())
.betweenIfPresent(ProjectReportDO::getPeriodStartDate, reqVO.getPeriodStartDate())
.betweenIfPresent(ProjectReportDO::getSubmitTime, reqVO.getSubmitTime());
if (StringUtils.hasText(reqVO.getKeyword())) {
wrapper.and(w -> w.like(ProjectReportDO::getProjectName, reqVO.getKeyword())
.or()
.like(ProjectReportDO::getPeriodLabel, reqVO.getKeyword())
.or()
.like(ProjectReportDO::getProjectOwnerName, reqVO.getKeyword())
.or()
.like(ProjectReportDO::getSupervisorName, reqVO.getKeyword()));
}
return wrapper;
}
}

View File

@@ -0,0 +1,23 @@
package com.njcn.rdms.module.project.dal.mysql.workreport.project;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.project.dal.dataobject.workreport.project.ProjectReportNextItemDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface ProjectReportNextItemMapper extends BaseMapperX<ProjectReportNextItemDO> {
default List<ProjectReportNextItemDO> selectListByReportId(Long reportId) {
return selectList(new LambdaQueryWrapperX<ProjectReportNextItemDO>()
.eq(ProjectReportNextItemDO::getReportId, reportId)
.orderByAsc(ProjectReportNextItemDO::getId));
}
default int deleteByReportId(Long reportId) {
return delete(new LambdaQueryWrapperX<ProjectReportNextItemDO>()
.eq(ProjectReportNextItemDO::getReportId, reportId));
}
}

View File

@@ -0,0 +1,29 @@
package com.njcn.rdms.module.project.dal.mysql.workreport.weekly;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.project.dal.dataobject.workreport.weekly.WeeklyReportApprovalRecordDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface WeeklyReportApprovalRecordMapper extends BaseMapperX<WeeklyReportApprovalRecordDO> {
default List<WeeklyReportApprovalRecordDO> selectListByWeeklyReportId(Long weeklyReportId) {
return selectList(new LambdaQueryWrapperX<WeeklyReportApprovalRecordDO>()
.eq(WeeklyReportApprovalRecordDO::getWeeklyReportId, weeklyReportId)
.orderByDesc(WeeklyReportApprovalRecordDO::getApprovalRound)
.orderByDesc(WeeklyReportApprovalRecordDO::getId));
}
default int countByWeeklyReportId(Long weeklyReportId) {
return Math.toIntExact(selectCount(new LambdaQueryWrapperX<WeeklyReportApprovalRecordDO>()
.eq(WeeklyReportApprovalRecordDO::getWeeklyReportId, weeklyReportId)));
}
default int deleteByWeeklyReportId(Long weeklyReportId) {
return delete(new LambdaQueryWrapperX<WeeklyReportApprovalRecordDO>()
.eq(WeeklyReportApprovalRecordDO::getWeeklyReportId, weeklyReportId));
}
}

View File

@@ -0,0 +1,124 @@
package com.njcn.rdms.module.project.dal.mysql.workreport.weekly;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.project.constant.WorkReportConstants;
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportPageReqVO;
import com.njcn.rdms.module.project.dal.dataobject.workreport.weekly.WeeklyReportDO;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
@Mapper
public interface WeeklyReportMapper extends BaseMapperX<WeeklyReportDO> {
default WeeklyReportDO selectByReporterIdAndPeriodKey(Long reporterId, String periodKey) {
return selectOne(new LambdaQueryWrapperX<WeeklyReportDO>()
.eq(WeeklyReportDO::getReporterId, reporterId)
.eq(WeeklyReportDO::getPeriodKey, periodKey));
}
default PageResult<WeeklyReportDO> selectReporterPage(Long reporterId, WeeklyReportPageReqVO reqVO) {
return selectReporterPage(reporterId, reqVO, null);
}
default PageResult<WeeklyReportDO> selectReporterPage(Long reporterId, WeeklyReportPageReqVO reqVO,
Collection<String> allowedStatusCodes) {
if (allowedStatusCodes != null && allowedStatusCodes.isEmpty()) {
return new PageResult<>(List.of(), 0L);
}
LambdaQueryWrapperX<WeeklyReportDO> wrapper = buildPageQuery(reqVO)
.eq(WeeklyReportDO::getReporterId, reporterId)
.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) {
LambdaQueryWrapperX<WeeklyReportDO> wrapper = buildPageQuery(reqVO)
.eq(WeeklyReportDO::getSupervisorUserId, supervisorUserId)
.eq(WeeklyReportDO::getStatusCode, WorkReportConstants.STATUS_PENDING_APPROVAL)
.orderByDesc(WeeklyReportDO::getSubmitTime)
.orderByDesc(WeeklyReportDO::getId);
return selectPage(reqVO, wrapper);
}
default int updateByIdAndStatus(WeeklyReportDO update, Long id, String fromStatus) {
return update(update, new LambdaQueryWrapperX<WeeklyReportDO>()
.eq(WeeklyReportDO::getId, id)
.eq(WeeklyReportDO::getStatusCode, fromStatus));
}
default int updateSubmitFieldsByIdAndStatus(Long id, String fromStatus, String reporterDeptName,
String reporterPostName, Long supervisorUserId,
String supervisorName, String toStatus, LocalDateTime submitTime,
String updater) {
return update(null, new LambdaUpdateWrapper<WeeklyReportDO>()
.set(WeeklyReportDO::getReporterDeptName, reporterDeptName)
.set(WeeklyReportDO::getReporterPostName, reporterPostName)
.set(WeeklyReportDO::getSupervisorUserId, supervisorUserId)
.set(WeeklyReportDO::getSupervisorName, supervisorName)
.set(WeeklyReportDO::getStatusCode, toStatus)
.set(WeeklyReportDO::getSubmitTime, submitTime)
.set(WeeklyReportDO::getApprovalTime, null)
.set(WeeklyReportDO::getApprovalComment, null)
.set(WeeklyReportDO::getLastStatusReason, null)
.set(WeeklyReportDO::getUpdateTime, submitTime)
.set(WeeklyReportDO::getUpdater, updater)
.eq(WeeklyReportDO::getId, id)
.eq(WeeklyReportDO::getStatusCode, fromStatus));
}
default int updateApprovalFieldsByIdAndStatus(Long id, String fromStatus, String toStatus,
LocalDateTime approvalTime, String approvalComment,
String lastStatusReason, String updater) {
return update(null, new LambdaUpdateWrapper<WeeklyReportDO>()
.set(WeeklyReportDO::getStatusCode, toStatus)
.set(WeeklyReportDO::getApprovalTime, approvalTime)
.set(WeeklyReportDO::getApprovalComment, approvalComment)
.set(WeeklyReportDO::getLastStatusReason, lastStatusReason)
.set(WeeklyReportDO::getUpdateTime, approvalTime)
.set(WeeklyReportDO::getUpdater, updater)
.eq(WeeklyReportDO::getId, id)
.eq(WeeklyReportDO::getStatusCode, fromStatus));
}
default int updateByIdAndStatusesAndReporterId(WeeklyReportDO update, Long id, Collection<String> statuses,
Long reporterId) {
return update(update, new LambdaQueryWrapperX<WeeklyReportDO>()
.eq(WeeklyReportDO::getId, id)
.eq(WeeklyReportDO::getReporterId, reporterId)
.in(WeeklyReportDO::getStatusCode, statuses));
}
default int deleteByIdAndStatusesAndReporterId(Long id, Collection<String> statuses, Long reporterId) {
return delete(new LambdaQueryWrapperX<WeeklyReportDO>()
.eq(WeeklyReportDO::getId, id)
.eq(WeeklyReportDO::getReporterId, reporterId)
.in(WeeklyReportDO::getStatusCode, statuses));
}
private LambdaQueryWrapperX<WeeklyReportDO> buildPageQuery(WeeklyReportPageReqVO reqVO) {
LambdaQueryWrapperX<WeeklyReportDO> wrapper = new LambdaQueryWrapperX<WeeklyReportDO>()
.eqIfPresent(WeeklyReportDO::getStatusCode, reqVO.getStatusCode())
.eqIfPresent(WeeklyReportDO::getIsBusinessTrip, reqVO.getIsBusinessTrip())
.betweenIfPresent(WeeklyReportDO::getPeriodStartDate, reqVO.getPeriodStartDate())
.betweenIfPresent(WeeklyReportDO::getSubmitTime, reqVO.getSubmitTime());
if (StringUtils.hasText(reqVO.getKeyword())) {
wrapper.and(w -> w.like(WeeklyReportDO::getPeriodLabel, reqVO.getKeyword())
.or()
.like(WeeklyReportDO::getReporterName, reqVO.getKeyword())
.or()
.like(WeeklyReportDO::getSupervisorName, reqVO.getKeyword()));
}
return wrapper;
}
}

View File

@@ -0,0 +1,24 @@
package com.njcn.rdms.module.project.dal.mysql.workreport.weekly;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.project.dal.dataobject.workreport.weekly.WeeklyReportTravelSegmentDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface WeeklyReportTravelSegmentMapper extends BaseMapperX<WeeklyReportTravelSegmentDO> {
default List<WeeklyReportTravelSegmentDO> selectListByWeeklyReportId(Long weeklyReportId) {
return selectList(new LambdaQueryWrapperX<WeeklyReportTravelSegmentDO>()
.eq(WeeklyReportTravelSegmentDO::getWeeklyReportId, weeklyReportId)
.orderByAsc(WeeklyReportTravelSegmentDO::getSort)
.orderByAsc(WeeklyReportTravelSegmentDO::getId));
}
default int deleteByWeeklyReportId(Long weeklyReportId) {
return delete(new LambdaQueryWrapperX<WeeklyReportTravelSegmentDO>()
.eq(WeeklyReportTravelSegmentDO::getWeeklyReportId, weeklyReportId));
}
}

View File

@@ -1,13 +1,15 @@
package com.njcn.rdms.module.project.framework.rpc.config; package com.njcn.rdms.module.project.framework.rpc.config;
import com.njcn.rdms.module.system.api.dept.DeptApi;
import com.njcn.rdms.module.system.api.dept.OrgLeaderApi; import com.njcn.rdms.module.system.api.dept.OrgLeaderApi;
import com.njcn.rdms.module.system.api.dept.PostApi;
import com.njcn.rdms.module.system.api.dict.DictDataApi; import com.njcn.rdms.module.system.api.dict.DictDataApi;
import com.njcn.rdms.module.system.api.file.FileApi; import com.njcn.rdms.module.system.api.file.FileApi;
import com.njcn.rdms.module.system.api.notify.NotifyMessageSendApi;
import com.njcn.rdms.module.system.api.permission.ObjectPermissionApi; import com.njcn.rdms.module.system.api.permission.ObjectPermissionApi;
import com.njcn.rdms.module.system.api.permission.PermissionApi; import com.njcn.rdms.module.system.api.permission.PermissionApi;
import com.njcn.rdms.module.system.api.permission.UserVisibilityConfigApi; import com.njcn.rdms.module.system.api.permission.UserVisibilityConfigApi;
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.UserManagementRelationApi;
import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -15,6 +17,9 @@ import org.springframework.context.annotation.Configuration;
* Project 模块的 RPC 配置 * Project 模块的 RPC 配置
*/ */
@Configuration(value = "projectRpcConfiguration", proxyBeanMethods = false) @Configuration(value = "projectRpcConfiguration", proxyBeanMethods = false)
@EnableFeignClients(clients = {AdminUserApi.class, ObjectPermissionApi.class, DictDataApi.class, FileApi.class, PermissionApi.class, OrgLeaderApi.class, UserVisibilityConfigApi.class, NotifyMessageSendApi.class}) @EnableFeignClients(clients =
{AdminUserApi.class, ObjectPermissionApi.class, DictDataApi.class, FileApi.class,
PermissionApi.class, OrgLeaderApi.class, UserVisibilityConfigApi.class,
DeptApi.class, PostApi.class, UserManagementRelationApi.class})
public class RpcConfiguration { public class RpcConfiguration {
} }

View File

@@ -1,6 +1,7 @@
package com.njcn.rdms.module.project.service.overtime; package com.njcn.rdms.module.project.service.overtime;
import com.njcn.rdms.framework.common.pojo.PageResult; import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationApprovalRecordRespVO;
import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationExportVO; import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationExportVO;
import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationPageReqVO; 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.controller.admin.overtime.vo.OvertimeApplicationRespVO;
@@ -21,8 +22,6 @@ public interface OvertimeApplicationService {
void reject(Long id, OvertimeApplicationStatusActionReqVO reqVO); void reject(Long id, OvertimeApplicationStatusActionReqVO reqVO);
void cancel(Long id, OvertimeApplicationStatusActionReqVO reqVO);
void deleteApplication(Long id); void deleteApplication(Long id);
OvertimeApplicationRespVO getApplication(Long id); OvertimeApplicationRespVO getApplication(Long id);
@@ -35,5 +34,7 @@ public interface OvertimeApplicationService {
List<OvertimeApplicationStatusLogRespVO> getStatusLogs(Long id); List<OvertimeApplicationStatusLogRespVO> getStatusLogs(Long id);
List<OvertimeApplicationApprovalRecordRespVO> getApprovalRecords(Long id);
List<OvertimeApplicationExportVO> getExportList(OvertimeApplicationPageReqVO reqVO); List<OvertimeApplicationExportVO> getExportList(OvertimeApplicationPageReqVO reqVO);
} }

View File

@@ -7,6 +7,7 @@ import com.njcn.rdms.framework.common.util.json.JsonUtils;
import com.njcn.rdms.framework.common.util.object.BeanUtils; import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils; import com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils;
import com.njcn.rdms.module.project.constant.OvertimeApplicationConstants; import com.njcn.rdms.module.project.constant.OvertimeApplicationConstants;
import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationApprovalRecordRespVO;
import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationExportVO; import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationExportVO;
import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationPageReqVO; 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.controller.admin.overtime.vo.OvertimeApplicationRespVO;
@@ -15,11 +16,13 @@ import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplica
import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationStatusDictRespVO; import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationStatusDictRespVO;
import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationStatusLogRespVO; import com.njcn.rdms.module.project.controller.admin.overtime.vo.OvertimeApplicationStatusLogRespVO;
import com.njcn.rdms.module.project.dal.dataobject.audit.BizAuditLogDO; import com.njcn.rdms.module.project.dal.dataobject.audit.BizAuditLogDO;
import com.njcn.rdms.module.project.dal.dataobject.overtime.OvertimeApplicationApprovalRecordDO;
import com.njcn.rdms.module.project.dal.dataobject.overtime.OvertimeApplicationDO; import com.njcn.rdms.module.project.dal.dataobject.overtime.OvertimeApplicationDO;
import com.njcn.rdms.module.project.dal.dataobject.overtime.OvertimeApplicationStatusLogDO; import com.njcn.rdms.module.project.dal.dataobject.overtime.OvertimeApplicationStatusLogDO;
import com.njcn.rdms.module.project.dal.dataobject.status.ObjectStatusModelDO; import com.njcn.rdms.module.project.dal.dataobject.status.ObjectStatusModelDO;
import com.njcn.rdms.module.project.dal.dataobject.status.ObjectStatusTransitionDO; import com.njcn.rdms.module.project.dal.dataobject.status.ObjectStatusTransitionDO;
import com.njcn.rdms.module.project.dal.mysql.audit.BizAuditLogMapper; import com.njcn.rdms.module.project.dal.mysql.audit.BizAuditLogMapper;
import com.njcn.rdms.module.project.dal.mysql.overtime.OvertimeApplicationApprovalRecordMapper;
import com.njcn.rdms.module.project.dal.mysql.overtime.OvertimeApplicationMapper; import com.njcn.rdms.module.project.dal.mysql.overtime.OvertimeApplicationMapper;
import com.njcn.rdms.module.project.dal.mysql.overtime.OvertimeApplicationStatusLogMapper; import com.njcn.rdms.module.project.dal.mysql.overtime.OvertimeApplicationStatusLogMapper;
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusModelMapper; import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusModelMapper;
@@ -53,6 +56,8 @@ public class OvertimeApplicationServiceImpl implements OvertimeApplicationServic
@Resource @Resource
private OvertimeApplicationStatusLogMapper overtimeApplicationStatusLogMapper; private OvertimeApplicationStatusLogMapper overtimeApplicationStatusLogMapper;
@Resource @Resource
private OvertimeApplicationApprovalRecordMapper overtimeApplicationApprovalRecordMapper;
@Resource
private BizAuditLogMapper bizAuditLogMapper; private BizAuditLogMapper bizAuditLogMapper;
@Resource @Resource
private ObjectStatusModelMapper objectStatusModelMapper; private ObjectStatusModelMapper objectStatusModelMapper;
@@ -108,8 +113,7 @@ public class OvertimeApplicationServiceImpl implements OvertimeApplicationServic
update.setApprovalTime(null); update.setApprovalTime(null);
int updateCount = overtimeApplicationMapper.updateByIdAndStatusesAndApplicantId(update, id, int updateCount = overtimeApplicationMapper.updateByIdAndStatusesAndApplicantId(update, id,
List.of(OvertimeApplicationConstants.STATUS_REJECTED, OvertimeApplicationConstants.STATUS_CANCELLED), List.of(OvertimeApplicationConstants.STATUS_REJECTED), loginUserId);
loginUserId);
if (updateCount != 1) { if (updateCount != 1) {
throw exception(ErrorCodeConstants.OVERTIME_APPLICATION_STATUS_CONCURRENT_MODIFIED); throw exception(ErrorCodeConstants.OVERTIME_APPLICATION_STATUS_CONCURRENT_MODIFIED);
} }
@@ -133,36 +137,6 @@ public class OvertimeApplicationServiceImpl implements OvertimeApplicationServic
processApprovalAction(id, OvertimeApplicationConstants.ACTION_REJECT, reqVO); processApprovalAction(id, OvertimeApplicationConstants.ACTION_REJECT, reqVO);
} }
@Override
@Transactional(rollbackFor = Exception.class)
public void cancel(Long id, OvertimeApplicationStatusActionReqVO reqVO) {
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
OvertimeApplicationDO current = validateApplicationExists(id);
if (!Objects.equals(current.getApplicantId(), loginUserId)) {
throw exception(ErrorCodeConstants.OVERTIME_APPLICATION_APPLICANT_ONLY);
}
String reason = normalizeNullableText(reqVO == null ? null : reqVO.getReason());
String fromStatus = current.getStatusCode();
ObjectStatusTransitionDO transition = validateTransition(fromStatus, OvertimeApplicationConstants.ACTION_CANCEL,
reason);
OvertimeApplicationDO update = new OvertimeApplicationDO();
update.setStatusCode(transition.getToStatusCode());
update.setApprovalComment(reason);
update.setApprovalTime(LocalDateTime.now());
int updateCount = overtimeApplicationMapper.updateByIdAndStatusAndApplicantId(update, id, fromStatus,
loginUserId);
if (updateCount != 1) {
throw exception(ErrorCodeConstants.OVERTIME_APPLICATION_STATUS_CONCURRENT_MODIFIED);
}
OvertimeApplicationDO after = mergeUpdated(current, update);
writeStatusLog(after, OvertimeApplicationConstants.ACTION_CANCEL, fromStatus, transition.getToStatusCode(),
reason);
writeAuditLog(after, OvertimeApplicationConstants.ACTION_CANCEL, fromStatus, transition.getToStatusCode(),
null, reason, null);
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void deleteApplication(Long id) { public void deleteApplication(Long id) {
@@ -171,8 +145,8 @@ public class OvertimeApplicationServiceImpl implements OvertimeApplicationServic
if (!Objects.equals(current.getApplicantId(), loginUserId)) { if (!Objects.equals(current.getApplicantId(), loginUserId)) {
throw exception(ErrorCodeConstants.OVERTIME_APPLICATION_APPLICANT_ONLY); throw exception(ErrorCodeConstants.OVERTIME_APPLICATION_APPLICANT_ONLY);
} }
if (!OvertimeApplicationConstants.STATUS_CANCELLED.equals(current.getStatusCode())) { if (!OvertimeApplicationConstants.STATUS_REJECTED.equals(current.getStatusCode())) {
throw exception(ErrorCodeConstants.OVERTIME_APPLICATION_DELETE_ONLY_CANCELLED); throw exception(ErrorCodeConstants.OVERTIME_APPLICATION_DELETE_ONLY_REJECTED);
} }
overtimeApplicationMapper.deleteById(id); overtimeApplicationMapper.deleteById(id);
writeAuditLog(current, OvertimeApplicationConstants.ACTION_DELETE, current.getStatusCode(), null, null, null, writeAuditLog(current, OvertimeApplicationConstants.ACTION_DELETE, current.getStatusCode(), null, null, null,
@@ -215,6 +189,13 @@ public class OvertimeApplicationServiceImpl implements OvertimeApplicationServic
OvertimeApplicationStatusLogRespVO.class); OvertimeApplicationStatusLogRespVO.class);
} }
@Override
public List<OvertimeApplicationApprovalRecordRespVO> getApprovalRecords(Long id) {
validateReadableApplication(id);
return BeanUtils.toBean(overtimeApplicationApprovalRecordMapper.selectListByApplicationId(id),
OvertimeApplicationApprovalRecordRespVO.class);
}
@Override @Override
public List<OvertimeApplicationExportVO> getExportList(OvertimeApplicationPageReqVO reqVO) { public List<OvertimeApplicationExportVO> getExportList(OvertimeApplicationPageReqVO reqVO) {
reqVO.setPageSize(PageParam.PAGE_SIZE_NONE); reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
@@ -242,7 +223,9 @@ public class OvertimeApplicationServiceImpl implements OvertimeApplicationServic
} }
OvertimeApplicationDO after = mergeUpdated(current, update); OvertimeApplicationDO after = mergeUpdated(current, update);
writeStatusLog(after, actionCode, fromStatus, transition.getToStatusCode(), reason); OvertimeApplicationStatusLogDO statusLog = writeStatusLog(after, actionCode, fromStatus,
transition.getToStatusCode(), reason);
writeApprovalRecord(after, statusLog, reason);
writeAuditLog(after, actionCode, fromStatus, transition.getToStatusCode(), null, reason, null); writeAuditLog(after, actionCode, fromStatus, transition.getToStatusCode(), null, reason, null);
} }
@@ -354,8 +337,8 @@ public class OvertimeApplicationServiceImpl implements OvertimeApplicationServic
return respVO; return respVO;
} }
private void writeStatusLog(OvertimeApplicationDO application, String actionType, String fromStatus, private OvertimeApplicationStatusLogDO writeStatusLog(OvertimeApplicationDO application, String actionType,
String toStatus, String reason) { String fromStatus, String toStatus, String reason) {
OvertimeApplicationStatusLogDO log = new OvertimeApplicationStatusLogDO(); OvertimeApplicationStatusLogDO log = new OvertimeApplicationStatusLogDO();
log.setApplicationId(application.getId()); log.setApplicationId(application.getId());
log.setActionType(actionType); log.setActionType(actionType);
@@ -369,6 +352,20 @@ public class OvertimeApplicationServiceImpl implements OvertimeApplicationServic
log.setOvertimeDurationSnapshot(application.getOvertimeDuration()); log.setOvertimeDurationSnapshot(application.getOvertimeDuration());
log.setRemark(buildSnapshotRemark(application)); log.setRemark(buildSnapshotRemark(application));
overtimeApplicationStatusLogMapper.insert(log); overtimeApplicationStatusLogMapper.insert(log);
return log;
}
private void writeApprovalRecord(OvertimeApplicationDO application, OvertimeApplicationStatusLogDO statusLog,
String reason) {
OvertimeApplicationApprovalRecordDO record = new OvertimeApplicationApprovalRecordDO();
record.setOvertimeApplicationId(application.getId());
record.setStatusLogId(statusLog.getId());
record.setApprovalRound(overtimeApplicationApprovalRecordMapper.countByApplicationId(application.getId()) + 1);
record.setConclusion(statusLog.getToStatus());
record.setOpinion(reason);
record.setAuditorUserId(SecurityFrameworkUtils.getLoginUserId());
record.setAuditorName(defaultText(SecurityFrameworkUtils.getLoginUserNickname()));
overtimeApplicationApprovalRecordMapper.insert(record);
} }
private void writeAuditLog(OvertimeApplicationDO application, String actionType, String fromStatus, private void writeAuditLog(OvertimeApplicationDO application, String actionType, String fromStatus,

View File

@@ -0,0 +1,10 @@
package com.njcn.rdms.module.project.service.workreport.common;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusDictRespVO;
import java.util.List;
public interface WorkReportStatusService {
List<WorkReportStatusDictRespVO> getStatusDict();
}

View File

@@ -0,0 +1,19 @@
package com.njcn.rdms.module.project.service.workreport.common;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusDictRespVO;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class WorkReportStatusServiceImpl implements WorkReportStatusService {
@Resource
private WorkReportCommonService workReportCommonService;
@Override
public List<WorkReportStatusDictRespVO> getStatusDict() {
return workReportCommonService.getStatusDict();
}
}

View File

@@ -0,0 +1,930 @@
package com.njcn.rdms.module.project.service.workreport.defaultdraft;
import com.njcn.rdms.framework.common.biz.system.dict.dto.DictDataRespDTO;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils;
import com.njcn.rdms.module.project.constant.ProjectObjectConstants;
import com.njcn.rdms.module.project.constant.ProjectTaskConstants;
import com.njcn.rdms.module.project.constant.WorkReportConstants;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.PersonalReportPlanItemRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.PersonalReportReviewItemRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportMemberSnapshotRespVO;
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.project.vo.ProjectReportDefaultDraftReqVO;
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.weekly.vo.WeeklyReportDefaultDraftReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportRespVO;
import com.njcn.rdms.module.project.dal.dataobject.member.UserObjectRoleDO;
import com.njcn.rdms.module.project.dal.dataobject.personal.PersonalItemDO;
import com.njcn.rdms.module.project.dal.dataobject.project.ProjectDO;
import com.njcn.rdms.module.project.dal.dataobject.project.execution.ProjectExecutionDO;
import com.njcn.rdms.module.project.dal.dataobject.project.task.ProjectTaskDO;
import com.njcn.rdms.module.project.dal.dataobject.project.task.TaskWorklogDO;
import com.njcn.rdms.module.project.dal.dataobject.status.ObjectStatusModelDO;
import com.njcn.rdms.module.project.dal.dataobject.workreport.common.WorkReportMemberSnapshotItem;
import com.njcn.rdms.module.project.dal.mysql.member.UserObjectRoleMapper;
import com.njcn.rdms.module.project.dal.mysql.personal.PersonalItemMapper;
import com.njcn.rdms.module.project.dal.mysql.project.ProjectMapper;
import com.njcn.rdms.module.project.dal.mysql.project.execution.ProjectExecutionMapper;
import com.njcn.rdms.module.project.dal.mysql.project.task.ProjectTaskMapper;
import com.njcn.rdms.module.project.dal.mysql.project.task.TaskWorklogMapper;
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusModelMapper;
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
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.dto.DeptRespDTO;
import com.njcn.rdms.module.system.api.dept.dto.PostRespDTO;
import com.njcn.rdms.module.system.api.dict.DictDataApi;
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 com.njcn.rdms.module.system.enums.DictTypeConstants;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
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.exception;
import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
@Service
public class WorkReportDefaultDraftService {
private static final String WORK_ITEM_MY_ITEMS = "我的事项";
@Resource
private ObjectStatusModelMapper objectStatusModelMapper;
@Resource
private AdminUserApi adminUserApi;
@Resource
private DeptApi deptApi;
@Resource
private PostApi postApi;
@Resource
private UserManagementRelationApi userManagementRelationApi;
@Resource
private DictDataApi dictDataApi;
@Resource
private ProjectMapper projectMapper;
@Resource
private UserObjectRoleMapper userObjectRoleMapper;
@Resource
private TaskWorklogMapper taskWorklogMapper;
@Resource
private ProjectTaskMapper projectTaskMapper;
@Resource
private PersonalItemMapper personalItemMapper;
@Resource
private ProjectExecutionMapper projectExecutionMapper;
public WeeklyReportRespVO previewWeeklyDefaultDraft(WeeklyReportDefaultDraftReqVO reqVO) {
validatePeriod(reqVO.getPeriodStartDate(), reqVO.getPeriodEndDate());
CurrentUserProfile profile = loadCurrentUserProfile(true);
ObjectStatusModelDO initialStatus = getInitialStatusModel();
WeeklyReportRespVO respVO = new WeeklyReportRespVO();
fillPersonalBase(respVO, profile);
respVO.setPeriodKey(reqVO.getPeriodKey());
respVO.setPeriodLabel(reqVO.getPeriodLabel());
respVO.setPeriodStartDate(reqVO.getPeriodStartDate());
respVO.setPeriodEndDate(reqVO.getPeriodEndDate());
respVO.setIsBusinessTrip(Boolean.FALSE);
respVO.setTravelSegments(Collections.emptyList());
respVO.setTotalTravelDays(BigDecimal.ZERO);
applyStatusView(respVO, initialStatus);
LocalDateRange nextRange = nextWeeklyRange(reqVO.getPeriodStartDate(), reqVO.getPeriodEndDate());
List<PersonalReportReviewItemRespVO> reviewItems = buildPersonalReviewItems(
reqVO.getPeriodStartDate(), reqVO.getPeriodEndDate(), profile.userId(), true);
List<PersonalReportPlanItemRespVO> planItems = buildPersonalPlanItems(
nextRange.startDate(), nextRange.endDate(), profile.userId(), true);
respVO.setReviewItems(reviewItems);
respVO.setPlanItems(planItems);
respVO.setTotalWorkHours(sumReviewWorkHours(reviewItems));
return respVO;
}
public MonthlyReportRespVO previewMonthlyDefaultDraft(MonthlyReportDefaultDraftReqVO reqVO) {
validatePeriod(reqVO.getPeriodStartDate(), reqVO.getPeriodEndDate());
CurrentUserProfile profile = loadCurrentUserProfile(true);
ObjectStatusModelDO initialStatus = getInitialStatusModel();
MonthlyReportRespVO respVO = new MonthlyReportRespVO();
fillPersonalBase(respVO, profile);
respVO.setPeriodKey(reqVO.getPeriodKey());
respVO.setPeriodLabel(reqVO.getPeriodLabel());
respVO.setPeriodStartDate(reqVO.getPeriodStartDate());
respVO.setPeriodEndDate(reqVO.getPeriodEndDate());
applyStatusView(respVO, initialStatus);
LocalDateRange nextRange = nextMonthlyRange(reqVO.getPeriodEndDate());
List<PersonalReportReviewItemRespVO> reviewItems = buildPersonalReviewItems(
reqVO.getPeriodStartDate(), reqVO.getPeriodEndDate(), profile.userId(), false);
List<PersonalReportPlanItemRespVO> planItems = buildPersonalPlanItems(
nextRange.startDate(), nextRange.endDate(), profile.userId(), false);
respVO.setReviewItems(reviewItems);
respVO.setPlanItems(planItems);
respVO.setTotalWorkHours(sumReviewWorkHours(reviewItems));
return respVO;
}
public ProjectReportRespVO previewProjectDefaultDraft(Long projectId, ProjectReportDefaultDraftReqVO reqVO) {
validatePeriod(reqVO.getPeriodStartDate(), reqVO.getPeriodEndDate());
validateProjectFlag(reqVO.getFlag());
CurrentUserProfile profile = loadCurrentUserProfile(true);
ProjectDO project = validateProjectExists(projectId);
ObjectStatusModelDO initialStatus = getInitialStatusModel();
ProjectReportRespVO respVO = new ProjectReportRespVO();
respVO.setProjectId(project.getId());
respVO.setProjectName(project.getProjectName());
respVO.setProjectOwnerId(profile.userId());
respVO.setProjectOwnerName(profile.userName());
respVO.setTechnicalOwnerName(resolveProjectManagerName(project.getManagerUserId()));
respVO.setProjectMemberSnapshot(BeanUtils.toBean(buildProjectMemberSnapshot(projectId),
WorkReportMemberSnapshotRespVO.class));
respVO.setSupervisorUserId(profile.directManagerId());
respVO.setSupervisorName(profile.directManagerName());
respVO.setPeriodKey(reqVO.getPeriodKey());
respVO.setPeriodLabel(reqVO.getPeriodLabel());
respVO.setPeriodStartDate(reqVO.getPeriodStartDate());
respVO.setPeriodEndDate(reqVO.getPeriodEndDate());
respVO.setFlag(reqVO.getFlag());
applyStatusView(respVO, initialStatus);
LocalDateRange nextRange = nextHalfMonthRange(reqVO.getPeriodEndDate());
List<ProjectReportItemRespVO> currentItems = buildProjectCurrentItems(
projectId, reqVO.getPeriodStartDate(), reqVO.getPeriodEndDate());
List<ProjectReportItemRespVO> nextItems = buildProjectNextItems(
projectId, nextRange.startDate(), nextRange.endDate());
respVO.setCurrentItems(currentItems);
respVO.setNextItems(nextItems);
respVO.setTotalWorkHours(sumProjectWorkHours(currentItems));
return respVO;
}
private List<PersonalReportReviewItemRespVO> buildPersonalReviewItems(LocalDate periodStartDate,
LocalDate periodEndDate,
Long userId,
boolean weeklyMode) {
List<TaskWorklogDO> worklogs = taskWorklogMapper.selectListByUserIdAndPeriod(userId, periodStartDate, periodEndDate);
if (worklogs.isEmpty()) {
return Collections.emptyList();
}
Set<Long> taskIds = worklogs.stream()
.map(TaskWorklogDO::getTaskId)
.filter(Objects::nonNull)
.collect(Collectors.toCollection(LinkedHashSet::new));
if (taskIds.isEmpty()) {
return Collections.emptyList();
}
Map<Long, ProjectTaskDO> taskMap = projectTaskMapper.selectBatchIds(taskIds).stream()
.collect(Collectors.toMap(ProjectTaskDO::getId, item -> item));
Map<Long, PersonalItemDO> itemMap = personalItemMapper.selectBatchIds(taskIds).stream()
.collect(Collectors.toMap(PersonalItemDO::getId, item -> item));
Set<Long> projectIds = taskMap.values().stream()
.map(ProjectTaskDO::getProjectId)
.filter(Objects::nonNull)
.collect(Collectors.toCollection(LinkedHashSet::new));
Map<Long, ProjectDO> projectMap = projectIds.isEmpty() ? Collections.emptyMap()
: projectMapper.selectBatchIds(projectIds).stream()
.collect(Collectors.toMap(ProjectDO::getId, item -> item));
Map<String, String> taskItemTypeLabelMap = loadTaskItemTypeLabelMap();
Map<String, ReviewAggregate> aggregateMap = new LinkedHashMap<>();
for (TaskWorklogDO worklog : worklogs) {
if (worklog.getTaskId() == null) {
continue;
}
ProjectTaskDO task = taskMap.get(worklog.getTaskId());
if (task != null) {
ProjectDO project = projectMap.get(task.getProjectId());
String workItemTitle = safeText(project == null ? null : project.getProjectName());
String groupKey = workItemTitle + "||task||" + task.getId();
ReviewAggregate aggregate = aggregateMap.computeIfAbsent(groupKey, key -> new ReviewAggregate(
workItemTitle,
safeText(task.getTaskTitle()),
safeText(task.getPriority()),
resolveTaskItemTypeLabel(task.getType(), taskItemTypeLabelMap)));
aggregate.merge(worklog);
continue;
}
PersonalItemDO item = itemMap.get(worklog.getTaskId());
if (item != null) {
String groupKey = WORK_ITEM_MY_ITEMS + "||item||" + item.getId();
ReviewAggregate aggregate = aggregateMap.computeIfAbsent(groupKey, key -> new ReviewAggregate(
WORK_ITEM_MY_ITEMS,
safeText(item.getTaskTitle()),
null,
resolveTaskItemTypeLabel(item.getType(), taskItemTypeLabelMap)));
aggregate.merge(worklog);
}
}
List<PersonalReportReviewItemRespVO> result = new ArrayList<>();
int itemNumber = 1;
for (ReviewAggregate aggregate : aggregateMap.values()) {
if (isZeroProgress(aggregate.latestProgressRate())) {
continue;
}
PersonalReportReviewItemRespVO item = new PersonalReportReviewItemRespVO();
item.setItemNumber(itemNumber++);
item.setItemTitle(aggregate.workItemTitle());
item.setWorkHours(nullToZero(aggregate.totalWorkHours()));
item.setContentText(weeklyMode ? aggregate.buildWeeklyReviewText() : aggregate.buildMonthlyReviewText());
item.setReflectionText(null);
result.add(item);
}
return result;
}
private List<PersonalReportPlanItemRespVO> buildPersonalPlanItems(LocalDate nextStartDate,
LocalDate nextEndDate,
Long userId,
boolean weeklyMode) {
List<TaskWorklogDO> nextPeriodWorklogs = taskWorklogMapper.selectListByUserIdAndPeriod(userId, nextStartDate, nextEndDate);
Map<Long, TaskWorklogAggregate> worklogAggregateMap = aggregateTaskWorklogs(nextPeriodWorklogs);
Map<Long, ProjectTaskDO> taskMap = loadPlanTaskMap(userId, nextStartDate, nextEndDate, worklogAggregateMap.keySet());
Map<Long, PersonalItemDO> itemMap = loadPlanItemMap(userId, nextStartDate, nextEndDate, worklogAggregateMap.keySet());
Set<Long> projectIds = taskMap.values().stream()
.map(ProjectTaskDO::getProjectId)
.filter(Objects::nonNull)
.collect(Collectors.toCollection(LinkedHashSet::new));
Map<Long, ProjectDO> projectMap = projectIds.isEmpty() ? Collections.emptyMap()
: projectMapper.selectBatchIds(projectIds).stream()
.collect(Collectors.toMap(ProjectDO::getId, item -> item));
Map<String, String> taskItemTypeLabelMap = loadTaskItemTypeLabelMap();
Map<String, PlanAggregate> aggregateMap = new LinkedHashMap<>();
for (ProjectTaskDO task : taskMap.values()) {
TaskWorklogAggregate worklogAggregate = worklogAggregateMap.get(task.getId());
if (!shouldIncludeTaskInPlan(task, nextStartDate, nextEndDate, worklogAggregate)) {
continue;
}
ProjectDO project = projectMap.get(task.getProjectId());
String workItemTitle = safeText(project == null ? null : project.getProjectName());
String categoryCode = safeText(task.getType());
String categoryLabel = resolveTaskItemTypeLabel(task.getType(), taskItemTypeLabelMap);
String groupKey = workItemTitle + "||" + categoryCode;
PlanAggregate aggregate = aggregateMap.computeIfAbsent(groupKey,
key -> new PlanAggregate(workItemTitle, categoryLabel));
aggregate.addTaskLine(safeText(task.getTaskTitle()), safeText(task.getPriority()), task.getProgressRate(),
worklogAggregate, weeklyMode);
}
for (PersonalItemDO item : itemMap.values()) {
TaskWorklogAggregate worklogAggregate = worklogAggregateMap.get(item.getId());
if (!shouldIncludePersonalItemInPlan(item, nextStartDate, nextEndDate, worklogAggregate)) {
continue;
}
String categoryCode = safeText(item.getType());
String categoryLabel = resolveTaskItemTypeLabel(item.getType(), taskItemTypeLabelMap);
String groupKey = WORK_ITEM_MY_ITEMS + "||" + categoryCode;
PlanAggregate aggregate = aggregateMap.computeIfAbsent(groupKey,
key -> new PlanAggregate(WORK_ITEM_MY_ITEMS, categoryLabel));
aggregate.addItemLine(safeText(item.getTaskTitle()), item.getProgressRate(), worklogAggregate, weeklyMode);
}
List<PersonalReportPlanItemRespVO> result = new ArrayList<>();
int itemNumber = 1;
for (PlanAggregate aggregate : aggregateMap.values()) {
if (aggregate.lines().isEmpty()) {
continue;
}
PersonalReportPlanItemRespVO item = new PersonalReportPlanItemRespVO();
item.setItemNumber(itemNumber++);
item.setItemTitle(aggregate.workItemTitle());
item.setTargetText(aggregate.buildTargetText());
item.setSupportNeed(null);
result.add(item);
}
return result;
}
private List<ProjectReportItemRespVO> buildProjectCurrentItems(Long projectId,
LocalDate periodStartDate,
LocalDate periodEndDate) {
List<ProjectTaskDO> tasks = projectTaskMapper.selectListByProjectId(projectId);
if (tasks.isEmpty()) {
return Collections.emptyList();
}
Set<Long> taskIds = tasks.stream()
.map(ProjectTaskDO::getId)
.collect(Collectors.toCollection(LinkedHashSet::new));
Map<Long, ProjectTaskDO> taskMap = tasks.stream()
.collect(Collectors.toMap(ProjectTaskDO::getId, item -> item));
List<TaskWorklogDO> worklogs = taskWorklogMapper.selectListByTaskIdsAndPeriod(taskIds, periodStartDate, periodEndDate);
if (worklogs.isEmpty()) {
return Collections.emptyList();
}
Map<Long, ProjectExecutionDO> executionMap = projectExecutionMapper.selectListByProjectId(projectId).stream()
.collect(Collectors.toMap(ProjectExecutionDO::getId, item -> item));
Map<Long, BigDecimal> hoursByExecutionId = new LinkedHashMap<>();
for (TaskWorklogDO worklog : worklogs) {
ProjectTaskDO task = taskMap.get(worklog.getTaskId());
if (task == null || task.getExecutionId() == null) {
continue;
}
hoursByExecutionId.merge(task.getExecutionId(), nullToZero(worklog.getDurationHours()), BigDecimal::add);
}
if (hoursByExecutionId.isEmpty()) {
return Collections.emptyList();
}
List<String> progressExcludedStatusCodes = loadProgressExcludedTaskStatusCodes();
List<ProjectReportItemRespVO> result = new ArrayList<>();
for (Map.Entry<Long, BigDecimal> entry : hoursByExecutionId.entrySet()) {
ProjectExecutionDO execution = executionMap.get(entry.getKey());
if (execution == null) {
continue;
}
ProjectReportItemRespVO item = new ProjectReportItemRespVO();
item.setItemTitle(safeText(execution.getExecutionName()));
item.setWorkHours(entry.getValue());
item.setPriorityCode(safeText(execution.getPriority()));
item.setProgressRate(normalizeProgress(projectTaskMapper.selectRootTaskAvgProgressByExecutionId(
projectId, execution.getId(), progressExcludedStatusCodes)));
result.add(item);
}
result.sort(Comparator.comparing(ProjectReportItemRespVO::getItemTitle, Comparator.nullsLast(String::compareTo)));
return result;
}
private List<ProjectReportItemRespVO> buildProjectNextItems(Long projectId,
LocalDate nextStartDate,
LocalDate nextEndDate) {
List<ProjectExecutionDO> plannedExecutions = projectExecutionMapper.selectPlannedListByProjectIdAndOverlap(
projectId, nextStartDate, nextEndDate, ProjectObjectConstants.STATUS_CANCELLED);
List<ProjectExecutionDO> zeroProgressExecutions = projectExecutionMapper.selectListByProjectIdAndStatusNot(
projectId, ProjectObjectConstants.STATUS_CANCELLED).stream()
.filter(execution -> isZeroProgress(execution.getProgressRate()))
.collect(Collectors.toList());
Map<Long, ProjectExecutionDO> executionMap = new LinkedHashMap<>();
plannedExecutions.forEach(item -> executionMap.put(item.getId(), item));
zeroProgressExecutions.forEach(item -> executionMap.put(item.getId(), item));
if (executionMap.isEmpty()) {
return Collections.emptyList();
}
List<String> progressExcludedStatusCodes = loadProgressExcludedTaskStatusCodes();
List<ProjectReportItemRespVO> result = new ArrayList<>();
for (ProjectExecutionDO execution : executionMap.values()) {
BigDecimal progress = normalizeProgress(projectTaskMapper.selectRootTaskAvgProgressByExecutionId(
projectId, execution.getId(), progressExcludedStatusCodes));
if (isCompleted(progress)) {
continue;
}
ProjectReportItemRespVO item = new ProjectReportItemRespVO();
item.setItemTitle(safeText(execution.getExecutionName()));
item.setWorkHours(BigDecimal.ZERO);
item.setPriorityCode(safeText(execution.getPriority()));
item.setProgressRate(progress);
result.add(item);
}
result.sort(Comparator.comparing(ProjectReportItemRespVO::getItemTitle, Comparator.nullsLast(String::compareTo)));
return result;
}
private void validateProjectFlag(Integer flag) {
if (!Objects.equals(flag, 1) && !Objects.equals(flag, 2)) {
throw invalidParamException("上半月/下半月标记只能为 1 或 2");
}
}
private void validatePeriod(LocalDate startDate, LocalDate endDate) {
if (startDate == null || endDate == null) {
throw invalidParamException("周期开始日期和结束日期不能为空");
}
if (endDate.isBefore(startDate)) {
throw invalidParamException("周期结束日期不能早于开始日期");
}
}
private ProjectDO validateProjectExists(Long projectId) {
ProjectDO project = projectMapper.selectById(projectId);
if (project == null) {
throw exception(ErrorCodeConstants.WORK_REPORT_PROJECT_NOT_EXISTS);
}
return project;
}
private ObjectStatusModelDO getInitialStatusModel() {
ObjectStatusModelDO statusModel = objectStatusModelMapper
.selectInitialByObjectTypeEnabled(WorkReportConstants.STATUS_OBJECT_TYPE);
if (statusModel == null || !StringUtils.hasText(statusModel.getStatusCode())) {
throw exception(ErrorCodeConstants.WORK_REPORT_STATUS_MODEL_NOT_EXISTS_OR_DISABLED);
}
return statusModel;
}
private void applyStatusView(WeeklyReportRespVO respVO, ObjectStatusModelDO statusModel) {
respVO.setStatusCode(statusModel.getStatusCode());
respVO.setStatusName(statusModel.getStatusName());
respVO.setAllowEdit(Boolean.TRUE.equals(statusModel.getAllowEdit()));
respVO.setTerminal(Boolean.TRUE.equals(statusModel.getTerminalFlag()));
}
private void applyStatusView(MonthlyReportRespVO respVO, ObjectStatusModelDO statusModel) {
respVO.setStatusCode(statusModel.getStatusCode());
respVO.setStatusName(statusModel.getStatusName());
respVO.setAllowEdit(Boolean.TRUE.equals(statusModel.getAllowEdit()));
respVO.setTerminal(Boolean.TRUE.equals(statusModel.getTerminalFlag()));
}
private void applyStatusView(ProjectReportRespVO respVO, ObjectStatusModelDO statusModel) {
respVO.setStatusCode(statusModel.getStatusCode());
respVO.setStatusName(statusModel.getStatusName());
respVO.setAllowEdit(Boolean.TRUE.equals(statusModel.getAllowEdit()));
respVO.setTerminal(Boolean.TRUE.equals(statusModel.getTerminalFlag()));
}
private void fillPersonalBase(WeeklyReportRespVO respVO, CurrentUserProfile profile) {
respVO.setReporterId(profile.userId());
respVO.setReporterName(profile.userName());
respVO.setReporterDeptName(profile.deptName());
respVO.setReporterPostName(profile.postName());
respVO.setSupervisorUserId(profile.directManagerId());
respVO.setSupervisorName(profile.directManagerName());
}
private void fillPersonalBase(MonthlyReportRespVO respVO, CurrentUserProfile profile) {
respVO.setReporterId(profile.userId());
respVO.setReporterName(profile.userName());
respVO.setReporterDeptName(profile.deptName());
respVO.setReporterPostName(profile.postName());
respVO.setSupervisorUserId(profile.directManagerId());
respVO.setSupervisorName(profile.directManagerName());
}
private CurrentUserProfile loadCurrentUserProfile(boolean requireManager) {
Long userId = SecurityFrameworkUtils.getLoginUserId();
AdminUserRespDTO user = loadUser(userId);
String userName = StringUtils.hasText(user.getNickname())
? user.getNickname().trim()
: safeText(SecurityFrameworkUtils.getLoginUserNickname());
String deptName = null;
if (user.getDeptId() != null) {
CommonResult<DeptRespDTO> deptResult = deptApi.getDept(user.getDeptId());
DeptRespDTO dept = deptResult == null ? null : deptResult.getCheckedData();
deptName = dept == null ? null : dept.getName();
}
String postName = null;
if (user.getPositionId() != null) {
Map<Long, PostRespDTO> postMap = postApi.getPostMap(Collections.singleton(user.getPositionId()));
PostRespDTO post = postMap.get(user.getPositionId());
postName = post == null ? null : post.getName();
}
Long directManagerId = null;
String directManagerName = null;
CommonResult<AdminUserRespDTO> directManagerResult = userManagementRelationApi.getDirectManager(userId);
AdminUserRespDTO directManager = directManagerResult == null ? null : directManagerResult.getCheckedData();
if (directManager != null) {
directManagerId = directManager.getId();
directManagerName = safeText(directManager.getNickname());
}
if (requireManager && directManagerId == null) {
throw exception(ErrorCodeConstants.WORK_REPORT_DIRECT_MANAGER_NOT_EXISTS);
}
return new CurrentUserProfile(userId, safeText(userName), deptName, postName, directManagerId, directManagerName);
}
private AdminUserRespDTO loadUser(Long userId) {
if (userId == null) {
throw invalidParamException("用户编号不能为空");
}
adminUserApi.validateUserList(Collections.singleton(userId)).getCheckedData();
CommonResult<AdminUserRespDTO> result = adminUserApi.getUser(userId);
AdminUserRespDTO user = result == null ? null : result.getCheckedData();
if (user == null) {
throw invalidParamException("用户不存在:{}", userId);
}
return user;
}
private String resolveProjectManagerName(Long managerUserId) {
if (managerUserId == null) {
return null;
}
AdminUserRespDTO manager = loadUser(managerUserId);
return safeText(manager.getNickname());
}
private List<WorkReportMemberSnapshotItem> buildProjectMemberSnapshot(Long projectId) {
List<UserObjectRoleDO> members = userObjectRoleMapper.selectListByObject(ProjectObjectConstants.OBJECT_TYPE, projectId);
Set<Long> userIds = new LinkedHashSet<>();
for (UserObjectRoleDO member : members) {
if (member == null || !Objects.equals(member.getStatus(), 0) || member.getUserId() == null) {
continue;
}
userIds.add(member.getUserId());
}
if (userIds.isEmpty()) {
return Collections.emptyList();
}
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
List<WorkReportMemberSnapshotItem> result = new ArrayList<>(userIds.size());
for (Long userId : userIds) {
WorkReportMemberSnapshotItem item = new WorkReportMemberSnapshotItem();
item.setUserId(userId);
AdminUserRespDTO user = userMap.get(userId);
item.setUserName(user == null ? "" : safeText(user.getNickname()));
result.add(item);
}
return result;
}
private Map<String, String> loadTaskItemTypeLabelMap() {
CommonResult<List<DictDataRespDTO>> result = dictDataApi.getDictDataList(DictTypeConstants.RDMS_TASK_ITEM_TYPE);
List<DictDataRespDTO> dictDataList = result == null ? null : result.getCheckedData();
if (dictDataList == null || dictDataList.isEmpty()) {
return Collections.emptyMap();
}
Map<String, String> labelMap = new LinkedHashMap<>();
for (DictDataRespDTO item : dictDataList) {
if (item == null || !StringUtils.hasText(item.getValue())) {
continue;
}
labelMap.put(item.getValue().trim(), safeText(item.getLabel()));
}
return labelMap;
}
private String resolveTaskItemTypeLabel(String typeCode, Map<String, String> labelMap) {
String normalizedTypeCode = safeText(typeCode);
if (!StringUtils.hasText(normalizedTypeCode)) {
return normalizedTypeCode;
}
String label = labelMap.get(normalizedTypeCode);
return StringUtils.hasText(label) ? label : normalizedTypeCode;
}
private List<String> loadProgressExcludedTaskStatusCodes() {
return objectStatusModelMapper.selectProgressExcludedStatusCodesByObjectTypeEnabled(ProjectTaskConstants.OBJECT_TYPE);
}
private BigDecimal sumReviewWorkHours(List<PersonalReportReviewItemRespVO> reviewItems) {
if (reviewItems == null || reviewItems.isEmpty()) {
return BigDecimal.ZERO;
}
return reviewItems.stream()
.map(PersonalReportReviewItemRespVO::getWorkHours)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
private BigDecimal sumProjectWorkHours(List<ProjectReportItemRespVO> items) {
if (items == null || items.isEmpty()) {
return BigDecimal.ZERO;
}
return items.stream()
.map(ProjectReportItemRespVO::getWorkHours)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
private boolean isZeroProgress(BigDecimal value) {
return value == null || value.compareTo(BigDecimal.ZERO) == 0;
}
private boolean isCompleted(BigDecimal value) {
return value != null && value.compareTo(BigDecimal.valueOf(100)) >= 0;
}
private BigDecimal normalizeProgress(BigDecimal value) {
return value == null ? BigDecimal.ZERO : value.stripTrailingZeros();
}
private BigDecimal nullToZero(BigDecimal value) {
return value == null ? BigDecimal.ZERO : value;
}
private Map<Long, ProjectTaskDO> loadPlanTaskMap(Long userId, LocalDate nextStartDate, LocalDate nextEndDate,
Set<Long> worklogTaskIds) {
Map<Long, ProjectTaskDO> taskMap = new LinkedHashMap<>();
projectTaskMapper.selectPlannedInvolvedListByUserIdAndOverlap(
userId, nextStartDate, nextEndDate, ProjectObjectConstants.STATUS_CANCELLED)
.forEach(task -> taskMap.put(task.getId(), task));
projectTaskMapper.selectInvolvedListByUserIdAndStatusNot(userId, ProjectObjectConstants.STATUS_CANCELLED).stream()
.filter(task -> worklogTaskIds.contains(task.getId()) || isZeroProgress(task.getProgressRate()))
.forEach(task -> taskMap.put(task.getId(), task));
return taskMap;
}
private Map<Long, PersonalItemDO> loadPlanItemMap(Long userId, LocalDate nextStartDate, LocalDate nextEndDate,
Set<Long> worklogTaskIds) {
Map<Long, PersonalItemDO> itemMap = new LinkedHashMap<>();
personalItemMapper.selectPlannedListByOwnerIdAndOverlap(
userId, nextStartDate, nextEndDate, ProjectObjectConstants.STATUS_CANCELLED)
.forEach(item -> itemMap.put(item.getId(), item));
personalItemMapper.selectListByOwnerIdAndStatusNot(userId, ProjectObjectConstants.STATUS_CANCELLED).stream()
.filter(item -> worklogTaskIds.contains(item.getId()) || isZeroProgress(item.getProgressRate()))
.forEach(item -> itemMap.put(item.getId(), item));
return itemMap;
}
private Map<Long, TaskWorklogAggregate> aggregateTaskWorklogs(List<TaskWorklogDO> worklogs) {
if (worklogs == null || worklogs.isEmpty()) {
return Collections.emptyMap();
}
Map<Long, TaskWorklogAggregate> aggregateMap = new LinkedHashMap<>();
for (TaskWorklogDO worklog : worklogs) {
if (worklog.getTaskId() == null) {
continue;
}
aggregateMap.computeIfAbsent(worklog.getTaskId(), key -> new TaskWorklogAggregate())
.merge(worklog);
}
return aggregateMap;
}
private boolean shouldIncludeTaskInPlan(ProjectTaskDO task, LocalDate nextStartDate, LocalDate nextEndDate,
TaskWorklogAggregate worklogAggregate) {
if (task == null || isCompleted(task.getProgressRate())) {
return false;
}
if (worklogAggregate != null) {
return true;
}
if (isZeroProgress(task.getProgressRate())) {
return true;
}
return overlapsNextPeriod(task.getPlannedStartDate(), task.getPlannedEndDate(), nextStartDate, nextEndDate);
}
private boolean shouldIncludePersonalItemInPlan(PersonalItemDO item, LocalDate nextStartDate, LocalDate nextEndDate,
TaskWorklogAggregate worklogAggregate) {
if (item == null || isCompleted(item.getProgressRate())) {
return false;
}
if (worklogAggregate != null) {
return true;
}
if (isZeroProgress(item.getProgressRate())) {
return true;
}
return overlapsNextPeriod(item.getPlannedStartDate(), item.getPlannedEndDate(), nextStartDate, nextEndDate);
}
private boolean overlapsNextPeriod(LocalDate plannedStartDate, LocalDate plannedEndDate,
LocalDate nextStartDate, LocalDate nextEndDate) {
return plannedStartDate != null
&& plannedEndDate != null
&& !plannedStartDate.isAfter(nextEndDate)
&& !plannedEndDate.isBefore(nextStartDate);
}
private String safeText(String value) {
return value == null ? "" : value.trim();
}
private LocalDateRange nextWeeklyRange(LocalDate currentStartDate, LocalDate currentEndDate) {
return new LocalDateRange(currentStartDate.plusWeeks(1), currentEndDate.plusWeeks(1));
}
private LocalDateRange nextMonthlyRange(LocalDate currentEndDate) {
LocalDate nextMonthStart = currentEndDate.withDayOfMonth(1).plusMonths(1);
return new LocalDateRange(nextMonthStart, nextMonthStart.withDayOfMonth(nextMonthStart.lengthOfMonth()));
}
private LocalDateRange nextHalfMonthRange(LocalDate currentEndDate) {
LocalDate nextDay = currentEndDate.plusDays(1);
if (nextDay.getDayOfMonth() <= 15) {
return new LocalDateRange(nextDay.withDayOfMonth(1), nextDay.withDayOfMonth(15));
}
return new LocalDateRange(nextDay.withDayOfMonth(16), nextDay.withDayOfMonth(nextDay.lengthOfMonth()));
}
private record CurrentUserProfile(Long userId, String userName, String deptName, String postName,
Long directManagerId, String directManagerName) {
}
private record LocalDateRange(LocalDate startDate, LocalDate endDate) {
}
private static final class ReviewAggregate {
private final String workItemTitle;
private final String lineTitle;
private final String priority;
private final String typeCode;
private BigDecimal totalWorkHours = BigDecimal.ZERO;
private BigDecimal latestProgressRate = BigDecimal.ZERO;
private LocalDate latestEndDate;
private final List<String> workContents = new ArrayList<>();
private ReviewAggregate(String workItemTitle, String lineTitle, String priority, String typeCode) {
this.workItemTitle = workItemTitle;
this.lineTitle = lineTitle;
this.priority = priority;
this.typeCode = typeCode;
}
private void merge(TaskWorklogDO worklog) {
totalWorkHours = totalWorkHours.add(
worklog.getDurationHours() == null ? BigDecimal.ZERO : worklog.getDurationHours());
LocalDate endDate = worklog.getEndDate();
if (endDate != null && (latestEndDate == null || !endDate.isBefore(latestEndDate))) {
latestEndDate = endDate;
latestProgressRate = worklog.getProgressRate() == null ? BigDecimal.ZERO : worklog.getProgressRate();
}
if (StringUtils.hasText(worklog.getWorkContent())) {
workContents.add(worklog.getWorkContent().trim());
}
}
private String buildWeeklyReviewText() {
StringBuilder builder = new StringBuilder();
if (StringUtils.hasText(typeCode)) {
builder.append(typeCode).append(" - ");
}
builder.append(lineTitle);
appendBracket(builder, priority, latestProgressRate, totalWorkHours);
if (!workContents.isEmpty()) {
builder.append("").append(String.join("", workContents));
}
return builder.toString();
}
private String buildMonthlyReviewText() {
StringBuilder builder = new StringBuilder();
if (StringUtils.hasText(typeCode)) {
builder.append(typeCode).append(" - ");
}
builder.append(lineTitle);
appendBracket(builder, priority, latestProgressRate, totalWorkHours);
return builder.toString();
}
private void appendBracket(StringBuilder builder, String priority,
BigDecimal progressRate, BigDecimal hours) {
List<String> parts = new ArrayList<>();
if (StringUtils.hasText(priority)) {
parts.add(priority);
}
if (progressRate != null) {
parts.add("进度" + progressRate.stripTrailingZeros().toPlainString() + "%");
}
if (hours != null) {
parts.add(hours.stripTrailingZeros().toPlainString() + "h");
}
if (!parts.isEmpty()) {
builder.append("").append(String.join(" / ", parts)).append("");
}
}
private String workItemTitle() {
return workItemTitle;
}
private BigDecimal totalWorkHours() {
return totalWorkHours;
}
private BigDecimal latestProgressRate() {
return latestProgressRate;
}
}
private static final class PlanAggregate {
private final String workItemTitle;
private final String category;
private final List<String> lines = new ArrayList<>();
private PlanAggregate(String workItemTitle, String category) {
this.workItemTitle = workItemTitle;
this.category = category;
}
private void addTaskLine(String title, String priority, BigDecimal progressRate,
TaskWorklogAggregate worklogAggregate, boolean weeklyMode) {
if (!StringUtils.hasText(title)) {
return;
}
if (worklogAggregate != null && worklogAggregate.hasWorkContent()) {
lines.add(buildWorklogStyleLine(title, priority, progressRate, worklogAggregate, weeklyMode));
return;
}
lines.add(buildPlannedStyleLine(title, priority, progressRate));
}
private void addItemLine(String title, BigDecimal progressRate,
TaskWorklogAggregate worklogAggregate, boolean weeklyMode) {
if (!StringUtils.hasText(title)) {
return;
}
if (worklogAggregate != null && worklogAggregate.hasWorkContent()) {
lines.add(buildWorklogStyleLine(title, null, progressRate, worklogAggregate, weeklyMode));
return;
}
lines.add(buildPlannedStyleLine(title, null, progressRate));
}
private String buildWorklogStyleLine(String title, String priority, BigDecimal progressRate,
TaskWorklogAggregate worklogAggregate, boolean weeklyMode) {
StringBuilder builder = new StringBuilder();
if (StringUtils.hasText(category)) {
builder.append(category).append(" - ");
}
builder.append(title);
List<String> parts = new ArrayList<>();
if (StringUtils.hasText(priority)) {
parts.add(priority);
}
if (progressRate != null) {
parts.add("进度" + progressRate.stripTrailingZeros().toPlainString() + "%");
}
if (worklogAggregate.totalWorkHours() != null) {
parts.add(worklogAggregate.totalWorkHours().stripTrailingZeros().toPlainString() + "h");
}
if (!parts.isEmpty()) {
builder.append("").append(String.join(" / ", parts)).append("");
}
if (weeklyMode && worklogAggregate.hasWorkContent()) {
builder.append("").append(String.join("", worklogAggregate.workContents()));
}
return builder.toString();
}
private String buildPlannedStyleLine(String title, String priority, BigDecimal progressRate) {
StringBuilder builder = new StringBuilder();
if (StringUtils.hasText(category)) {
builder.append(category).append(" - ");
}
builder.append(title);
List<String> parts = new ArrayList<>();
if (StringUtils.hasText(priority)) {
parts.add(priority);
}
if (progressRate != null) {
parts.add("进度" + progressRate.stripTrailingZeros().toPlainString() + "%");
}
if (!parts.isEmpty()) {
builder.append("").append(String.join(" / ", parts)).append("");
}
return builder.toString();
}
private String buildTargetText() {
return String.join("\n", lines);
}
private String workItemTitle() {
return workItemTitle;
}
private List<String> lines() {
return lines;
}
}
private static final class TaskWorklogAggregate {
private BigDecimal totalWorkHours = BigDecimal.ZERO;
private final List<String> workContents = new ArrayList<>();
private void merge(TaskWorklogDO worklog) {
totalWorkHours = totalWorkHours.add(
worklog.getDurationHours() == null ? BigDecimal.ZERO : worklog.getDurationHours());
if (StringUtils.hasText(worklog.getWorkContent())) {
workContents.add(worklog.getWorkContent().trim());
}
}
private boolean hasWorkContent() {
return !workContents.isEmpty();
}
private BigDecimal totalWorkHours() {
return totalWorkHours;
}
private List<String> workContents() {
return workContents;
}
}
}

View File

@@ -0,0 +1,4 @@
package com.njcn.rdms.module.project.service.workreport.export;
public record WorkReportExportFile(String filename, String contentType, byte[] content) {
}

View File

@@ -0,0 +1,45 @@
package com.njcn.rdms.module.project.service.workreport.monthly;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportApprovalRecordRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportApproveReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportDefaultDraftReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportExportVO;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportPageReqVO;
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.common.vo.WorkReportStatusActionReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusLogRespVO;
import java.util.List;
public interface MonthlyReportService {
MonthlyReportRespVO initMonthlyReport();
MonthlyReportRespVO previewMonthlyDefaultDraft(MonthlyReportDefaultDraftReqVO reqVO);
Long createMonthlyReport(MonthlyReportSaveReqVO reqVO);
void updateMonthlyReport(Long id, MonthlyReportSaveReqVO reqVO);
MonthlyReportRespVO getMonthlyReport(Long id);
PageResult<MonthlyReportRespVO> getMonthlyReportPage(MonthlyReportPageReqVO reqVO);
PageResult<MonthlyReportRespVO> getMonthlyApprovalPage(MonthlyReportPageReqVO reqVO);
void submitMonthlyReport(Long id);
void approveMonthlyReport(Long id, MonthlyReportApproveReqVO reqVO);
void rejectMonthlyReport(Long id, WorkReportStatusActionReqVO reqVO);
void deleteMonthlyReport(Long id);
List<WorkReportStatusLogRespVO> getMonthlyStatusLogs(Long id);
List<MonthlyReportApprovalRecordRespVO> getMonthlyApprovalRecords(Long id);
List<MonthlyReportExportVO> getMonthlyExportList(MonthlyReportPageReqVO reqVO);
}

View File

@@ -0,0 +1,97 @@
package com.njcn.rdms.module.project.service.workreport.monthly;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportApprovalRecordRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportApproveReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportDefaultDraftReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportExportVO;
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportPageReqVO;
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.common.vo.WorkReportStatusActionReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusLogRespVO;
import com.njcn.rdms.module.project.service.workreport.common.WorkReportCommonService;
import com.njcn.rdms.module.project.service.workreport.defaultdraft.WorkReportDefaultDraftService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class MonthlyReportServiceImpl implements MonthlyReportService {
@Resource
private WorkReportCommonService workReportCommonService;
@Resource
private WorkReportDefaultDraftService workReportDefaultDraftService;
@Override
public MonthlyReportRespVO initMonthlyReport() {
return workReportCommonService.initMonthlyReport();
}
@Override
public MonthlyReportRespVO previewMonthlyDefaultDraft(MonthlyReportDefaultDraftReqVO reqVO) {
return workReportDefaultDraftService.previewMonthlyDefaultDraft(reqVO);
}
@Override
public Long createMonthlyReport(MonthlyReportSaveReqVO reqVO) {
return workReportCommonService.createMonthlyReport(reqVO);
}
@Override
public void updateMonthlyReport(Long id, MonthlyReportSaveReqVO reqVO) {
workReportCommonService.updateMonthlyReport(id, reqVO);
}
@Override
public MonthlyReportRespVO getMonthlyReport(Long id) {
return workReportCommonService.getMonthlyReport(id);
}
@Override
public PageResult<MonthlyReportRespVO> getMonthlyReportPage(MonthlyReportPageReqVO reqVO) {
return workReportCommonService.getMonthlyReportPage(reqVO);
}
@Override
public PageResult<MonthlyReportRespVO> getMonthlyApprovalPage(MonthlyReportPageReqVO reqVO) {
return workReportCommonService.getMonthlyApprovalPage(reqVO);
}
@Override
public void submitMonthlyReport(Long id) {
workReportCommonService.submitMonthlyReport(id);
}
@Override
public void approveMonthlyReport(Long id, MonthlyReportApproveReqVO reqVO) {
workReportCommonService.approveMonthlyReport(id, reqVO);
}
@Override
public void rejectMonthlyReport(Long id, WorkReportStatusActionReqVO reqVO) {
workReportCommonService.rejectMonthlyReport(id, reqVO);
}
@Override
public void deleteMonthlyReport(Long id) {
workReportCommonService.deleteMonthlyReport(id);
}
@Override
public List<WorkReportStatusLogRespVO> getMonthlyStatusLogs(Long id) {
return workReportCommonService.getMonthlyStatusLogs(id);
}
@Override
public List<MonthlyReportApprovalRecordRespVO> getMonthlyApprovalRecords(Long id) {
return workReportCommonService.getMonthlyApprovalRecords(id);
}
@Override
public List<MonthlyReportExportVO> getMonthlyExportList(MonthlyReportPageReqVO reqVO) {
return workReportCommonService.getMonthlyExportList(reqVO);
}
}

View File

@@ -0,0 +1,47 @@
package com.njcn.rdms.module.project.service.workreport.project;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportExportVO;
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportDefaultDraftReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportOwnerProjectOptionRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportPageReqVO;
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.common.vo.WorkReportApprovalRecordRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusActionReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusLogRespVO;
import java.util.List;
public interface ProjectReportService {
List<ProjectReportOwnerProjectOptionRespVO> getOwnerProjectOptions();
ProjectReportRespVO initProjectReport(Long projectId);
ProjectReportRespVO previewProjectDefaultDraft(Long projectId, ProjectReportDefaultDraftReqVO reqVO);
Long createProjectReport(ProjectReportSaveReqVO reqVO);
void updateProjectReport(Long id, ProjectReportSaveReqVO reqVO);
ProjectReportRespVO getProjectReport(Long id);
PageResult<ProjectReportRespVO> getProjectReportPage(ProjectReportPageReqVO reqVO);
PageResult<ProjectReportRespVO> getProjectApprovalPage(ProjectReportPageReqVO reqVO);
void submitProjectReport(Long id);
void approveProjectReport(Long id, WorkReportStatusActionReqVO reqVO);
void rejectProjectReport(Long id, WorkReportStatusActionReqVO reqVO);
void deleteProjectReport(Long id);
List<WorkReportStatusLogRespVO> getProjectStatusLogs(Long id);
List<WorkReportApprovalRecordRespVO> getProjectApprovalRecords(Long id);
List<ProjectReportExportVO> getProjectExportList(ProjectReportPageReqVO reqVO);
}

View File

@@ -0,0 +1,106 @@
package com.njcn.rdms.module.project.service.workreport.project;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportExportVO;
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportDefaultDraftReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportOwnerProjectOptionRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.project.vo.ProjectReportPageReqVO;
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.common.vo.WorkReportApprovalRecordRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusActionReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusLogRespVO;
import com.njcn.rdms.module.project.service.workreport.common.WorkReportCommonService;
import com.njcn.rdms.module.project.service.workreport.defaultdraft.WorkReportDefaultDraftService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ProjectReportServiceImpl implements ProjectReportService {
@Resource
private WorkReportCommonService workReportCommonService;
@Resource
private WorkReportDefaultDraftService workReportDefaultDraftService;
@Override
public List<ProjectReportOwnerProjectOptionRespVO> getOwnerProjectOptions() {
return workReportCommonService.getProjectReportOwnerProjectOptions();
}
@Override
public ProjectReportRespVO initProjectReport(Long projectId) {
workReportCommonService.validateCurrentUserIsProjectReportProjectOwner(projectId);
return workReportCommonService.initProjectReport(projectId);
}
@Override
public ProjectReportRespVO previewProjectDefaultDraft(Long projectId, ProjectReportDefaultDraftReqVO reqVO) {
workReportCommonService.validateCurrentUserIsProjectReportProjectOwner(projectId);
return workReportDefaultDraftService.previewProjectDefaultDraft(projectId, reqVO);
}
@Override
public Long createProjectReport(ProjectReportSaveReqVO reqVO) {
workReportCommonService.validateCurrentUserIsProjectReportProjectOwner(reqVO.getProjectId());
return workReportCommonService.createProjectReport(reqVO);
}
@Override
public void updateProjectReport(Long id, ProjectReportSaveReqVO reqVO) {
workReportCommonService.validateCurrentUserIsProjectReportProjectOwner(reqVO.getProjectId());
workReportCommonService.updateProjectReport(id, reqVO);
}
@Override
public ProjectReportRespVO getProjectReport(Long id) {
return workReportCommonService.getProjectReport(id);
}
@Override
public PageResult<ProjectReportRespVO> getProjectReportPage(ProjectReportPageReqVO reqVO) {
return workReportCommonService.getProjectReportPage(reqVO);
}
@Override
public PageResult<ProjectReportRespVO> getProjectApprovalPage(ProjectReportPageReqVO reqVO) {
return workReportCommonService.getProjectApprovalPage(reqVO);
}
@Override
public void submitProjectReport(Long id) {
workReportCommonService.submitProjectReport(id);
}
@Override
public void approveProjectReport(Long id, WorkReportStatusActionReqVO reqVO) {
workReportCommonService.approveProjectReport(id, reqVO);
}
@Override
public void rejectProjectReport(Long id, WorkReportStatusActionReqVO reqVO) {
workReportCommonService.rejectProjectReport(id, reqVO);
}
@Override
public void deleteProjectReport(Long id) {
workReportCommonService.deleteProjectReport(id);
}
@Override
public List<WorkReportStatusLogRespVO> getProjectStatusLogs(Long id) {
return workReportCommonService.getProjectStatusLogs(id);
}
@Override
public List<WorkReportApprovalRecordRespVO> getProjectApprovalRecords(Long id) {
return workReportCommonService.getProjectApprovalRecords(id);
}
@Override
public List<ProjectReportExportVO> getProjectExportList(ProjectReportPageReqVO reqVO) {
return workReportCommonService.getProjectExportList(reqVO);
}
}

View File

@@ -0,0 +1,44 @@
package com.njcn.rdms.module.project.service.workreport.weekly;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportExportVO;
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportDefaultDraftReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportPageReqVO;
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.common.vo.WorkReportApprovalRecordRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusActionReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusLogRespVO;
import java.util.List;
public interface WeeklyReportService {
WeeklyReportRespVO initWeeklyReport();
WeeklyReportRespVO previewWeeklyDefaultDraft(WeeklyReportDefaultDraftReqVO reqVO);
Long createWeeklyReport(WeeklyReportSaveReqVO reqVO);
void updateWeeklyReport(Long id, WeeklyReportSaveReqVO reqVO);
WeeklyReportRespVO getWeeklyReport(Long id);
PageResult<WeeklyReportRespVO> getWeeklyReportPage(WeeklyReportPageReqVO reqVO);
PageResult<WeeklyReportRespVO> getWeeklyApprovalPage(WeeklyReportPageReqVO reqVO);
void submitWeeklyReport(Long id);
void approveWeeklyReport(Long id, WorkReportStatusActionReqVO reqVO);
void rejectWeeklyReport(Long id, WorkReportStatusActionReqVO reqVO);
void deleteWeeklyReport(Long id);
List<WorkReportStatusLogRespVO> getWeeklyStatusLogs(Long id);
List<WorkReportApprovalRecordRespVO> getWeeklyApprovalRecords(Long id);
List<WeeklyReportExportVO> getWeeklyExportList(WeeklyReportPageReqVO reqVO);
}

View File

@@ -0,0 +1,96 @@
package com.njcn.rdms.module.project.service.workreport.weekly;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportExportVO;
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportDefaultDraftReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.weekly.vo.WeeklyReportPageReqVO;
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.common.vo.WorkReportApprovalRecordRespVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusActionReqVO;
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusLogRespVO;
import com.njcn.rdms.module.project.service.workreport.defaultdraft.WorkReportDefaultDraftService;
import com.njcn.rdms.module.project.service.workreport.common.WorkReportCommonService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class WeeklyReportServiceImpl implements WeeklyReportService {
@Resource
private WorkReportCommonService workReportCommonService;
@Resource
private WorkReportDefaultDraftService workReportDefaultDraftService;
@Override
public WeeklyReportRespVO initWeeklyReport() {
return workReportCommonService.initWeeklyReport();
}
@Override
public WeeklyReportRespVO previewWeeklyDefaultDraft(WeeklyReportDefaultDraftReqVO reqVO) {
return workReportDefaultDraftService.previewWeeklyDefaultDraft(reqVO);
}
@Override
public Long createWeeklyReport(WeeklyReportSaveReqVO reqVO) {
return workReportCommonService.createWeeklyReport(reqVO);
}
@Override
public void updateWeeklyReport(Long id, WeeklyReportSaveReqVO reqVO) {
workReportCommonService.updateWeeklyReport(id, reqVO);
}
@Override
public WeeklyReportRespVO getWeeklyReport(Long id) {
return workReportCommonService.getWeeklyReport(id);
}
@Override
public PageResult<WeeklyReportRespVO> getWeeklyReportPage(WeeklyReportPageReqVO reqVO) {
return workReportCommonService.getWeeklyReportPage(reqVO);
}
@Override
public PageResult<WeeklyReportRespVO> getWeeklyApprovalPage(WeeklyReportPageReqVO reqVO) {
return workReportCommonService.getWeeklyApprovalPage(reqVO);
}
@Override
public void submitWeeklyReport(Long id) {
workReportCommonService.submitWeeklyReport(id);
}
@Override
public void approveWeeklyReport(Long id, WorkReportStatusActionReqVO reqVO) {
workReportCommonService.approveWeeklyReport(id, reqVO);
}
@Override
public void rejectWeeklyReport(Long id, WorkReportStatusActionReqVO reqVO) {
workReportCommonService.rejectWeeklyReport(id, reqVO);
}
@Override
public void deleteWeeklyReport(Long id) {
workReportCommonService.deleteWeeklyReport(id);
}
@Override
public List<WorkReportStatusLogRespVO> getWeeklyStatusLogs(Long id) {
return workReportCommonService.getWeeklyStatusLogs(id);
}
@Override
public List<WorkReportApprovalRecordRespVO> getWeeklyApprovalRecords(Long id) {
return workReportCommonService.getWeeklyApprovalRecords(id);
}
@Override
public List<WeeklyReportExportVO> getWeeklyExportList(WeeklyReportPageReqVO reqVO) {
return workReportCommonService.getWeeklyExportList(reqVO);
}
}