feat(绩效第二阶段、签名管理): 开发绩效第二阶段、下签功能、用户签名管理。
This commit is contained in:
@@ -261,6 +261,15 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode WORK_REPORT_PERIOD_DUPLICATE = new ErrorCode(1_008_010_013, "当前周期的工作报告已存在,请勿重复创建");
|
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_APPROVAL_RECORD_NOT_EXISTS = new ErrorCode(1_008_010_014, "工作报告审核记录不存在");
|
||||||
ErrorCode WORK_REPORT_PROJECT_OWNER_ONLY = new ErrorCode(1_008_010_015, "仅项目负责人可创建或维护该项目的项目半月报");
|
ErrorCode WORK_REPORT_PROJECT_OWNER_ONLY = new ErrorCode(1_008_010_015, "仅项目负责人可创建或维护该项目的项目半月报");
|
||||||
|
ErrorCode WORK_REPORT_SIGN_OFF_NOT_ALLOWED = new ErrorCode(1_008_010_016, "当前月报未处于待员工确认状态");
|
||||||
|
ErrorCode WORK_REPORT_SIGN_OFF_BATCH_LOCKED = new ErrorCode(1_008_010_017, "该月份已下签,禁止重复操作");
|
||||||
|
ErrorCode WORK_REPORT_MONTHLY_SIGN_OFF_NOT_EXISTS = new ErrorCode(1_008_010_018, "月报下签实例不存在");
|
||||||
|
ErrorCode WORK_REPORT_MONTHLY_SIGN_OFF_CONFIRM_ONLY_REPORTER = new ErrorCode(1_008_010_019, "仅月报填报人可确认下签");
|
||||||
|
ErrorCode WORK_REPORT_MONTHLY_SIGN_OFF_APPROVAL_RECORD_NOT_EXISTS = new ErrorCode(1_008_010_020, "月报缺少审批通过记录,无法完成下签确认");
|
||||||
|
ErrorCode WORK_REPORT_MONTHLY_SIGN_OFF_CANDIDATE_EMPTY = new ErrorCode(1_008_010_021, "没有可下签的月报数据");
|
||||||
|
ErrorCode SIGN_OFF_STATUS_ACTION_NOT_ALLOWED = new ErrorCode(1_008_010_022, "当前下签状态为「{}」,不支持「{}」操作");
|
||||||
|
ErrorCode SIGN_OFF_STATUS_ACTION_REASON_REQUIRED = new ErrorCode(1_008_010_023, "「{}」操作必须填写原因");
|
||||||
|
ErrorCode SIGN_OFF_STATUS_MODEL_NOT_EXISTS_OR_DISABLED = new ErrorCode(1_008_010_024, "下签状态定义不存在或已停用");
|
||||||
|
|
||||||
// ========== 绩效管理 1_008_011_xxx ==========
|
// ========== 绩效管理 1_008_011_xxx ==========
|
||||||
ErrorCode PERFORMANCE_TEMPLATE_NOT_EXISTS = new ErrorCode(1_008_011_001, "绩效模板不存在");
|
ErrorCode PERFORMANCE_TEMPLATE_NOT_EXISTS = new ErrorCode(1_008_011_001, "绩效模板不存在");
|
||||||
@@ -282,4 +291,12 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode PERFORMANCE_SHEET_STATUS_MODEL_NOT_EXISTS_OR_DISABLED = new ErrorCode(1_008_011_017, "绩效表状态定义不存在或已停用");
|
ErrorCode PERFORMANCE_SHEET_STATUS_MODEL_NOT_EXISTS_OR_DISABLED = new ErrorCode(1_008_011_017, "绩效表状态定义不存在或已停用");
|
||||||
ErrorCode PERFORMANCE_SHEET_STATUS_ACTION_REASON_REQUIRED = new ErrorCode(1_008_011_018, "「{}」操作必须填写原因");
|
ErrorCode PERFORMANCE_SHEET_STATUS_ACTION_REASON_REQUIRED = new ErrorCode(1_008_011_018, "「{}」操作必须填写原因");
|
||||||
ErrorCode PERFORMANCE_EMPLOYEE_DEPT_INVALID = new ErrorCode(1_008_011_019, "被考核员工部门信息不完整");
|
ErrorCode PERFORMANCE_EMPLOYEE_DEPT_INVALID = new ErrorCode(1_008_011_019, "被考核员工部门信息不完整");
|
||||||
|
ErrorCode PERFORMANCE_SHEET_SIGN_OFF_NOT_ALLOWED = new ErrorCode(1_008_011_020, "当前绩效表未处于待员工确认状态");
|
||||||
|
ErrorCode PERFORMANCE_SHEET_SIGN_OFF_BATCH_LOCKED = new ErrorCode(1_008_011_021, "该月份已下签,禁止重复操作");
|
||||||
|
ErrorCode PERFORMANCE_SHEET_SIGN_OFF_NOT_EXISTS = new ErrorCode(1_008_011_022, "绩效下签实例不存在");
|
||||||
|
ErrorCode PERFORMANCE_SHEET_IMPORT_ZIP_EMPTY = new ErrorCode(1_008_011_023, "导入压缩包不能为空");
|
||||||
|
ErrorCode PERFORMANCE_SHEET_IMPORT_TARGET_EMPTY = new ErrorCode(1_008_011_024, "没有匹配到可导入的绩效表");
|
||||||
|
ErrorCode PERFORMANCE_SHEET_SIGN_OFF_CANDIDATE_EMPTY = new ErrorCode(1_008_011_025, "没有可下签的绩效表数据");
|
||||||
|
ErrorCode PERFORMANCE_SHEET_MONTHLY_REPORT_NOT_EXISTS = new ErrorCode(1_008_011_026, "未找到对应月报,无法同步绩效结果");
|
||||||
|
ErrorCode PERFORMANCE_SHEET_MONTHLY_APPROVAL_RECORD_NOT_EXISTS = new ErrorCode(1_008_011_027, "未找到对应月报审批记录,无法同步绩效结果");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,4 +36,6 @@ public final class PerformanceConstants {
|
|||||||
public static final String PERMISSION_SHEET_REJECT = "project:performance-sheet:reject";
|
public static final String PERMISSION_SHEET_REJECT = "project:performance-sheet:reject";
|
||||||
public static final String PERMISSION_SHEET_EXPORT = "project:performance-sheet:export";
|
public static final String PERMISSION_SHEET_EXPORT = "project:performance-sheet:export";
|
||||||
public static final String PERMISSION_TEAM_DASHBOARD = "project:performance-sheet:team-dashboard";
|
public static final String PERMISSION_TEAM_DASHBOARD = "project:performance-sheet:team-dashboard";
|
||||||
|
public static final String PERMISSION_SHEET_IMPORT = "project:performance-sheet:import";
|
||||||
|
public static final String PERMISSION_SHEET_SIGN_OFF = "project:performance-sheet:sign-off";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.njcn.rdms.module.project.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 员工下签常量。
|
||||||
|
*/
|
||||||
|
public final class SignOffConstants {
|
||||||
|
|
||||||
|
private SignOffConstants() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String STATUS_OBJECT_TYPE = "employee_sign_off";
|
||||||
|
|
||||||
|
public static final String STATUS_NOT_STARTED = "not_started";
|
||||||
|
public static final String STATUS_PENDING_EMPLOYEE_CONFIRM = "pending_employee_confirm";
|
||||||
|
public static final String STATUS_EMPLOYEE_CONFIRMED = "employee_confirmed";
|
||||||
|
public static final String STATUS_EMPLOYEE_REJECTED = "employee_rejected";
|
||||||
|
|
||||||
|
public static final String ACTION_ISSUE = "issue";
|
||||||
|
public static final String ACTION_CONFIRM = "confirm";
|
||||||
|
public static final String ACTION_REJECT = "reject";
|
||||||
|
}
|
||||||
@@ -39,4 +39,6 @@ public final class WorkReportConstants {
|
|||||||
public static final String PERMISSION_EXPORT = "project:work-report:export";
|
public static final String PERMISSION_EXPORT = "project:work-report:export";
|
||||||
public static final String PERMISSION_PROJECT_OWNER = "project:work-report:project-owner";
|
public static final String PERMISSION_PROJECT_OWNER = "project:work-report:project-owner";
|
||||||
public static final String PERMISSION_TEAM_DASHBOARD = "project:work-report:team-dashboard";
|
public static final String PERMISSION_TEAM_DASHBOARD = "project:work-report:team-dashboard";
|
||||||
|
public static final String PERMISSION_SIGN_OFF_QUERY = "project:work-report:sign-off-query";
|
||||||
|
public static final String PERMISSION_SIGN_OFF_CONFIRM = "project:work-report:sign-off-confirm";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,13 @@ import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceM
|
|||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetBatchDownloadReqVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetBatchDownloadReqVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetCreateReqVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetCreateReqVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetExcelUpdateReqVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetExcelUpdateReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetImportZipReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetImportZipRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetPageReqVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetPageReqVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetPrefillRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetPrefillRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetResponseRecordRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetResponseRecordRespVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetSignOffReqVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusActionReqVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusActionReqVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusDictRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusDictRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusLogRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusLogRespVO;
|
||||||
@@ -124,6 +127,21 @@ public class PerformanceSheetController {
|
|||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/import-zip")
|
||||||
|
@Operation(summary = "导入绩效压缩包")
|
||||||
|
@PreAuthorize("@ss.hasPermission('" + PerformanceConstants.PERMISSION_SHEET_IMPORT + "')")
|
||||||
|
public CommonResult<PerformanceSheetImportZipRespVO> importZip(@Valid PerformanceSheetImportZipReqVO reqVO)
|
||||||
|
throws Exception {
|
||||||
|
return success(performanceSheetService.importZip(reqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/sign-off")
|
||||||
|
@Operation(summary = "一键下签")
|
||||||
|
@PreAuthorize("@ss.hasPermission('" + PerformanceConstants.PERMISSION_SHEET_SIGN_OFF + "')")
|
||||||
|
public CommonResult<Long> signOff(@Valid @RequestBody PerformanceSheetSignOffReqVO reqVO) {
|
||||||
|
return success(performanceSheetService.signOff(reqVO));
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/{id}/download")
|
@GetMapping("/{id}/download")
|
||||||
@Operation(summary = "下载单条绩效表")
|
@Operation(summary = "下载单条绩效表")
|
||||||
@PreAuthorize("@ss.hasPermission('" + PerformanceConstants.PERMISSION_SHEET_EXPORT + "')")
|
@PreAuthorize("@ss.hasPermission('" + PerformanceConstants.PERMISSION_SHEET_EXPORT + "')")
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.njcn.rdms.module.project.controller.admin.performance.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.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 绩效压缩包导入 Request VO")
|
||||||
|
@Data
|
||||||
|
public class PerformanceSheetImportZipReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "zip 文件", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotNull(message = "导入文件不能为空")
|
||||||
|
private MultipartFile file;
|
||||||
|
|
||||||
|
@Schema(description = "绩效月份,格式 yyyy-MM", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026-06")
|
||||||
|
@NotBlank(message = "绩效月份不能为空")
|
||||||
|
private String periodMonth;
|
||||||
|
|
||||||
|
@Schema(description = "限定员工 ID 列表")
|
||||||
|
private List<Long> employeeIds;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.njcn.rdms.module.project.controller.admin.performance.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 绩效压缩包导入结果 Response VO")
|
||||||
|
@Data
|
||||||
|
public class PerformanceSheetImportZipRespVO {
|
||||||
|
|
||||||
|
private Integer workbookCount;
|
||||||
|
|
||||||
|
private Integer sheetCount;
|
||||||
|
|
||||||
|
private Integer successCount;
|
||||||
|
|
||||||
|
private Integer skippedCount;
|
||||||
|
|
||||||
|
private Integer failedCount;
|
||||||
|
|
||||||
|
private List<String> messages;
|
||||||
|
}
|
||||||
@@ -38,4 +38,7 @@ public class PerformanceSheetPageReqVO extends PageParam {
|
|||||||
|
|
||||||
@Schema(description = "状态编码", example = "sent")
|
@Schema(description = "状态编码", example = "sent")
|
||||||
private String statusCode;
|
private String statusCode;
|
||||||
|
|
||||||
|
@Schema(description = "下签状态编码", example = "pending_employee_confirm")
|
||||||
|
private String signOffStatus;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ public class PerformanceSheetRespVO {
|
|||||||
private Integer fileVersion;
|
private Integer fileVersion;
|
||||||
private String statusCode;
|
private String statusCode;
|
||||||
private String statusName;
|
private String statusName;
|
||||||
|
private String signOffStatus;
|
||||||
|
private String signOffStatusName;
|
||||||
private BigDecimal actualScoreTotal;
|
private BigDecimal actualScoreTotal;
|
||||||
private BigDecimal baseScoreTotal;
|
private BigDecimal baseScoreTotal;
|
||||||
private BigDecimal extraScoreTotal;
|
private BigDecimal extraScoreTotal;
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.njcn.rdms.module.project.controller.admin.performance.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 绩效一键下签 Request VO")
|
||||||
|
@Data
|
||||||
|
public class PerformanceSheetSignOffReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "绩效月份,格式 yyyy-MM", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026-06")
|
||||||
|
@NotBlank(message = "绩效月份不能为空")
|
||||||
|
private String periodMonth;
|
||||||
|
|
||||||
|
@Schema(description = "员工 ID 列表;为空则默认全部下属")
|
||||||
|
private List<Long> employeeIds;
|
||||||
|
|
||||||
|
@Schema(description = "备注")
|
||||||
|
@Size(max = 500, message = "备注长度不能超过 500 个字符")
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@@ -17,6 +17,8 @@ import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.Month
|
|||||||
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportRefreshDraftReqVO;
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportRefreshDraftReqVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportRespVO;
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportSaveReqVO;
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportSaveReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportSignOffConfirmReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportSignOffDetailRespVO;
|
||||||
import com.njcn.rdms.module.project.service.workreport.export.WorkReportContentExportService;
|
import com.njcn.rdms.module.project.service.workreport.export.WorkReportContentExportService;
|
||||||
import com.njcn.rdms.module.project.service.workreport.monthly.MonthlyReportService;
|
import com.njcn.rdms.module.project.service.workreport.monthly.MonthlyReportService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@@ -111,6 +113,20 @@ public class MonthlyReportController {
|
|||||||
return success(monthlyReportService.getMonthlyApprovalPage(reqVO));
|
return success(monthlyReportService.getMonthlyApprovalPage(reqVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/sign-off-page")
|
||||||
|
@Operation(summary = "获取待我确认的月报分页")
|
||||||
|
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_SIGN_OFF_QUERY + "')")
|
||||||
|
public CommonResult<PageResult<MonthlyReportRespVO>> getMonthlySignOffPage(@Valid MonthlyReportPageReqVO reqVO) {
|
||||||
|
return success(monthlyReportService.getMonthlySignOffPage(reqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}/sign-off-detail")
|
||||||
|
@Operation(summary = "获取月报下签详情")
|
||||||
|
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_SIGN_OFF_QUERY + "')")
|
||||||
|
public CommonResult<MonthlyReportSignOffDetailRespVO> getMonthlySignOffDetail(@PathVariable("id") Long id) {
|
||||||
|
return success(monthlyReportService.getMonthlySignOffDetail(id));
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/{id}/submit")
|
@PostMapping("/{id}/submit")
|
||||||
@Operation(summary = "提交月报")
|
@Operation(summary = "提交月报")
|
||||||
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_UPDATE + "')")
|
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_UPDATE + "')")
|
||||||
@@ -137,6 +153,15 @@ public class MonthlyReportController {
|
|||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{id}/confirm-sign-off")
|
||||||
|
@Operation(summary = "确认月报下签")
|
||||||
|
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_SIGN_OFF_CONFIRM + "')")
|
||||||
|
public CommonResult<Boolean> confirmMonthlySignOff(@PathVariable("id") Long id,
|
||||||
|
@Valid @RequestBody MonthlyReportSignOffConfirmReqVO reqVO) {
|
||||||
|
monthlyReportService.confirmMonthlySignOff(id, reqVO);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
@Operation(summary = "删除月报")
|
@Operation(summary = "删除月报")
|
||||||
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_DELETE + "')")
|
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_DELETE + "')")
|
||||||
|
|||||||
@@ -36,10 +36,14 @@ public class MonthlyReportApprovalRecordRespVO {
|
|||||||
|
|
||||||
private String employeeSignName;
|
private String employeeSignName;
|
||||||
|
|
||||||
|
private Long employeeSignatureFileId;
|
||||||
|
|
||||||
private LocalDate employeeSignedDate;
|
private LocalDate employeeSignedDate;
|
||||||
|
|
||||||
private String supervisorSignName;
|
private String supervisorSignName;
|
||||||
|
|
||||||
|
private Long supervisorSignatureFileId;
|
||||||
|
|
||||||
private LocalDate supervisorSignedDate;
|
private LocalDate supervisorSignedDate;
|
||||||
|
|
||||||
private Long auditorUserId;
|
private Long auditorUserId;
|
||||||
|
|||||||
@@ -14,4 +14,7 @@ public class MonthlyReportPageReqVO extends WorkReportBasePageReqVO {
|
|||||||
|
|
||||||
@Schema(description = "团队视角下的填报人用户编号列表")
|
@Schema(description = "团队视角下的填报人用户编号列表")
|
||||||
private List<Long> reporterIds;
|
private List<Long> reporterIds;
|
||||||
|
|
||||||
|
@Schema(description = "下签状态编码", example = "pending_employee_confirm")
|
||||||
|
private String signOffStatus;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ public class MonthlyReportRespVO {
|
|||||||
private LocalDate periodEndDate;
|
private LocalDate periodEndDate;
|
||||||
private String statusCode;
|
private String statusCode;
|
||||||
private String statusName;
|
private String statusName;
|
||||||
|
private String signOffStatus;
|
||||||
|
private String signOffStatusName;
|
||||||
private Boolean allowEdit;
|
private Boolean allowEdit;
|
||||||
private Boolean terminal;
|
private Boolean terminal;
|
||||||
private BigDecimal totalWorkHours;
|
private BigDecimal totalWorkHours;
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
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 MonthlyReportSignOffConfirmReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "面谈日期", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotNull(message = "面谈日期不能为空")
|
||||||
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||||
|
private LocalDate meetingDate;
|
||||||
|
|
||||||
|
@Schema(description = "员工签字日期")
|
||||||
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||||
|
private LocalDate employeeSignedDate;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 月报下签详情 Response VO")
|
||||||
|
@Data
|
||||||
|
public class MonthlyReportSignOffDetailRespVO {
|
||||||
|
|
||||||
|
private MonthlyReportRespVO report;
|
||||||
|
|
||||||
|
private MonthlyReportApprovalRecordRespVO latestApprovalRecord;
|
||||||
|
}
|
||||||
@@ -46,6 +46,8 @@ public class PerformanceSheetDO extends BaseDO {
|
|||||||
|
|
||||||
private String statusCode;
|
private String statusCode;
|
||||||
|
|
||||||
|
private String signOffStatus;
|
||||||
|
|
||||||
private BigDecimal actualScoreTotal;
|
private BigDecimal actualScoreTotal;
|
||||||
|
|
||||||
private BigDecimal baseScoreTotal;
|
private BigDecimal baseScoreTotal;
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.njcn.rdms.module.project.dal.dataobject.performance;
|
||||||
|
|
||||||
|
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.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绩效下签当前实例。
|
||||||
|
*/
|
||||||
|
@TableName("rdms_performance_sheet_sign_off")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class PerformanceSheetSignOffDO extends BaseDO {
|
||||||
|
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private Long performanceSheetId;
|
||||||
|
|
||||||
|
private Long batchNo;
|
||||||
|
|
||||||
|
private String statusCode;
|
||||||
|
|
||||||
|
private Long issueUserId;
|
||||||
|
|
||||||
|
private String issueUserName;
|
||||||
|
|
||||||
|
private LocalDateTime issueTime;
|
||||||
|
|
||||||
|
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||||
|
private Long confirmUserId;
|
||||||
|
|
||||||
|
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||||
|
private String confirmUserName;
|
||||||
|
|
||||||
|
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||||
|
private LocalDateTime confirmTime;
|
||||||
|
|
||||||
|
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||||
|
private String lastRejectReason;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.njcn.rdms.module.project.dal.dataobject.performance;
|
||||||
|
|
||||||
|
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_performance_sheet_sign_off_record")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class PerformanceSheetSignOffRecordDO extends BaseDO {
|
||||||
|
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private Long signOffId;
|
||||||
|
|
||||||
|
private Long performanceSheetId;
|
||||||
|
|
||||||
|
private Long batchNo;
|
||||||
|
|
||||||
|
private String actionType;
|
||||||
|
|
||||||
|
private String fromSignOffStatus;
|
||||||
|
|
||||||
|
private String toSignOffStatus;
|
||||||
|
|
||||||
|
private String reason;
|
||||||
|
|
||||||
|
private Long operatorUserId;
|
||||||
|
|
||||||
|
private String operatorName;
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.njcn.rdms.module.project.dal.dataobject.signoff;
|
||||||
|
|
||||||
|
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_employee_sign_off_batch")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class EmployeeSignOffBatchDO extends BaseDO {
|
||||||
|
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String periodMonth;
|
||||||
|
|
||||||
|
private Long deptId;
|
||||||
|
|
||||||
|
private String deptName;
|
||||||
|
|
||||||
|
private Long operatorUserId;
|
||||||
|
|
||||||
|
private String operatorName;
|
||||||
|
|
||||||
|
private Integer lockedFlag;
|
||||||
|
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@@ -56,12 +56,18 @@ public class MonthlyReportApprovalRecordDO extends BaseDO {
|
|||||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||||
private String employeeSignName;
|
private String employeeSignName;
|
||||||
|
|
||||||
|
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||||
|
private Long employeeSignatureFileId;
|
||||||
|
|
||||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||||
private LocalDate employeeSignedDate;
|
private LocalDate employeeSignedDate;
|
||||||
|
|
||||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||||
private String supervisorSignName;
|
private String supervisorSignName;
|
||||||
|
|
||||||
|
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||||
|
private Long supervisorSignatureFileId;
|
||||||
|
|
||||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||||
private LocalDate supervisorSignedDate;
|
private LocalDate supervisorSignedDate;
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ public class MonthlyReportDO extends BaseDO {
|
|||||||
|
|
||||||
private String statusCode;
|
private String statusCode;
|
||||||
|
|
||||||
|
private String signOffStatus;
|
||||||
|
|
||||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||||
private BigDecimal totalWorkHours;
|
private BigDecimal totalWorkHours;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
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.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 月报下签当前实例。
|
||||||
|
*/
|
||||||
|
@TableName("rdms_work_report_monthly_sign_off")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class MonthlyReportSignOffDO extends BaseDO {
|
||||||
|
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private Long monthlyReportId;
|
||||||
|
|
||||||
|
private Long batchNo;
|
||||||
|
|
||||||
|
private String statusCode;
|
||||||
|
|
||||||
|
private Long issueUserId;
|
||||||
|
|
||||||
|
private String issueUserName;
|
||||||
|
|
||||||
|
private LocalDateTime issueTime;
|
||||||
|
|
||||||
|
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||||
|
private Long confirmUserId;
|
||||||
|
|
||||||
|
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||||
|
private String confirmUserName;
|
||||||
|
|
||||||
|
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||||
|
private LocalDateTime confirmTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.njcn.rdms.module.project.dal.dataobject.workreport.monthly;
|
||||||
|
|
||||||
|
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_monthly_sign_off_record")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class MonthlyReportSignOffRecordDO extends BaseDO {
|
||||||
|
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private Long signOffId;
|
||||||
|
|
||||||
|
private Long monthlyReportId;
|
||||||
|
|
||||||
|
private Long approvalRecordId;
|
||||||
|
|
||||||
|
private Long batchNo;
|
||||||
|
|
||||||
|
private String actionType;
|
||||||
|
|
||||||
|
private String fromSignOffStatus;
|
||||||
|
|
||||||
|
private String toSignOffStatus;
|
||||||
|
|
||||||
|
private Long operatorUserId;
|
||||||
|
|
||||||
|
private String operatorName;
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.njcn.rdms.module.project.dal.mysql.performance;
|
package com.njcn.rdms.module.project.dal.mysql.performance;
|
||||||
|
|
||||||
import com.njcn.rdms.framework.common.pojo.PageResult;
|
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.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import com.njcn.rdms.module.project.constant.PerformanceConstants;
|
import com.njcn.rdms.module.project.constant.PerformanceConstants;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetPageReqVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetPageReqVO;
|
||||||
import com.njcn.rdms.module.project.dal.dataobject.performance.PerformanceSheetDO;
|
import com.njcn.rdms.module.project.dal.dataobject.performance.PerformanceSheetDO;
|
||||||
@@ -102,6 +102,14 @@ public interface PerformanceSheetMapper extends BaseMapperX<PerformanceSheetDO>
|
|||||||
.eq(PerformanceSheetDO::getStatusCode, fromStatus));
|
.eq(PerformanceSheetDO::getStatusCode, fromStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default int updateByIdAndStatusAndSignOffStatus(PerformanceSheetDO update, Long id, String fromStatus,
|
||||||
|
String fromSignOffStatus) {
|
||||||
|
return update(update, new LambdaQueryWrapperX<PerformanceSheetDO>()
|
||||||
|
.eq(PerformanceSheetDO::getId, id)
|
||||||
|
.eq(PerformanceSheetDO::getStatusCode, fromStatus)
|
||||||
|
.eq(PerformanceSheetDO::getSignOffStatus, fromSignOffStatus));
|
||||||
|
}
|
||||||
|
|
||||||
private LambdaQueryWrapperX<PerformanceSheetDO> buildPageQuery(PerformanceSheetPageReqVO reqVO) {
|
private LambdaQueryWrapperX<PerformanceSheetDO> buildPageQuery(PerformanceSheetPageReqVO reqVO) {
|
||||||
return new LambdaQueryWrapperX<PerformanceSheetDO>()
|
return new LambdaQueryWrapperX<PerformanceSheetDO>()
|
||||||
.geIfPresent(PerformanceSheetDO::getPeriodMonth, reqVO.getPeriodMonthStart())
|
.geIfPresent(PerformanceSheetDO::getPeriodMonth, reqVO.getPeriodMonthStart())
|
||||||
@@ -111,6 +119,7 @@ public interface PerformanceSheetMapper extends BaseMapperX<PerformanceSheetDO>
|
|||||||
.likeIfPresent(PerformanceSheetDO::getEmployeeDeptName, reqVO.getEmployeeDeptName())
|
.likeIfPresent(PerformanceSheetDO::getEmployeeDeptName, reqVO.getEmployeeDeptName())
|
||||||
.eqIfPresent(PerformanceSheetDO::getManagerId, reqVO.getManagerId())
|
.eqIfPresent(PerformanceSheetDO::getManagerId, reqVO.getManagerId())
|
||||||
.likeIfPresent(PerformanceSheetDO::getManagerName, reqVO.getManagerName())
|
.likeIfPresent(PerformanceSheetDO::getManagerName, reqVO.getManagerName())
|
||||||
.eqIfPresent(PerformanceSheetDO::getStatusCode, reqVO.getStatusCode());
|
.eqIfPresent(PerformanceSheetDO::getStatusCode, reqVO.getStatusCode())
|
||||||
|
.eqIfPresent(PerformanceSheetDO::getSignOffStatus, reqVO.getSignOffStatus());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.njcn.rdms.module.project.dal.mysql.performance;
|
||||||
|
|
||||||
|
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.performance.PerformanceSheetSignOffDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface PerformanceSheetSignOffMapper extends BaseMapperX<PerformanceSheetSignOffDO> {
|
||||||
|
|
||||||
|
default PerformanceSheetSignOffDO selectByPerformanceSheetId(Long performanceSheetId) {
|
||||||
|
return selectOne(new LambdaQueryWrapperX<PerformanceSheetSignOffDO>()
|
||||||
|
.eq(PerformanceSheetSignOffDO::getPerformanceSheetId, performanceSheetId));
|
||||||
|
}
|
||||||
|
|
||||||
|
default int updateByPerformanceSheetIdAndStatus(PerformanceSheetSignOffDO update, Long performanceSheetId,
|
||||||
|
String fromStatus) {
|
||||||
|
return update(update, new LambdaQueryWrapperX<PerformanceSheetSignOffDO>()
|
||||||
|
.eq(PerformanceSheetSignOffDO::getPerformanceSheetId, performanceSheetId)
|
||||||
|
.eq(PerformanceSheetSignOffDO::getStatusCode, fromStatus));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.njcn.rdms.module.project.dal.mysql.performance;
|
||||||
|
|
||||||
|
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import com.njcn.rdms.module.project.dal.dataobject.performance.PerformanceSheetSignOffRecordDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface PerformanceSheetSignOffRecordMapper extends BaseMapperX<PerformanceSheetSignOffRecordDO> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.njcn.rdms.module.project.dal.mysql.signoff;
|
||||||
|
|
||||||
|
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.signoff.EmployeeSignOffBatchDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface EmployeeSignOffBatchMapper extends BaseMapperX<EmployeeSignOffBatchDO> {
|
||||||
|
|
||||||
|
default EmployeeSignOffBatchDO selectByPeriodMonthAndDeptId(String periodMonth, Long deptId) {
|
||||||
|
return selectOne(new LambdaQueryWrapperX<EmployeeSignOffBatchDO>()
|
||||||
|
.eq(EmployeeSignOffBatchDO::getPeriodMonth, periodMonth)
|
||||||
|
.eq(EmployeeSignOffBatchDO::getDeptId, deptId));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,4 +26,13 @@ public interface MonthlyReportApprovalRecordMapper extends BaseMapperX<MonthlyRe
|
|||||||
return delete(new LambdaQueryWrapperX<MonthlyReportApprovalRecordDO>()
|
return delete(new LambdaQueryWrapperX<MonthlyReportApprovalRecordDO>()
|
||||||
.eq(MonthlyReportApprovalRecordDO::getMonthlyReportId, monthlyReportId));
|
.eq(MonthlyReportApprovalRecordDO::getMonthlyReportId, monthlyReportId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default MonthlyReportApprovalRecordDO selectLatestApprovedByMonthlyReportId(Long monthlyReportId) {
|
||||||
|
return selectOne(new LambdaQueryWrapperX<MonthlyReportApprovalRecordDO>()
|
||||||
|
.eq(MonthlyReportApprovalRecordDO::getMonthlyReportId, monthlyReportId)
|
||||||
|
.eq(MonthlyReportApprovalRecordDO::getConclusion, "approved")
|
||||||
|
.orderByDesc(MonthlyReportApprovalRecordDO::getApprovalRound)
|
||||||
|
.orderByDesc(MonthlyReportApprovalRecordDO::getId)
|
||||||
|
.last("LIMIT 1"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,6 +147,14 @@ public interface MonthlyReportMapper extends BaseMapperX<MonthlyReportDO> {
|
|||||||
.eq(MonthlyReportDO::getStatusCode, fromStatus));
|
.eq(MonthlyReportDO::getStatusCode, fromStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default int updateByIdAndStatusAndSignOffStatus(MonthlyReportDO update, Long id, String fromStatus,
|
||||||
|
String fromSignOffStatus) {
|
||||||
|
return update(update, new LambdaQueryWrapperX<MonthlyReportDO>()
|
||||||
|
.eq(MonthlyReportDO::getId, id)
|
||||||
|
.eq(MonthlyReportDO::getStatusCode, fromStatus)
|
||||||
|
.eq(MonthlyReportDO::getSignOffStatus, fromSignOffStatus));
|
||||||
|
}
|
||||||
|
|
||||||
default int updateByIdAndStatusesAndReporterId(MonthlyReportDO update, Long id, Collection<String> statuses,
|
default int updateByIdAndStatusesAndReporterId(MonthlyReportDO update, Long id, Collection<String> statuses,
|
||||||
Long reporterId) {
|
Long reporterId) {
|
||||||
return update(update, new LambdaQueryWrapperX<MonthlyReportDO>()
|
return update(update, new LambdaQueryWrapperX<MonthlyReportDO>()
|
||||||
@@ -177,6 +185,7 @@ public interface MonthlyReportMapper extends BaseMapperX<MonthlyReportDO> {
|
|||||||
private LambdaQueryWrapperX<MonthlyReportDO> buildPageQuery(MonthlyReportPageReqVO reqVO) {
|
private LambdaQueryWrapperX<MonthlyReportDO> buildPageQuery(MonthlyReportPageReqVO reqVO) {
|
||||||
LambdaQueryWrapperX<MonthlyReportDO> wrapper = new LambdaQueryWrapperX<MonthlyReportDO>()
|
LambdaQueryWrapperX<MonthlyReportDO> wrapper = new LambdaQueryWrapperX<MonthlyReportDO>()
|
||||||
.eqIfPresent(MonthlyReportDO::getStatusCode, reqVO.getStatusCode())
|
.eqIfPresent(MonthlyReportDO::getStatusCode, reqVO.getStatusCode())
|
||||||
|
.eqIfPresent(MonthlyReportDO::getSignOffStatus, reqVO.getSignOffStatus())
|
||||||
.betweenIfPresent(MonthlyReportDO::getPeriodStartDate, reqVO.getPeriodStartDate())
|
.betweenIfPresent(MonthlyReportDO::getPeriodStartDate, reqVO.getPeriodStartDate())
|
||||||
.betweenIfPresent(MonthlyReportDO::getSubmitTime, reqVO.getSubmitTime());
|
.betweenIfPresent(MonthlyReportDO::getSubmitTime, reqVO.getSubmitTime());
|
||||||
if (StringUtils.hasText(reqVO.getKeyword())) {
|
if (StringUtils.hasText(reqVO.getKeyword())) {
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
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.MonthlyReportSignOffDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface MonthlyReportSignOffMapper extends BaseMapperX<MonthlyReportSignOffDO> {
|
||||||
|
|
||||||
|
default MonthlyReportSignOffDO selectByMonthlyReportId(Long monthlyReportId) {
|
||||||
|
return selectOne(new LambdaQueryWrapperX<MonthlyReportSignOffDO>()
|
||||||
|
.eq(MonthlyReportSignOffDO::getMonthlyReportId, monthlyReportId));
|
||||||
|
}
|
||||||
|
|
||||||
|
default int updateByMonthlyReportIdAndStatus(MonthlyReportSignOffDO update, Long monthlyReportId,
|
||||||
|
String fromStatus) {
|
||||||
|
return update(update, new LambdaQueryWrapperX<MonthlyReportSignOffDO>()
|
||||||
|
.eq(MonthlyReportSignOffDO::getMonthlyReportId, monthlyReportId)
|
||||||
|
.eq(MonthlyReportSignOffDO::getStatusCode, fromStatus));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.njcn.rdms.module.project.dal.mysql.workreport.monthly;
|
||||||
|
|
||||||
|
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportSignOffRecordDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface MonthlyReportSignOffRecordMapper extends BaseMapperX<MonthlyReportSignOffRecordDO> {
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ 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 com.njcn.rdms.module.system.api.user.UserManagementRelationApi;
|
||||||
|
import com.njcn.rdms.module.system.api.user.UserSignatureApi;
|
||||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
@@ -22,6 +23,6 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
{AdminUserApi.class, ObjectPermissionApi.class, DictDataApi.class, FileApi.class,
|
{AdminUserApi.class, ObjectPermissionApi.class, DictDataApi.class, FileApi.class,
|
||||||
PermissionApi.class, OrgLeaderApi.class, UserVisibilityConfigApi.class,
|
PermissionApi.class, OrgLeaderApi.class, UserVisibilityConfigApi.class,
|
||||||
DeptApi.class, PostApi.class, UserManagementRelationApi.class,
|
DeptApi.class, PostApi.class, UserManagementRelationApi.class,
|
||||||
NotifyMessageSendApi.class})
|
NotifyMessageSendApi.class, UserSignatureApi.class})
|
||||||
public class RpcConfiguration {
|
public class RpcConfiguration {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,13 @@ import com.njcn.rdms.framework.common.pojo.PageResult;
|
|||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceMonthlyResultRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceMonthlyResultRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetCreateReqVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetCreateReqVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetExcelUpdateReqVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetExcelUpdateReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetImportZipReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetImportZipRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetPageReqVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetPageReqVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetPrefillRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetPrefillRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetResponseRecordRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetResponseRecordRespVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetSignOffReqVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusActionReqVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusActionReqVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusDictRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusDictRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusLogRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusLogRespVO;
|
||||||
@@ -36,6 +39,10 @@ public interface PerformanceSheetService {
|
|||||||
|
|
||||||
void reject(Long id, PerformanceSheetStatusActionReqVO reqVO);
|
void reject(Long id, PerformanceSheetStatusActionReqVO reqVO);
|
||||||
|
|
||||||
|
PerformanceSheetImportZipRespVO importZip(PerformanceSheetImportZipReqVO reqVO) throws Exception;
|
||||||
|
|
||||||
|
Long signOff(PerformanceSheetSignOffReqVO reqVO);
|
||||||
|
|
||||||
PerformanceDownloadFile download(Long id);
|
PerformanceDownloadFile download(Long id);
|
||||||
|
|
||||||
PerformanceDownloadFile batchDownload(Collection<Long> ids);
|
PerformanceDownloadFile batchDownload(Collection<Long> ids);
|
||||||
|
|||||||
@@ -6,37 +6,52 @@ 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.PerformanceExcelCellConstants;
|
import com.njcn.rdms.module.project.constant.PerformanceExcelCellConstants;
|
||||||
import com.njcn.rdms.module.project.constant.PerformanceConstants;
|
import com.njcn.rdms.module.project.constant.PerformanceConstants;
|
||||||
|
import com.njcn.rdms.module.project.constant.SignOffConstants;
|
||||||
|
import com.njcn.rdms.module.project.constant.WorkReportConstants;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceMonthlyResultRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceMonthlyResultRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetCreateReqVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetCreateReqVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetExcelUpdateReqVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetExcelUpdateReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetImportZipReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetImportZipRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetPageReqVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetPageReqVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetPrefillRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetPrefillRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetResponseRecordRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetResponseRecordRespVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetSignOffReqVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusActionReqVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusActionReqVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusDictRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusDictRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusLogRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusLogRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusTransitionRespVO;
|
import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetStatusTransitionRespVO;
|
||||||
import com.njcn.rdms.module.project.dal.dataobject.performance.PerformanceSheetDO;
|
import com.njcn.rdms.module.project.dal.dataobject.performance.PerformanceSheetDO;
|
||||||
import com.njcn.rdms.module.project.dal.dataobject.performance.PerformanceSheetResponseRecordDO;
|
import com.njcn.rdms.module.project.dal.dataobject.performance.PerformanceSheetResponseRecordDO;
|
||||||
|
import com.njcn.rdms.module.project.dal.dataobject.performance.PerformanceSheetSignOffDO;
|
||||||
|
import com.njcn.rdms.module.project.dal.dataobject.performance.PerformanceSheetSignOffRecordDO;
|
||||||
import com.njcn.rdms.module.project.dal.dataobject.performance.PerformanceSheetStatusLogDO;
|
import com.njcn.rdms.module.project.dal.dataobject.performance.PerformanceSheetStatusLogDO;
|
||||||
import com.njcn.rdms.module.project.dal.dataobject.performance.PerformanceTemplateDO;
|
import com.njcn.rdms.module.project.dal.dataobject.performance.PerformanceTemplateDO;
|
||||||
|
import com.njcn.rdms.module.project.dal.dataobject.signoff.EmployeeSignOffBatchDO;
|
||||||
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.performance.PerformanceSheetMapper;
|
import com.njcn.rdms.module.project.dal.mysql.performance.PerformanceSheetMapper;
|
||||||
import com.njcn.rdms.module.project.dal.mysql.performance.PerformanceSheetResponseRecordMapper;
|
import com.njcn.rdms.module.project.dal.mysql.performance.PerformanceSheetResponseRecordMapper;
|
||||||
|
import com.njcn.rdms.module.project.dal.mysql.performance.PerformanceSheetSignOffMapper;
|
||||||
|
import com.njcn.rdms.module.project.dal.mysql.performance.PerformanceSheetSignOffRecordMapper;
|
||||||
import com.njcn.rdms.module.project.dal.mysql.performance.PerformanceSheetStatusLogMapper;
|
import com.njcn.rdms.module.project.dal.mysql.performance.PerformanceSheetStatusLogMapper;
|
||||||
import com.njcn.rdms.module.project.dal.mysql.performance.PerformanceTemplateMapper;
|
import com.njcn.rdms.module.project.dal.mysql.performance.PerformanceTemplateMapper;
|
||||||
|
import com.njcn.rdms.module.project.dal.mysql.signoff.EmployeeSignOffBatchMapper;
|
||||||
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusModelMapper;
|
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusModelMapper;
|
||||||
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusTransitionMapper;
|
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusTransitionMapper;
|
||||||
|
import com.njcn.rdms.module.project.dal.mysql.workreport.monthly.MonthlyReportApprovalRecordMapper;
|
||||||
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
|
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
|
||||||
import com.njcn.rdms.module.project.framework.notify.NotifySendEvent;
|
import com.njcn.rdms.module.project.framework.notify.NotifySendEvent;
|
||||||
import com.njcn.rdms.module.project.framework.notify.NotifyTemplateCodeConstants;
|
import com.njcn.rdms.module.project.framework.notify.NotifyTemplateCodeConstants;
|
||||||
|
import com.njcn.rdms.module.project.service.signoff.EmployeeSignOffStatusService;
|
||||||
import com.njcn.rdms.module.project.service.status.StatusActionTextResolver;
|
import com.njcn.rdms.module.project.service.status.StatusActionTextResolver;
|
||||||
import com.njcn.rdms.module.project.service.team.TeamDashboardAccessService;
|
import com.njcn.rdms.module.project.service.team.TeamDashboardAccessService;
|
||||||
|
import com.njcn.rdms.module.project.service.workreport.common.WorkReportCommonService;
|
||||||
import com.njcn.rdms.module.system.api.dept.DeptApi;
|
import com.njcn.rdms.module.system.api.dept.DeptApi;
|
||||||
import com.njcn.rdms.module.system.api.dept.dto.DeptRespDTO;
|
import com.njcn.rdms.module.system.api.dept.dto.DeptRespDTO;
|
||||||
import com.njcn.rdms.module.system.api.file.FileApi;
|
import com.njcn.rdms.module.system.api.file.FileApi;
|
||||||
|
import com.njcn.rdms.module.system.api.file.dto.FileContentCreateReqDTO;
|
||||||
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 com.njcn.rdms.module.system.api.user.UserManagementRelationApi;
|
||||||
import com.njcn.rdms.module.system.api.user.dto.AdminUserRespDTO;
|
import com.njcn.rdms.module.system.api.user.dto.AdminUserRespDTO;
|
||||||
@@ -71,13 +86,18 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.YearMonth;
|
import java.time.YearMonth;
|
||||||
@@ -95,6 +115,8 @@ import java.util.Objects;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
|
import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
|
||||||
@@ -116,12 +138,22 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
|||||||
@Resource
|
@Resource
|
||||||
private PerformanceSheetResponseRecordMapper performanceSheetResponseRecordMapper;
|
private PerformanceSheetResponseRecordMapper performanceSheetResponseRecordMapper;
|
||||||
@Resource
|
@Resource
|
||||||
|
private PerformanceSheetSignOffMapper performanceSheetSignOffMapper;
|
||||||
|
@Resource
|
||||||
|
private PerformanceSheetSignOffRecordMapper performanceSheetSignOffRecordMapper;
|
||||||
|
@Resource
|
||||||
|
private EmployeeSignOffBatchMapper employeeSignOffBatchMapper;
|
||||||
|
@Resource
|
||||||
|
private MonthlyReportApprovalRecordMapper monthlyReportApprovalRecordMapper;
|
||||||
|
@Resource
|
||||||
private ObjectStatusModelMapper objectStatusModelMapper;
|
private ObjectStatusModelMapper objectStatusModelMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private ObjectStatusTransitionMapper objectStatusTransitionMapper;
|
private ObjectStatusTransitionMapper objectStatusTransitionMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private StatusActionTextResolver statusActionTextResolver;
|
private StatusActionTextResolver statusActionTextResolver;
|
||||||
@Resource
|
@Resource
|
||||||
|
private EmployeeSignOffStatusService employeeSignOffStatusService;
|
||||||
|
@Resource
|
||||||
private AdminUserApi adminUserApi;
|
private AdminUserApi adminUserApi;
|
||||||
@Resource
|
@Resource
|
||||||
private DeptApi deptApi;
|
private DeptApi deptApi;
|
||||||
@@ -130,9 +162,13 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
|||||||
@Resource
|
@Resource
|
||||||
private FileApi fileApi;
|
private FileApi fileApi;
|
||||||
@Resource
|
@Resource
|
||||||
|
private WorkReportCommonService workReportCommonService;
|
||||||
|
@Resource
|
||||||
private TeamDashboardAccessService teamDashboardAccessService;
|
private TeamDashboardAccessService teamDashboardAccessService;
|
||||||
@Resource
|
@Resource
|
||||||
private ApplicationEventPublisher applicationEventPublisher;
|
private ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
@Resource
|
||||||
|
private TransactionTemplate transactionTemplate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<PerformanceSheetRespVO> getSheetPage(PerformanceSheetPageReqVO reqVO) {
|
public PageResult<PerformanceSheetRespVO> getSheetPage(PerformanceSheetPageReqVO reqVO) {
|
||||||
@@ -183,6 +219,7 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
|||||||
sheet.setFileName(buildPerformanceFileName(periodMonth, employee.getNickname()));
|
sheet.setFileName(buildPerformanceFileName(periodMonth, employee.getNickname()));
|
||||||
sheet.setFileVersion(0);
|
sheet.setFileVersion(0);
|
||||||
sheet.setStatusCode(getInitialStatusCode());
|
sheet.setStatusCode(getInitialStatusCode());
|
||||||
|
sheet.setSignOffStatus(SignOffConstants.STATUS_NOT_STARTED);
|
||||||
performanceSheetMapper.insert(sheet);
|
performanceSheetMapper.insert(sheet);
|
||||||
return sheet.getId();
|
return sheet.getId();
|
||||||
}
|
}
|
||||||
@@ -248,6 +285,158 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
|||||||
publishPerformanceNotice(List.of(sheet.getManagerId()), NotifyTemplateCodeConstants.PERFORMANCE_REJECTED, sheet);
|
publishPerformanceNotice(List.of(sheet.getManagerId()), NotifyTemplateCodeConstants.PERFORMANCE_REJECTED, sheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PerformanceSheetImportZipRespVO importZip(PerformanceSheetImportZipReqVO reqVO) throws Exception {
|
||||||
|
MultipartFile file = reqVO.getFile();
|
||||||
|
if (file == null || file.isEmpty()) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_IMPORT_ZIP_EMPTY);
|
||||||
|
}
|
||||||
|
String periodMonth = normalizePeriodMonth(reqVO.getPeriodMonth());
|
||||||
|
CurrentOperatorProfile operatorProfile = loadCurrentOperatorProfile();
|
||||||
|
validateBatchUnlocked(periodMonth, operatorProfile.deptId());
|
||||||
|
List<Long> candidateEmployeeIds = resolveRequestedEmployeeIds(reqVO.getEmployeeIds(),
|
||||||
|
PerformanceConstants.PERMISSION_SHEET_IMPORT);
|
||||||
|
if (candidateEmployeeIds.isEmpty()) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_IMPORT_TARGET_EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, List<PerformanceSheetDO>> sheetsByEmployeeName = performanceSheetMapper
|
||||||
|
.selectListByEmployeeIdsAndPeriodMonth(candidateEmployeeIds, periodMonth)
|
||||||
|
.stream()
|
||||||
|
.collect(java.util.stream.Collectors.groupingBy(PerformanceSheetDO::getEmployeeName,
|
||||||
|
LinkedHashMap::new, java.util.stream.Collectors.toList()));
|
||||||
|
if (sheetsByEmployeeName.isEmpty()) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_IMPORT_TARGET_EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> messages = new ArrayList<>();
|
||||||
|
int workbookCount = 0;
|
||||||
|
int sheetCount = 0;
|
||||||
|
int successCount = 0;
|
||||||
|
int skippedCount = 0;
|
||||||
|
int failedCount = 0;
|
||||||
|
List<ImportedWorkbookEntry> workbookEntries = readZipWorkbookEntries(file.getBytes());
|
||||||
|
for (ImportedWorkbookEntry workbookEntry : workbookEntries) {
|
||||||
|
if (shouldIgnoreImportedWorkbook(workbookEntry.displayName())) {
|
||||||
|
skippedCount++;
|
||||||
|
messages.add("跳过工作簿:" + workbookEntry.displayName() + ",原因:兼容忽略 0_绩效表汇总");
|
||||||
|
log.info("导入绩效压缩包时跳过工作簿,workbookName={}, reason={}",
|
||||||
|
workbookEntry.displayName(), "兼容忽略 0_绩效表汇总");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
workbookCount++;
|
||||||
|
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(workbookEntry.content());
|
||||||
|
Workbook workbook = WorkbookFactory.create(inputStream)) {
|
||||||
|
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
|
||||||
|
DataFormatter formatter = new DataFormatter();
|
||||||
|
for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) {
|
||||||
|
Sheet importedSheet = workbook.getSheetAt(sheetIndex);
|
||||||
|
sheetCount++;
|
||||||
|
try {
|
||||||
|
importOneSheet(periodMonth, workbookEntry.displayName(), importedSheet, evaluator, formatter,
|
||||||
|
sheetsByEmployeeName);
|
||||||
|
successCount++;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
failedCount++;
|
||||||
|
String message = "导入失败:" + workbookEntry.displayName() + " / " + importedSheet.getSheetName()
|
||||||
|
+ ",原因:" + ex.getMessage();
|
||||||
|
messages.add(message);
|
||||||
|
log.warn("导入绩效 sheet 失败,workbookName={}, sheetName={}, reason={}",
|
||||||
|
workbookEntry.displayName(), importedSheet.getSheetName(), ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PerformanceSheetImportZipRespVO respVO = new PerformanceSheetImportZipRespVO();
|
||||||
|
respVO.setWorkbookCount(workbookCount);
|
||||||
|
respVO.setSheetCount(sheetCount);
|
||||||
|
respVO.setSuccessCount(successCount);
|
||||||
|
respVO.setSkippedCount(skippedCount);
|
||||||
|
respVO.setFailedCount(failedCount);
|
||||||
|
respVO.setMessages(messages);
|
||||||
|
return respVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Long signOff(PerformanceSheetSignOffReqVO reqVO) {
|
||||||
|
String periodMonth = normalizePeriodMonth(reqVO.getPeriodMonth());
|
||||||
|
CurrentOperatorProfile operatorProfile = loadCurrentOperatorProfile();
|
||||||
|
validateBatchUnlocked(periodMonth, operatorProfile.deptId());
|
||||||
|
|
||||||
|
boolean explicitSelection = reqVO.getEmployeeIds() != null && !reqVO.getEmployeeIds().isEmpty();
|
||||||
|
List<Long> requestedEmployeeIds = resolveRequestedEmployeeIds(reqVO.getEmployeeIds(),
|
||||||
|
PerformanceConstants.PERMISSION_SHEET_SIGN_OFF);
|
||||||
|
if (requestedEmployeeIds.isEmpty()) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_SIGN_OFF_CANDIDATE_EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<PerformanceSheetDO> performanceSheets = performanceSheetMapper
|
||||||
|
.selectListByEmployeeIdsAndPeriodMonth(requestedEmployeeIds, periodMonth);
|
||||||
|
List<PerformanceSheetDO> eligiblePerformanceSheets = performanceSheets.stream()
|
||||||
|
.filter(this::isEligibleForIssue)
|
||||||
|
.toList();
|
||||||
|
Map<Long, PerformanceSheetDO> performanceByEmployeeId = eligiblePerformanceSheets.stream()
|
||||||
|
.collect(java.util.stream.Collectors.toMap(PerformanceSheetDO::getEmployeeId, item -> item,
|
||||||
|
(left, right) -> left, LinkedHashMap::new));
|
||||||
|
|
||||||
|
List<com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportDO> monthlyReports =
|
||||||
|
workReportCommonService.listMonthlyReportsForSignOff(requestedEmployeeIds, periodMonth);
|
||||||
|
List<com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportDO> eligibleMonthlyReports =
|
||||||
|
monthlyReports.stream()
|
||||||
|
.filter(this::isEligibleMonthlyReportForIssue)
|
||||||
|
.filter(report -> hasLatestApprovedRecord(report.getId()))
|
||||||
|
.toList();
|
||||||
|
Map<Long, com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportDO> monthlyByEmployeeId =
|
||||||
|
eligibleMonthlyReports.stream()
|
||||||
|
.collect(java.util.stream.Collectors.toMap(
|
||||||
|
com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportDO::getReporterId,
|
||||||
|
item -> item, (left, right) -> left, LinkedHashMap::new));
|
||||||
|
|
||||||
|
List<Long> targetEmployeeIds = new ArrayList<>();
|
||||||
|
if (explicitSelection) {
|
||||||
|
for (Long employeeId : requestedEmployeeIds) {
|
||||||
|
if (!performanceByEmployeeId.containsKey(employeeId) || !monthlyByEmployeeId.containsKey(employeeId)) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_SIGN_OFF_CANDIDATE_EMPTY);
|
||||||
|
}
|
||||||
|
targetEmployeeIds.add(employeeId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (Long employeeId : requestedEmployeeIds) {
|
||||||
|
if (performanceByEmployeeId.containsKey(employeeId) && monthlyByEmployeeId.containsKey(employeeId)) {
|
||||||
|
targetEmployeeIds.add(employeeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (targetEmployeeIds.isEmpty()) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_SIGN_OFF_CANDIDATE_EMPTY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<PerformanceSheetDO> targetSheets = targetEmployeeIds.stream()
|
||||||
|
.map(performanceByEmployeeId::get)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.toList();
|
||||||
|
List<com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportDO> targetReports =
|
||||||
|
targetEmployeeIds.stream()
|
||||||
|
.map(monthlyByEmployeeId::get)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
EmployeeSignOffBatchDO batch = new EmployeeSignOffBatchDO();
|
||||||
|
batch.setPeriodMonth(periodMonth);
|
||||||
|
batch.setDeptId(operatorProfile.deptId());
|
||||||
|
batch.setDeptName(operatorProfile.deptName());
|
||||||
|
batch.setOperatorUserId(operatorProfile.userId());
|
||||||
|
batch.setOperatorName(operatorProfile.userName());
|
||||||
|
batch.setLockedFlag(1);
|
||||||
|
batch.setRemark(normalizeNullableText(reqVO.getRemark()));
|
||||||
|
employeeSignOffBatchMapper.insert(batch);
|
||||||
|
|
||||||
|
issuePerformanceSignOff(targetSheets, batch.getId());
|
||||||
|
workReportCommonService.issueMonthlySignOff(targetReports, batch.getId());
|
||||||
|
return batch.getId();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PerformanceDownloadFile download(Long id) {
|
public PerformanceDownloadFile download(Long id) {
|
||||||
PerformanceSheetDO sheet = validateReadableSheet(id);
|
PerformanceSheetDO sheet = validateReadableSheet(id);
|
||||||
@@ -393,23 +582,38 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
|||||||
private PerformanceSheetDO processEmployeeResponse(Long id, String actionType, String reason) {
|
private PerformanceSheetDO processEmployeeResponse(Long id, String actionType, String reason) {
|
||||||
PerformanceSheetDO current = validateSheetExists(id);
|
PerformanceSheetDO current = validateSheetExists(id);
|
||||||
validateEmployeeOnly(current.getEmployeeId());
|
validateEmployeeOnly(current.getEmployeeId());
|
||||||
|
PerformanceEmployeeResponseContext responseContext = resolvePerformanceEmployeeResponseContext(current);
|
||||||
ObjectStatusTransitionDO transition = validateTransition(current.getStatusCode(), actionType, reason);
|
ObjectStatusTransitionDO transition = validateTransition(current.getStatusCode(), actionType, reason);
|
||||||
PerformanceSheetDO update = new PerformanceSheetDO();
|
PerformanceSheetDO update = new PerformanceSheetDO();
|
||||||
update.setStatusCode(transition.getToStatusCode());
|
update.setStatusCode(transition.getToStatusCode());
|
||||||
if (PerformanceConstants.STATUS_CONFIRMED.equals(transition.getToStatusCode())) {
|
if (PerformanceConstants.STATUS_CONFIRMED.equals(transition.getToStatusCode())) {
|
||||||
update.setConfirmedTime(LocalDateTime.now());
|
update.setConfirmedTime(LocalDateTime.now());
|
||||||
|
if (responseContext.signOffFlow()) {
|
||||||
|
update.setSignOffStatus(SignOffConstants.STATUS_EMPLOYEE_CONFIRMED);
|
||||||
|
}
|
||||||
} else if (PerformanceConstants.STATUS_REJECTED.equals(transition.getToStatusCode())) {
|
} else if (PerformanceConstants.STATUS_REJECTED.equals(transition.getToStatusCode())) {
|
||||||
update.setRejectedTime(LocalDateTime.now());
|
update.setRejectedTime(LocalDateTime.now());
|
||||||
update.setLastStatusReason(reason);
|
update.setLastStatusReason(reason);
|
||||||
|
if (responseContext.signOffFlow()) {
|
||||||
|
update.setSignOffStatus(SignOffConstants.STATUS_EMPLOYEE_REJECTED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
int updateCount = performanceSheetMapper.updateStatusByIdAndStatus(update, id, current.getStatusCode());
|
int updateCount = performanceSheetMapper.updateByIdAndStatusAndSignOffStatus(update, id, current.getStatusCode(),
|
||||||
|
current.getSignOffStatus());
|
||||||
if (updateCount != 1) {
|
if (updateCount != 1) {
|
||||||
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_STATUS_CONCURRENT_MODIFIED);
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_STATUS_CONCURRENT_MODIFIED);
|
||||||
}
|
}
|
||||||
|
if (responseContext.signOffFlow()) {
|
||||||
|
updatePerformanceSignOffAfterEmployeeAction(current, responseContext.signOff(), actionType, reason);
|
||||||
|
}
|
||||||
PerformanceSheetDO after = merge(current, update);
|
PerformanceSheetDO after = merge(current, update);
|
||||||
PerformanceSheetStatusLogDO statusLog = writeStatusLog(after, actionType, current.getStatusCode(),
|
PerformanceSheetStatusLogDO statusLog = writeStatusLog(after, actionType, current.getStatusCode(),
|
||||||
transition.getToStatusCode(), reason);
|
transition.getToStatusCode(), reason);
|
||||||
writeResponseRecord(after, statusLog, actionType, current.getStatusCode(), transition.getToStatusCode(), reason);
|
writeResponseRecord(after, statusLog, actionType, current.getStatusCode(), transition.getToStatusCode(), reason);
|
||||||
|
if (PerformanceConstants.ACTION_CONFIRM.equals(actionType)) {
|
||||||
|
workReportCommonService.syncPerformanceResult(after.getEmployeeId(), after.getPeriodMonth(),
|
||||||
|
formatScoreForMonthlyResult(after.getActualScoreTotal()));
|
||||||
|
}
|
||||||
return after;
|
return after;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,6 +731,11 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
|||||||
private PerformanceSheetRespVO toRespVO(PerformanceSheetDO sheet) {
|
private PerformanceSheetRespVO toRespVO(PerformanceSheetDO sheet) {
|
||||||
PerformanceSheetRespVO respVO = BeanUtils.toBean(sheet, PerformanceSheetRespVO.class);
|
PerformanceSheetRespVO respVO = BeanUtils.toBean(sheet, PerformanceSheetRespVO.class);
|
||||||
respVO.setStatusName(statusName(sheet.getStatusCode()));
|
respVO.setStatusName(statusName(sheet.getStatusCode()));
|
||||||
|
String signOffStatus = StringUtils.hasText(sheet.getSignOffStatus())
|
||||||
|
? sheet.getSignOffStatus()
|
||||||
|
: SignOffConstants.STATUS_NOT_STARTED;
|
||||||
|
respVO.setSignOffStatus(signOffStatus);
|
||||||
|
respVO.setSignOffStatusName(employeeSignOffStatusService.statusName(signOffStatus));
|
||||||
return respVO;
|
return respVO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1095,17 +1304,22 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
|||||||
Sheet sourceSheet = workbook.getSheetAt(0);
|
Sheet sourceSheet = workbook.getSheetAt(0);
|
||||||
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
|
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
|
||||||
DataFormatter formatter = new DataFormatter();
|
DataFormatter formatter = new DataFormatter();
|
||||||
Map<String, String> cellValues = new LinkedHashMap<>();
|
return readSelectedCellValues(sourceSheet, evaluator, formatter, cellAddresses);
|
||||||
for (String cellAddress : cellAddresses) {
|
|
||||||
String value = readCellDisplayValue(sourceSheet, evaluator, formatter, cellAddress);
|
|
||||||
if (value != null) {
|
|
||||||
cellValues.put(cellAddress, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cellValues;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, String> readSelectedCellValues(Sheet sheet, FormulaEvaluator evaluator,
|
||||||
|
DataFormatter formatter, List<String> cellAddresses) {
|
||||||
|
Map<String, String> cellValues = new LinkedHashMap<>();
|
||||||
|
for (String cellAddress : cellAddresses) {
|
||||||
|
String value = readCellDisplayValue(sheet, evaluator, formatter, cellAddress);
|
||||||
|
if (value != null) {
|
||||||
|
cellValues.put(cellAddress, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cellValues;
|
||||||
|
}
|
||||||
|
|
||||||
private String readCellDisplayValue(Sheet sheet,
|
private String readCellDisplayValue(Sheet sheet,
|
||||||
FormulaEvaluator evaluator,
|
FormulaEvaluator evaluator,
|
||||||
DataFormatter formatter,
|
DataFormatter formatter,
|
||||||
@@ -1123,6 +1337,348 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
|||||||
return StringUtils.hasText(value) ? value.trim() : null;
|
return StringUtils.hasText(value) ? value.trim() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void importOneSheet(String periodMonth, String workbookName, Sheet importedSheet,
|
||||||
|
FormulaEvaluator evaluator, DataFormatter formatter,
|
||||||
|
Map<String, List<PerformanceSheetDO>> sheetsByEmployeeName) {
|
||||||
|
transactionTemplate.executeWithoutResult(status -> {
|
||||||
|
String sheetName = importedSheet.getSheetName();
|
||||||
|
String employeeName = parseEmployeeNameFromSheetName(periodMonth, sheetName);
|
||||||
|
List<PerformanceSheetDO> matchedSheets = sheetsByEmployeeName.getOrDefault(employeeName, List.of());
|
||||||
|
if (matchedSheets.isEmpty()) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_IMPORT_TARGET_EMPTY);
|
||||||
|
}
|
||||||
|
if (matchedSheets.size() > 1) {
|
||||||
|
throw invalidParamException("存在重名员工,无法唯一匹配:" + employeeName);
|
||||||
|
}
|
||||||
|
PerformanceSheetDO currentSheet = matchedSheets.get(0);
|
||||||
|
Map<String, String> importedValues = readSelectedCellValues(importedSheet, evaluator, formatter,
|
||||||
|
PerformanceExcelCellConstants.MERGED_EXPORT_CELL_ADDRESSES);
|
||||||
|
if (importedValues.isEmpty()) {
|
||||||
|
throw invalidParamException("未读取到可回写的绩效单元格");
|
||||||
|
}
|
||||||
|
applyImportedSheetValues(currentSheet, workbookName, sheetName, importedValues);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyImportedSheetValues(PerformanceSheetDO currentSheet, String workbookName, String sheetName,
|
||||||
|
Map<String, String> importedValues) {
|
||||||
|
byte[] sourceContent = readFileContent(currentSheet);
|
||||||
|
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(sourceContent);
|
||||||
|
Workbook workbook = WorkbookFactory.create(inputStream);
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||||
|
if (workbook.getNumberOfSheets() <= 0) {
|
||||||
|
throw invalidParamException("原始绩效文件缺少 sheet 页");
|
||||||
|
}
|
||||||
|
Sheet targetSheet = workbook.getSheetAt(0);
|
||||||
|
writeMergedExportCellValues(targetSheet, importedValues);
|
||||||
|
workbook.setForceFormulaRecalculation(true);
|
||||||
|
FormulaEvaluator targetEvaluator = workbook.getCreationHelper().createFormulaEvaluator();
|
||||||
|
targetEvaluator.evaluateAll();
|
||||||
|
DataFormatter formatter = new DataFormatter();
|
||||||
|
BigDecimal actualScoreTotal = parseScore(readCellDisplayValue(targetSheet, targetEvaluator, formatter,
|
||||||
|
PerformanceExcelCellConstants.ACTUAL_SCORE_TOTAL_CELL));
|
||||||
|
BigDecimal baseScoreTotal = parseScore(readCellDisplayValue(targetSheet, targetEvaluator, formatter,
|
||||||
|
PerformanceExcelCellConstants.BASE_SCORE_TOTAL_CELL));
|
||||||
|
BigDecimal extraScoreTotal = parseScore(readCellDisplayValue(targetSheet, targetEvaluator, formatter,
|
||||||
|
PerformanceExcelCellConstants.EXTRA_SCORE_TOTAL_CELL));
|
||||||
|
|
||||||
|
workbook.write(outputStream);
|
||||||
|
FileContentCreateReqDTO fileCreateReqDTO = new FileContentCreateReqDTO();
|
||||||
|
fileCreateReqDTO.setContent(outputStream.toByteArray());
|
||||||
|
fileCreateReqDTO.setName(defaultDownloadName(currentSheet));
|
||||||
|
fileCreateReqDTO.setDirectory("rdms/performance");
|
||||||
|
fileCreateReqDTO.setType(resolveExcelContentType(defaultDownloadName(currentSheet)));
|
||||||
|
CommonResult<Long> createFileResult = fileApi.createFileByContent(fileCreateReqDTO);
|
||||||
|
Long newFileId = createFileResult == null ? null : createFileResult.getCheckedData();
|
||||||
|
if (newFileId == null) {
|
||||||
|
throw new IllegalStateException("上传更新后的绩效文件失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
PerformanceSheetDO update = new PerformanceSheetDO();
|
||||||
|
update.setFileId(newFileId);
|
||||||
|
update.setFileName(defaultDownloadName(currentSheet));
|
||||||
|
update.setFileVersion(currentSheet.getFileVersion() == null ? 1 : currentSheet.getFileVersion() + 1);
|
||||||
|
update.setActualScoreTotal(actualScoreTotal);
|
||||||
|
update.setBaseScoreTotal(baseScoreTotal);
|
||||||
|
update.setExtraScoreTotal(extraScoreTotal);
|
||||||
|
int updateCount = performanceSheetMapper.updateExcelByIdAndVersion(update, currentSheet.getId(),
|
||||||
|
currentSheet.getFileVersion());
|
||||||
|
if (updateCount != 1) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_STATUS_CONCURRENT_MODIFIED);
|
||||||
|
}
|
||||||
|
workReportCommonService.syncPerformanceResult(currentSheet.getEmployeeId(), currentSheet.getPeriodMonth(),
|
||||||
|
formatScoreForMonthlyResult(actualScoreTotal));
|
||||||
|
log.info("导入绩效 sheet 成功,workbookName={}, sheetName={}, sheetId={}, employeeId={}",
|
||||||
|
workbookName, sheetName, currentSheet.getId(), currentSheet.getEmployeeId());
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
throw ex;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new IllegalStateException("回写绩效 Excel 失败", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ImportedWorkbookEntry> readZipWorkbookEntries(byte[] zipBytes) throws IOException {
|
||||||
|
List<Charset> charsets = List.of(StandardCharsets.UTF_8, Charset.forName("GBK"));
|
||||||
|
Exception lastException = null;
|
||||||
|
for (Charset charset : charsets) {
|
||||||
|
try {
|
||||||
|
return readZipWorkbookEntries(zipBytes, charset);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
lastException = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastException instanceof IOException ioException) {
|
||||||
|
throw ioException;
|
||||||
|
}
|
||||||
|
throw new IOException("读取 zip 文件失败", lastException);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ImportedWorkbookEntry> readZipWorkbookEntries(byte[] zipBytes, Charset charset) throws IOException {
|
||||||
|
List<ImportedWorkbookEntry> workbookEntries = new ArrayList<>();
|
||||||
|
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(zipBytes);
|
||||||
|
ZipInputStream zipInputStream = new ZipInputStream(inputStream, charset)) {
|
||||||
|
ZipEntry entry;
|
||||||
|
while ((entry = zipInputStream.getNextEntry()) != null) {
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String displayName = extractEntryDisplayName(entry.getName());
|
||||||
|
if (!isExcelEntry(displayName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
zipInputStream.transferTo(outputStream);
|
||||||
|
workbookEntries.add(new ImportedWorkbookEntry(displayName, outputStream.toByteArray()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return workbookEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractEntryDisplayName(String entryName) {
|
||||||
|
if (!StringUtils.hasText(entryName)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String normalized = entryName.replace("\\", "/");
|
||||||
|
int index = normalized.lastIndexOf('/');
|
||||||
|
return index >= 0 ? normalized.substring(index + 1) : normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isExcelEntry(String fileName) {
|
||||||
|
if (!StringUtils.hasText(fileName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String lowerCase = fileName.toLowerCase();
|
||||||
|
return lowerCase.endsWith(".xlsx") || lowerCase.endsWith(".xlsm") || lowerCase.endsWith(".xls");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldIgnoreImportedWorkbook(String workbookName) {
|
||||||
|
return StringUtils.hasText(workbookName) && workbookName.startsWith("0_绩效表汇总");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseEmployeeNameFromSheetName(String periodMonth, String sheetName) {
|
||||||
|
if (!StringUtils.hasText(sheetName)) {
|
||||||
|
throw invalidParamException("sheet 名不能为空");
|
||||||
|
}
|
||||||
|
String normalizedName = sheetName.trim();
|
||||||
|
int splitIndex = normalizedName.indexOf('_');
|
||||||
|
if (splitIndex <= 0 || splitIndex >= normalizedName.length() - 1) {
|
||||||
|
throw invalidParamException("sheet 名不符合“月份_姓名”规则:" + normalizedName);
|
||||||
|
}
|
||||||
|
String monthPart = normalizedName.substring(0, splitIndex).trim();
|
||||||
|
if (!periodMonth.equals(monthPart)) {
|
||||||
|
throw invalidParamException("sheet 月份与导入月份不一致:" + normalizedName);
|
||||||
|
}
|
||||||
|
String employeeName = normalizedName.substring(splitIndex + 1).trim();
|
||||||
|
if (!StringUtils.hasText(employeeName)) {
|
||||||
|
throw invalidParamException("sheet 名未包含员工姓名:" + normalizedName);
|
||||||
|
}
|
||||||
|
return employeeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PerformanceEmployeeResponseContext resolvePerformanceEmployeeResponseContext(PerformanceSheetDO sheet) {
|
||||||
|
if (!PerformanceConstants.STATUS_SENT.equals(sheet.getStatusCode())) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_SIGN_OFF_NOT_ALLOWED);
|
||||||
|
}
|
||||||
|
if (SignOffConstants.STATUS_PENDING_EMPLOYEE_CONFIRM.equals(sheet.getSignOffStatus())) {
|
||||||
|
PerformanceSheetSignOffDO signOff = validatePerformanceSignOffExists(sheet.getId());
|
||||||
|
if (!SignOffConstants.STATUS_PENDING_EMPLOYEE_CONFIRM.equals(signOff.getStatusCode())) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_SIGN_OFF_NOT_ALLOWED);
|
||||||
|
}
|
||||||
|
return new PerformanceEmployeeResponseContext(signOff, true);
|
||||||
|
}
|
||||||
|
if (SignOffConstants.STATUS_EMPLOYEE_REJECTED.equals(sheet.getSignOffStatus())) {
|
||||||
|
PerformanceSheetSignOffDO signOff = validatePerformanceSignOffExists(sheet.getId());
|
||||||
|
if (!SignOffConstants.STATUS_EMPLOYEE_REJECTED.equals(signOff.getStatusCode())) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_SIGN_OFF_NOT_ALLOWED);
|
||||||
|
}
|
||||||
|
return new PerformanceEmployeeResponseContext(signOff, false);
|
||||||
|
}
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_SIGN_OFF_NOT_ALLOWED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PerformanceSheetSignOffDO validatePerformanceSignOffExists(Long sheetId) {
|
||||||
|
PerformanceSheetSignOffDO signOff = performanceSheetSignOffMapper.selectByPerformanceSheetId(sheetId);
|
||||||
|
if (signOff == null) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_SIGN_OFF_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
return signOff;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePerformanceSignOffAfterEmployeeAction(PerformanceSheetDO current, PerformanceSheetSignOffDO signOff,
|
||||||
|
String actionType, String reason) {
|
||||||
|
PerformanceSheetSignOffDO signOffUpdate = new PerformanceSheetSignOffDO();
|
||||||
|
signOffUpdate.setStatusCode(PerformanceConstants.ACTION_CONFIRM.equals(actionType)
|
||||||
|
? SignOffConstants.STATUS_EMPLOYEE_CONFIRMED
|
||||||
|
: SignOffConstants.STATUS_EMPLOYEE_REJECTED);
|
||||||
|
signOffUpdate.setConfirmUserId(SecurityFrameworkUtils.getLoginUserId());
|
||||||
|
signOffUpdate.setConfirmUserName(defaultText(SecurityFrameworkUtils.getLoginUserNickname()));
|
||||||
|
signOffUpdate.setConfirmTime(LocalDateTime.now());
|
||||||
|
signOffUpdate.setLastRejectReason(PerformanceConstants.ACTION_REJECT.equals(actionType) ? reason : null);
|
||||||
|
int signOffUpdateCount = performanceSheetSignOffMapper.updateByPerformanceSheetIdAndStatus(signOffUpdate,
|
||||||
|
current.getId(), signOff.getStatusCode());
|
||||||
|
if (signOffUpdateCount != 1) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_STATUS_CONCURRENT_MODIFIED);
|
||||||
|
}
|
||||||
|
writePerformanceSignOffRecord(signOff.getId(), current.getId(), signOff.getBatchNo(), actionType,
|
||||||
|
signOff.getStatusCode(), signOffUpdate.getStatusCode(), reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void issuePerformanceSignOff(List<PerformanceSheetDO> sheets, Long batchNo) {
|
||||||
|
if (sheets == null || sheets.isEmpty()) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_SIGN_OFF_CANDIDATE_EMPTY);
|
||||||
|
}
|
||||||
|
LocalDateTime issueTime = LocalDateTime.now();
|
||||||
|
Long operatorUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
|
String operatorName = defaultText(SecurityFrameworkUtils.getLoginUserNickname());
|
||||||
|
for (PerformanceSheetDO sheet : sheets) {
|
||||||
|
PerformanceSheetDO update = new PerformanceSheetDO();
|
||||||
|
update.setSignOffStatus(SignOffConstants.STATUS_PENDING_EMPLOYEE_CONFIRM);
|
||||||
|
int updateCount = performanceSheetMapper.updateByIdAndStatusAndSignOffStatus(update, sheet.getId(),
|
||||||
|
sheet.getStatusCode(), sheet.getSignOffStatus());
|
||||||
|
if (updateCount != 1) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_STATUS_CONCURRENT_MODIFIED);
|
||||||
|
}
|
||||||
|
PerformanceSheetSignOffDO currentSignOff = performanceSheetSignOffMapper.selectByPerformanceSheetId(sheet.getId());
|
||||||
|
if (currentSignOff == null) {
|
||||||
|
PerformanceSheetSignOffDO signOff = new PerformanceSheetSignOffDO();
|
||||||
|
signOff.setPerformanceSheetId(sheet.getId());
|
||||||
|
signOff.setBatchNo(batchNo);
|
||||||
|
signOff.setStatusCode(SignOffConstants.STATUS_PENDING_EMPLOYEE_CONFIRM);
|
||||||
|
signOff.setIssueUserId(operatorUserId);
|
||||||
|
signOff.setIssueUserName(operatorName);
|
||||||
|
signOff.setIssueTime(issueTime);
|
||||||
|
performanceSheetSignOffMapper.insert(signOff);
|
||||||
|
writePerformanceSignOffRecord(signOff.getId(), sheet.getId(), batchNo, SignOffConstants.ACTION_ISSUE,
|
||||||
|
SignOffConstants.STATUS_NOT_STARTED, SignOffConstants.STATUS_PENDING_EMPLOYEE_CONFIRM, null);
|
||||||
|
} else {
|
||||||
|
employeeSignOffStatusService.validateTransition(currentSignOff.getStatusCode(), SignOffConstants.ACTION_ISSUE, null);
|
||||||
|
PerformanceSheetSignOffDO signOffUpdate = new PerformanceSheetSignOffDO();
|
||||||
|
signOffUpdate.setStatusCode(SignOffConstants.STATUS_PENDING_EMPLOYEE_CONFIRM);
|
||||||
|
signOffUpdate.setBatchNo(batchNo);
|
||||||
|
signOffUpdate.setIssueUserId(operatorUserId);
|
||||||
|
signOffUpdate.setIssueUserName(operatorName);
|
||||||
|
signOffUpdate.setIssueTime(issueTime);
|
||||||
|
signOffUpdate.setConfirmUserId(null);
|
||||||
|
signOffUpdate.setConfirmUserName(null);
|
||||||
|
signOffUpdate.setConfirmTime(null);
|
||||||
|
signOffUpdate.setLastRejectReason(null);
|
||||||
|
int signOffUpdateCount = performanceSheetSignOffMapper.updateByPerformanceSheetIdAndStatus(signOffUpdate,
|
||||||
|
sheet.getId(), currentSignOff.getStatusCode());
|
||||||
|
if (signOffUpdateCount != 1) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_STATUS_CONCURRENT_MODIFIED);
|
||||||
|
}
|
||||||
|
writePerformanceSignOffRecord(currentSignOff.getId(), sheet.getId(), batchNo,
|
||||||
|
SignOffConstants.ACTION_ISSUE, currentSignOff.getStatusCode(),
|
||||||
|
SignOffConstants.STATUS_PENDING_EMPLOYEE_CONFIRM, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writePerformanceSignOffRecord(Long signOffId, Long sheetId, Long batchNo, String actionType,
|
||||||
|
String fromStatus, String toStatus, String reason) {
|
||||||
|
PerformanceSheetSignOffRecordDO record = new PerformanceSheetSignOffRecordDO();
|
||||||
|
record.setSignOffId(signOffId);
|
||||||
|
record.setPerformanceSheetId(sheetId);
|
||||||
|
record.setBatchNo(batchNo);
|
||||||
|
record.setActionType(actionType);
|
||||||
|
record.setFromSignOffStatus(fromStatus);
|
||||||
|
record.setToSignOffStatus(toStatus);
|
||||||
|
record.setReason(reason);
|
||||||
|
record.setOperatorUserId(SecurityFrameworkUtils.getLoginUserId());
|
||||||
|
record.setOperatorName(defaultText(SecurityFrameworkUtils.getLoginUserNickname()));
|
||||||
|
performanceSheetSignOffRecordMapper.insert(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateBatchUnlocked(String periodMonth, Long deptId) {
|
||||||
|
if (employeeSignOffBatchMapper.selectByPeriodMonthAndDeptId(periodMonth, deptId) != null) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_SIGN_OFF_BATCH_LOCKED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Long> resolveRequestedEmployeeIds(Collection<Long> employeeIds, String permission) {
|
||||||
|
return teamDashboardAccessService.resolveRequestedSubordinateUserIds(employeeIds, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isEligibleForIssue(PerformanceSheetDO sheet) {
|
||||||
|
return sheet != null
|
||||||
|
&& PerformanceConstants.STATUS_SENT.equals(sheet.getStatusCode())
|
||||||
|
&& isIssueAllowed(sheet.getSignOffStatus())
|
||||||
|
&& sheet.getFileId() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isEligibleMonthlyReportForIssue(
|
||||||
|
com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportDO report) {
|
||||||
|
return report != null
|
||||||
|
&& WorkReportConstants.STATUS_APPROVED.equals(report.getStatusCode())
|
||||||
|
&& isIssueAllowed(report.getSignOffStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasLatestApprovedRecord(Long monthlyReportId) {
|
||||||
|
return monthlyReportApprovalRecordMapper.selectLatestApprovedByMonthlyReportId(monthlyReportId) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isIssueAllowed(String signOffStatus) {
|
||||||
|
return !StringUtils.hasText(signOffStatus)
|
||||||
|
|| SignOffConstants.STATUS_NOT_STARTED.equals(signOffStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal parseScore(String value) {
|
||||||
|
if (!StringUtils.hasText(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return normalizeScore(new BigDecimal(value.trim().replace(",", "")));
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatScoreForMonthlyResult(BigDecimal score) {
|
||||||
|
return score == null ? null : score.stripTrailingZeros().toPlainString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveExcelContentType(String fileName) {
|
||||||
|
return StringUtils.hasText(fileName) && fileName.toLowerCase().endsWith(".xls")
|
||||||
|
? "application/vnd.ms-excel"
|
||||||
|
: EXCEL_CONTENT_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CurrentOperatorProfile loadCurrentOperatorProfile() {
|
||||||
|
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
|
CommonResult<AdminUserRespDTO> userResult = adminUserApi.getUser(loginUserId);
|
||||||
|
AdminUserRespDTO user = userResult == null ? null : userResult.getCheckedData();
|
||||||
|
if (user == null || user.getDeptId() == null) {
|
||||||
|
throw invalidParamException("当前登录用户部门信息不完整");
|
||||||
|
}
|
||||||
|
CommonResult<DeptRespDTO> deptResult = deptApi.getDept(user.getDeptId());
|
||||||
|
DeptRespDTO dept = deptResult == null ? null : deptResult.getCheckedData();
|
||||||
|
if (dept == null || !StringUtils.hasText(dept.getName())) {
|
||||||
|
throw invalidParamException("当前登录用户部门信息不完整");
|
||||||
|
}
|
||||||
|
return new CurrentOperatorProfile(loginUserId, defaultText(SecurityFrameworkUtils.getLoginUserNickname()),
|
||||||
|
dept.getId(), dept.getName().trim());
|
||||||
|
}
|
||||||
|
|
||||||
private PerformanceSheetDO merge(PerformanceSheetDO source, PerformanceSheetDO update) {
|
private PerformanceSheetDO merge(PerformanceSheetDO source, PerformanceSheetDO update) {
|
||||||
PerformanceSheetDO merged = BeanUtils.toBean(source, PerformanceSheetDO.class);
|
PerformanceSheetDO merged = BeanUtils.toBean(source, PerformanceSheetDO.class);
|
||||||
if (update.getStatusCode() != null) {
|
if (update.getStatusCode() != null) {
|
||||||
@@ -1140,6 +1696,9 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
|||||||
if (update.getLastStatusReason() != null) {
|
if (update.getLastStatusReason() != null) {
|
||||||
merged.setLastStatusReason(update.getLastStatusReason());
|
merged.setLastStatusReason(update.getLastStatusReason());
|
||||||
}
|
}
|
||||||
|
if (update.getSignOffStatus() != null) {
|
||||||
|
merged.setSignOffStatus(update.getSignOffStatus());
|
||||||
|
}
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1258,4 +1817,13 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
|||||||
private final Map<Font, Font> fontCache = new IdentityHashMap<>();
|
private final Map<Font, Font> fontCache = new IdentityHashMap<>();
|
||||||
private final Map<String, Short> dataFormatCache = new HashMap<>();
|
private final Map<String, Short> dataFormatCache = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private record ImportedWorkbookEntry(String displayName, byte[] content) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private record PerformanceEmployeeResponseContext(PerformanceSheetSignOffDO signOff, boolean signOffFlow) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private record CurrentOperatorProfile(Long userId, String userName, Long deptId, String deptName) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.njcn.rdms.module.project.service.signoff;
|
||||||
|
|
||||||
|
import com.njcn.rdms.module.project.dal.dataobject.status.ObjectStatusModelDO;
|
||||||
|
import com.njcn.rdms.module.project.dal.dataobject.status.ObjectStatusTransitionDO;
|
||||||
|
|
||||||
|
public interface EmployeeSignOffStatusService {
|
||||||
|
|
||||||
|
String getInitialStatusCode();
|
||||||
|
|
||||||
|
String statusName(String statusCode);
|
||||||
|
|
||||||
|
ObjectStatusTransitionDO validateTransition(String fromStatus, String actionCode, String reason);
|
||||||
|
|
||||||
|
ObjectStatusModelDO validateStatusModel(String statusCode);
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package com.njcn.rdms.module.project.service.signoff;
|
||||||
|
|
||||||
|
import com.njcn.rdms.module.project.constant.SignOffConstants;
|
||||||
|
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.mysql.status.ObjectStatusModelMapper;
|
||||||
|
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusTransitionMapper;
|
||||||
|
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
|
||||||
|
import com.njcn.rdms.module.project.service.status.StatusActionTextResolver;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class EmployeeSignOffStatusServiceImpl implements EmployeeSignOffStatusService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ObjectStatusModelMapper objectStatusModelMapper;
|
||||||
|
@Resource
|
||||||
|
private ObjectStatusTransitionMapper objectStatusTransitionMapper;
|
||||||
|
@Resource
|
||||||
|
private StatusActionTextResolver statusActionTextResolver;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getInitialStatusCode() {
|
||||||
|
ObjectStatusModelDO model = objectStatusModelMapper.selectInitialByObjectTypeEnabled(SignOffConstants.STATUS_OBJECT_TYPE);
|
||||||
|
if (model == null || !StringUtils.hasText(model.getStatusCode())) {
|
||||||
|
throw exception(ErrorCodeConstants.SIGN_OFF_STATUS_MODEL_NOT_EXISTS_OR_DISABLED);
|
||||||
|
}
|
||||||
|
return model.getStatusCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String statusName(String statusCode) {
|
||||||
|
return statusActionTextResolver.statusName(SignOffConstants.STATUS_OBJECT_TYPE, statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectStatusTransitionDO validateTransition(String fromStatus, String actionCode, String reason) {
|
||||||
|
ObjectStatusTransitionDO transition = objectStatusTransitionMapper.selectByObjectTypeAndFromStatusAndAction(
|
||||||
|
SignOffConstants.STATUS_OBJECT_TYPE, fromStatus, actionCode);
|
||||||
|
if (transition == null) {
|
||||||
|
throw exception(ErrorCodeConstants.SIGN_OFF_STATUS_ACTION_NOT_ALLOWED,
|
||||||
|
statusActionTextResolver.statusName(SignOffConstants.STATUS_OBJECT_TYPE, fromStatus),
|
||||||
|
statusActionTextResolver.actionName(SignOffConstants.STATUS_OBJECT_TYPE, actionCode));
|
||||||
|
}
|
||||||
|
if (Boolean.TRUE.equals(transition.getNeedReason()) && !StringUtils.hasText(reason)) {
|
||||||
|
throw exception(ErrorCodeConstants.SIGN_OFF_STATUS_ACTION_REASON_REQUIRED,
|
||||||
|
statusActionTextResolver.actionName(SignOffConstants.STATUS_OBJECT_TYPE, actionCode));
|
||||||
|
}
|
||||||
|
validateStatusModel(transition.getToStatusCode());
|
||||||
|
return transition;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectStatusModelDO validateStatusModel(String statusCode) {
|
||||||
|
ObjectStatusModelDO model = objectStatusModelMapper.selectByObjectTypeAndStatusCodeEnabled(
|
||||||
|
SignOffConstants.STATUS_OBJECT_TYPE, statusCode);
|
||||||
|
if (model == null) {
|
||||||
|
throw exception(ErrorCodeConstants.SIGN_OFF_STATUS_MODEL_NOT_EXISTS_OR_DISABLED);
|
||||||
|
}
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import com.njcn.rdms.framework.common.pojo.PageResult;
|
|||||||
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.ProjectObjectConstants;
|
import com.njcn.rdms.module.project.constant.ProjectObjectConstants;
|
||||||
|
import com.njcn.rdms.module.project.constant.SignOffConstants;
|
||||||
import com.njcn.rdms.module.project.constant.WorkReportConstants;
|
import com.njcn.rdms.module.project.constant.WorkReportConstants;
|
||||||
import com.njcn.rdms.module.project.framework.notify.NotifySendEvent;
|
import com.njcn.rdms.module.project.framework.notify.NotifySendEvent;
|
||||||
import com.njcn.rdms.module.project.framework.notify.NotifyTemplateCodeConstants;
|
import com.njcn.rdms.module.project.framework.notify.NotifyTemplateCodeConstants;
|
||||||
@@ -24,6 +25,8 @@ import com.njcn.rdms.module.project.dal.dataobject.workreport.common.WorkReportM
|
|||||||
import com.njcn.rdms.module.project.dal.dataobject.workreport.common.WorkReportStatusLogDO;
|
import com.njcn.rdms.module.project.dal.dataobject.workreport.common.WorkReportStatusLogDO;
|
||||||
import com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportApprovalRecordDO;
|
import com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportApprovalRecordDO;
|
||||||
import com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportDO;
|
import com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportDO;
|
||||||
|
import com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportSignOffDO;
|
||||||
|
import com.njcn.rdms.module.project.dal.dataobject.workreport.monthly.MonthlyReportSignOffRecordDO;
|
||||||
import com.njcn.rdms.module.project.dal.dataobject.workreport.project.ProjectReportApprovalRecordDO;
|
import com.njcn.rdms.module.project.dal.dataobject.workreport.project.ProjectReportApprovalRecordDO;
|
||||||
import com.njcn.rdms.module.project.dal.dataobject.workreport.project.ProjectReportCurrentItemDO;
|
import com.njcn.rdms.module.project.dal.dataobject.workreport.project.ProjectReportCurrentItemDO;
|
||||||
import com.njcn.rdms.module.project.dal.dataobject.workreport.project.ProjectReportDO;
|
import com.njcn.rdms.module.project.dal.dataobject.workreport.project.ProjectReportDO;
|
||||||
@@ -41,6 +44,8 @@ import com.njcn.rdms.module.project.dal.mysql.workreport.common.PersonalReportRe
|
|||||||
import com.njcn.rdms.module.project.dal.mysql.workreport.common.WorkReportStatusLogMapper;
|
import com.njcn.rdms.module.project.dal.mysql.workreport.common.WorkReportStatusLogMapper;
|
||||||
import com.njcn.rdms.module.project.dal.mysql.workreport.monthly.MonthlyReportApprovalRecordMapper;
|
import com.njcn.rdms.module.project.dal.mysql.workreport.monthly.MonthlyReportApprovalRecordMapper;
|
||||||
import com.njcn.rdms.module.project.dal.mysql.workreport.monthly.MonthlyReportMapper;
|
import com.njcn.rdms.module.project.dal.mysql.workreport.monthly.MonthlyReportMapper;
|
||||||
|
import com.njcn.rdms.module.project.dal.mysql.workreport.monthly.MonthlyReportSignOffMapper;
|
||||||
|
import com.njcn.rdms.module.project.dal.mysql.workreport.monthly.MonthlyReportSignOffRecordMapper;
|
||||||
import com.njcn.rdms.module.project.dal.mysql.workreport.project.ProjectReportApprovalRecordMapper;
|
import com.njcn.rdms.module.project.dal.mysql.workreport.project.ProjectReportApprovalRecordMapper;
|
||||||
import com.njcn.rdms.module.project.dal.mysql.workreport.project.ProjectReportCurrentItemMapper;
|
import com.njcn.rdms.module.project.dal.mysql.workreport.project.ProjectReportCurrentItemMapper;
|
||||||
import com.njcn.rdms.module.project.dal.mysql.workreport.project.ProjectReportMapper;
|
import com.njcn.rdms.module.project.dal.mysql.workreport.project.ProjectReportMapper;
|
||||||
@@ -49,10 +54,12 @@ import com.njcn.rdms.module.project.dal.mysql.workreport.weekly.WeeklyReportAppr
|
|||||||
import com.njcn.rdms.module.project.dal.mysql.workreport.weekly.WeeklyReportMapper;
|
import com.njcn.rdms.module.project.dal.mysql.workreport.weekly.WeeklyReportMapper;
|
||||||
import com.njcn.rdms.module.project.dal.mysql.workreport.weekly.WeeklyReportTravelSegmentMapper;
|
import com.njcn.rdms.module.project.dal.mysql.workreport.weekly.WeeklyReportTravelSegmentMapper;
|
||||||
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
|
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
|
||||||
|
import com.njcn.rdms.module.project.service.signoff.EmployeeSignOffStatusService;
|
||||||
import com.njcn.rdms.module.project.service.status.StatusActionTextResolver;
|
import com.njcn.rdms.module.project.service.status.StatusActionTextResolver;
|
||||||
import com.njcn.rdms.module.project.service.team.TeamDashboardAccessService;
|
import com.njcn.rdms.module.project.service.team.TeamDashboardAccessService;
|
||||||
import com.njcn.rdms.module.system.api.dept.DeptApi;
|
import com.njcn.rdms.module.system.api.dept.DeptApi;
|
||||||
import com.njcn.rdms.module.system.api.dept.PostApi;
|
import com.njcn.rdms.module.system.api.dept.PostApi;
|
||||||
|
import com.njcn.rdms.module.system.api.user.UserSignatureApi;
|
||||||
import com.njcn.rdms.module.system.api.dept.dto.DeptRespDTO;
|
import com.njcn.rdms.module.system.api.dept.dto.DeptRespDTO;
|
||||||
import com.njcn.rdms.module.system.api.dept.dto.PostRespDTO;
|
import com.njcn.rdms.module.system.api.dept.dto.PostRespDTO;
|
||||||
import com.njcn.rdms.module.system.api.permission.ObjectPermissionApi;
|
import com.njcn.rdms.module.system.api.permission.ObjectPermissionApi;
|
||||||
@@ -60,6 +67,7 @@ import com.njcn.rdms.module.system.api.permission.dto.ObjectRoleRespDTO;
|
|||||||
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 com.njcn.rdms.module.system.api.user.UserManagementRelationApi;
|
||||||
import com.njcn.rdms.module.system.api.user.dto.AdminUserRespDTO;
|
import com.njcn.rdms.module.system.api.user.dto.AdminUserRespDTO;
|
||||||
|
import com.njcn.rdms.module.system.api.user.dto.UserSignatureRespDTO;
|
||||||
import com.njcn.rdms.module.system.enums.notify.NotifyMessageLevelConstants;
|
import com.njcn.rdms.module.system.enums.notify.NotifyMessageLevelConstants;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
@@ -109,6 +117,10 @@ public class WorkReportCommonService {
|
|||||||
@Resource
|
@Resource
|
||||||
private MonthlyReportApprovalRecordMapper monthlyReportApprovalRecordMapper;
|
private MonthlyReportApprovalRecordMapper monthlyReportApprovalRecordMapper;
|
||||||
@Resource
|
@Resource
|
||||||
|
private MonthlyReportSignOffMapper monthlyReportSignOffMapper;
|
||||||
|
@Resource
|
||||||
|
private MonthlyReportSignOffRecordMapper monthlyReportSignOffRecordMapper;
|
||||||
|
@Resource
|
||||||
private ProjectReportApprovalRecordMapper projectReportApprovalRecordMapper;
|
private ProjectReportApprovalRecordMapper projectReportApprovalRecordMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private WorkReportStatusLogMapper workReportStatusLogMapper;
|
private WorkReportStatusLogMapper workReportStatusLogMapper;
|
||||||
@@ -121,6 +133,8 @@ public class WorkReportCommonService {
|
|||||||
@Resource
|
@Resource
|
||||||
private StatusActionTextResolver statusActionTextResolver;
|
private StatusActionTextResolver statusActionTextResolver;
|
||||||
@Resource
|
@Resource
|
||||||
|
private EmployeeSignOffStatusService employeeSignOffStatusService;
|
||||||
|
@Resource
|
||||||
private AdminUserApi adminUserApi;
|
private AdminUserApi adminUserApi;
|
||||||
@Resource
|
@Resource
|
||||||
private DeptApi deptApi;
|
private DeptApi deptApi;
|
||||||
@@ -129,6 +143,8 @@ public class WorkReportCommonService {
|
|||||||
@Resource
|
@Resource
|
||||||
private UserManagementRelationApi userManagementRelationApi;
|
private UserManagementRelationApi userManagementRelationApi;
|
||||||
@Resource
|
@Resource
|
||||||
|
private UserSignatureApi userSignatureApi;
|
||||||
|
@Resource
|
||||||
private ObjectPermissionApi objectPermissionApi;
|
private ObjectPermissionApi objectPermissionApi;
|
||||||
@Resource
|
@Resource
|
||||||
private ProjectMapper projectMapper;
|
private ProjectMapper projectMapper;
|
||||||
@@ -368,6 +384,7 @@ public class WorkReportCommonService {
|
|||||||
MonthlyReportDO report = new MonthlyReportDO();
|
MonthlyReportDO report = new MonthlyReportDO();
|
||||||
applyMonthlySaveFields(report, reqVO, profile);
|
applyMonthlySaveFields(report, reqVO, profile);
|
||||||
report.setStatusCode(getInitialStatusCode());
|
report.setStatusCode(getInitialStatusCode());
|
||||||
|
report.setSignOffStatus(SignOffConstants.STATUS_NOT_STARTED);
|
||||||
monthlyReportMapper.insert(report);
|
monthlyReportMapper.insert(report);
|
||||||
replaceMonthlyChildren(report.getId(), reqVO);
|
replaceMonthlyChildren(report.getId(), reqVO);
|
||||||
MonthlyReportDO latest = monthlyReportMapper.selectById(report.getId());
|
MonthlyReportDO latest = monthlyReportMapper.selectById(report.getId());
|
||||||
@@ -439,6 +456,29 @@ public class WorkReportCommonService {
|
|||||||
.collect(Collectors.toList()), pageResult.getTotal());
|
.collect(Collectors.toList()), pageResult.getTotal());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PageResult<MonthlyReportRespVO> getMonthlySignOffPage(MonthlyReportPageReqVO reqVO) {
|
||||||
|
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
|
reqVO.setStatusCode(WorkReportConstants.STATUS_APPROVED);
|
||||||
|
reqVO.setSignOffStatus(SignOffConstants.STATUS_PENDING_EMPLOYEE_CONFIRM);
|
||||||
|
PageResult<MonthlyReportDO> pageResult = monthlyReportMapper.selectReporterPage(loginUserId, reqVO,
|
||||||
|
List.of(WorkReportConstants.STATUS_APPROVED));
|
||||||
|
return new PageResult<>(pageResult.getList().stream()
|
||||||
|
.map(report -> toMonthlyRespVO(report, false))
|
||||||
|
.collect(Collectors.toList()), pageResult.getTotal());
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonthlyReportSignOffDetailRespVO getMonthlySignOffDetail(Long id) {
|
||||||
|
MonthlyReportDO report = validateMonthlyReportExists(id);
|
||||||
|
validateReporter(SecurityFrameworkUtils.getLoginUserId(), report.getReporterId());
|
||||||
|
MonthlyReportSignOffDetailRespVO respVO = new MonthlyReportSignOffDetailRespVO();
|
||||||
|
respVO.setReport(toMonthlyRespVO(report, true));
|
||||||
|
MonthlyReportApprovalRecordDO latestApprovalRecord = monthlyReportApprovalRecordMapper
|
||||||
|
.selectLatestApprovedByMonthlyReportId(id);
|
||||||
|
respVO.setLatestApprovalRecord(latestApprovalRecord == null ? null
|
||||||
|
: BeanUtils.toBean(latestApprovalRecord, MonthlyReportApprovalRecordRespVO.class));
|
||||||
|
return respVO;
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void submitMonthlyReport(Long id) {
|
public void submitMonthlyReport(Long id) {
|
||||||
MonthlyReportDO current = validateMonthlyReportExists(id);
|
MonthlyReportDO current = validateMonthlyReportExists(id);
|
||||||
@@ -478,6 +518,55 @@ public class WorkReportCommonService {
|
|||||||
processMonthlyApproval(id, WorkReportConstants.ACTION_REJECT, rejectReqVO);
|
processMonthlyApproval(id, WorkReportConstants.ACTION_REJECT, rejectReqVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void confirmMonthlySignOff(Long id, MonthlyReportSignOffConfirmReqVO reqVO) {
|
||||||
|
MonthlyReportDO current = validateMonthlyReportExists(id);
|
||||||
|
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
|
validateReporter(loginUserId, current.getReporterId());
|
||||||
|
if (!WorkReportConstants.STATUS_APPROVED.equals(current.getStatusCode())
|
||||||
|
|| !SignOffConstants.STATUS_PENDING_EMPLOYEE_CONFIRM.equals(current.getSignOffStatus())) {
|
||||||
|
throw exception(ErrorCodeConstants.WORK_REPORT_SIGN_OFF_NOT_ALLOWED);
|
||||||
|
}
|
||||||
|
MonthlyReportSignOffDO signOff = validateMonthlySignOffExists(current.getId());
|
||||||
|
employeeSignOffStatusService.validateTransition(signOff.getStatusCode(), SignOffConstants.ACTION_CONFIRM, null);
|
||||||
|
MonthlyReportApprovalRecordDO approvalRecord = monthlyReportApprovalRecordMapper
|
||||||
|
.selectLatestApprovedByMonthlyReportId(current.getId());
|
||||||
|
if (approvalRecord == null) {
|
||||||
|
throw exception(ErrorCodeConstants.WORK_REPORT_MONTHLY_SIGN_OFF_APPROVAL_RECORD_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserSignatureRespDTO userSignature = getUserSignature(loginUserId);
|
||||||
|
LocalDate signedDate = reqVO.getEmployeeSignedDate() != null ? reqVO.getEmployeeSignedDate() : LocalDate.now();
|
||||||
|
MonthlyReportApprovalRecordDO approvalUpdate = new MonthlyReportApprovalRecordDO();
|
||||||
|
approvalUpdate.setId(approvalRecord.getId());
|
||||||
|
approvalUpdate.setMeetingDate(reqVO.getMeetingDate());
|
||||||
|
approvalUpdate.setEmployeeSignName(defaultText(SecurityFrameworkUtils.getLoginUserNickname()));
|
||||||
|
approvalUpdate.setEmployeeSignatureFileId(userSignature == null ? null : userSignature.getFileId());
|
||||||
|
approvalUpdate.setEmployeeSignedDate(signedDate);
|
||||||
|
monthlyReportApprovalRecordMapper.updateById(approvalUpdate);
|
||||||
|
|
||||||
|
MonthlyReportDO reportUpdate = new MonthlyReportDO();
|
||||||
|
reportUpdate.setSignOffStatus(SignOffConstants.STATUS_EMPLOYEE_CONFIRMED);
|
||||||
|
int reportUpdateCount = monthlyReportMapper.updateByIdAndStatusAndSignOffStatus(reportUpdate, current.getId(),
|
||||||
|
current.getStatusCode(), current.getSignOffStatus());
|
||||||
|
if (reportUpdateCount != 1) {
|
||||||
|
throw exception(ErrorCodeConstants.WORK_REPORT_STATUS_CONCURRENT_MODIFIED);
|
||||||
|
}
|
||||||
|
|
||||||
|
MonthlyReportSignOffDO signOffUpdate = new MonthlyReportSignOffDO();
|
||||||
|
signOffUpdate.setStatusCode(SignOffConstants.STATUS_EMPLOYEE_CONFIRMED);
|
||||||
|
signOffUpdate.setConfirmUserId(loginUserId);
|
||||||
|
signOffUpdate.setConfirmUserName(defaultText(SecurityFrameworkUtils.getLoginUserNickname()));
|
||||||
|
signOffUpdate.setConfirmTime(LocalDateTime.now());
|
||||||
|
int signOffUpdateCount = monthlyReportSignOffMapper.updateByMonthlyReportIdAndStatus(signOffUpdate,
|
||||||
|
current.getId(), signOff.getStatusCode());
|
||||||
|
if (signOffUpdateCount != 1) {
|
||||||
|
throw exception(ErrorCodeConstants.WORK_REPORT_STATUS_CONCURRENT_MODIFIED);
|
||||||
|
}
|
||||||
|
writeMonthlySignOffRecord(signOff.getId(), current.getId(), approvalRecord.getId(), signOff.getBatchNo(),
|
||||||
|
SignOffConstants.ACTION_CONFIRM, signOff.getStatusCode(), SignOffConstants.STATUS_EMPLOYEE_CONFIRMED);
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void deleteMonthlyReport(Long id) {
|
public void deleteMonthlyReport(Long id) {
|
||||||
MonthlyReportDO current = validateMonthlyReportExists(id);
|
MonthlyReportDO current = validateMonthlyReportExists(id);
|
||||||
@@ -513,6 +602,89 @@ public class WorkReportCommonService {
|
|||||||
return BeanUtils.toBean(getMonthlyReportPage(reqVO).getList(), MonthlyReportExportVO.class);
|
return BeanUtils.toBean(getMonthlyReportPage(reqVO).getList(), MonthlyReportExportVO.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<MonthlyReportDO> listMonthlyReportsForSignOff(Collection<Long> reporterIds, String periodMonth) {
|
||||||
|
return monthlyReportMapper.selectListByReporterIdsAndPeriodKey(reporterIds, periodMonth,
|
||||||
|
List.of(WorkReportConstants.STATUS_APPROVED));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void issueMonthlySignOff(List<MonthlyReportDO> reports, Long batchNo) {
|
||||||
|
if (reports == null || reports.isEmpty()) {
|
||||||
|
throw exception(ErrorCodeConstants.WORK_REPORT_MONTHLY_SIGN_OFF_CANDIDATE_EMPTY);
|
||||||
|
}
|
||||||
|
Long operatorUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
|
String operatorName = defaultText(SecurityFrameworkUtils.getLoginUserNickname());
|
||||||
|
LocalDateTime issueTime = LocalDateTime.now();
|
||||||
|
for (MonthlyReportDO report : reports) {
|
||||||
|
if (!WorkReportConstants.STATUS_APPROVED.equals(report.getStatusCode())
|
||||||
|
|| !isIssueAllowed(report.getSignOffStatus())) {
|
||||||
|
throw exception(ErrorCodeConstants.WORK_REPORT_SIGN_OFF_NOT_ALLOWED);
|
||||||
|
}
|
||||||
|
MonthlyReportApprovalRecordDO approvalRecord = monthlyReportApprovalRecordMapper
|
||||||
|
.selectLatestApprovedByMonthlyReportId(report.getId());
|
||||||
|
if (approvalRecord == null) {
|
||||||
|
throw exception(ErrorCodeConstants.WORK_REPORT_MONTHLY_SIGN_OFF_APPROVAL_RECORD_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
MonthlyReportDO reportUpdate = new MonthlyReportDO();
|
||||||
|
reportUpdate.setSignOffStatus(SignOffConstants.STATUS_PENDING_EMPLOYEE_CONFIRM);
|
||||||
|
int reportUpdateCount = monthlyReportMapper.updateByIdAndStatusAndSignOffStatus(reportUpdate, report.getId(),
|
||||||
|
report.getStatusCode(), report.getSignOffStatus());
|
||||||
|
if (reportUpdateCount != 1) {
|
||||||
|
throw exception(ErrorCodeConstants.WORK_REPORT_STATUS_CONCURRENT_MODIFIED);
|
||||||
|
}
|
||||||
|
|
||||||
|
MonthlyReportSignOffDO currentSignOff = monthlyReportSignOffMapper.selectByMonthlyReportId(report.getId());
|
||||||
|
if (currentSignOff == null) {
|
||||||
|
MonthlyReportSignOffDO signOff = new MonthlyReportSignOffDO();
|
||||||
|
signOff.setMonthlyReportId(report.getId());
|
||||||
|
signOff.setBatchNo(batchNo);
|
||||||
|
signOff.setStatusCode(SignOffConstants.STATUS_PENDING_EMPLOYEE_CONFIRM);
|
||||||
|
signOff.setIssueUserId(operatorUserId);
|
||||||
|
signOff.setIssueUserName(operatorName);
|
||||||
|
signOff.setIssueTime(issueTime);
|
||||||
|
monthlyReportSignOffMapper.insert(signOff);
|
||||||
|
writeMonthlySignOffRecord(signOff.getId(), report.getId(), approvalRecord.getId(), batchNo,
|
||||||
|
SignOffConstants.ACTION_ISSUE, SignOffConstants.STATUS_NOT_STARTED,
|
||||||
|
SignOffConstants.STATUS_PENDING_EMPLOYEE_CONFIRM);
|
||||||
|
} else {
|
||||||
|
employeeSignOffStatusService.validateTransition(currentSignOff.getStatusCode(), SignOffConstants.ACTION_ISSUE, null);
|
||||||
|
MonthlyReportSignOffDO signOffUpdate = new MonthlyReportSignOffDO();
|
||||||
|
signOffUpdate.setStatusCode(SignOffConstants.STATUS_PENDING_EMPLOYEE_CONFIRM);
|
||||||
|
signOffUpdate.setBatchNo(batchNo);
|
||||||
|
signOffUpdate.setIssueUserId(operatorUserId);
|
||||||
|
signOffUpdate.setIssueUserName(operatorName);
|
||||||
|
signOffUpdate.setIssueTime(issueTime);
|
||||||
|
signOffUpdate.setConfirmUserId(null);
|
||||||
|
signOffUpdate.setConfirmUserName(null);
|
||||||
|
signOffUpdate.setConfirmTime(null);
|
||||||
|
int signOffUpdateCount = monthlyReportSignOffMapper.updateByMonthlyReportIdAndStatus(signOffUpdate,
|
||||||
|
report.getId(), currentSignOff.getStatusCode());
|
||||||
|
if (signOffUpdateCount != 1) {
|
||||||
|
throw exception(ErrorCodeConstants.WORK_REPORT_STATUS_CONCURRENT_MODIFIED);
|
||||||
|
}
|
||||||
|
writeMonthlySignOffRecord(currentSignOff.getId(), report.getId(), approvalRecord.getId(), batchNo,
|
||||||
|
SignOffConstants.ACTION_ISSUE, currentSignOff.getStatusCode(),
|
||||||
|
SignOffConstants.STATUS_PENDING_EMPLOYEE_CONFIRM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void syncPerformanceResult(Long reporterId, String periodMonth, String performanceResult) {
|
||||||
|
MonthlyReportDO report = monthlyReportMapper.selectByReporterIdAndPeriodKey(reporterId, periodMonth);
|
||||||
|
if (report == null) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_MONTHLY_REPORT_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
MonthlyReportApprovalRecordDO approvalRecord = monthlyReportApprovalRecordMapper
|
||||||
|
.selectLatestApprovedByMonthlyReportId(report.getId());
|
||||||
|
if (approvalRecord == null) {
|
||||||
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_MONTHLY_APPROVAL_RECORD_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
MonthlyReportApprovalRecordDO update = new MonthlyReportApprovalRecordDO();
|
||||||
|
update.setId(approvalRecord.getId());
|
||||||
|
update.setPerformanceResult(performanceResult);
|
||||||
|
monthlyReportApprovalRecordMapper.updateById(update);
|
||||||
|
}
|
||||||
|
|
||||||
public ProjectReportRespVO initProjectReport(Long projectId) {
|
public ProjectReportRespVO initProjectReport(Long projectId) {
|
||||||
CurrentUserProfile profile = loadCurrentUserProfile(true);
|
CurrentUserProfile profile = loadCurrentUserProfile(true);
|
||||||
ProjectDO project = validateProjectExists(projectId);
|
ProjectDO project = validateProjectExists(projectId);
|
||||||
@@ -810,6 +982,14 @@ public class WorkReportCommonService {
|
|||||||
return report;
|
return report;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MonthlyReportSignOffDO validateMonthlySignOffExists(Long monthlyReportId) {
|
||||||
|
MonthlyReportSignOffDO signOff = monthlyReportSignOffMapper.selectByMonthlyReportId(monthlyReportId);
|
||||||
|
if (signOff == null) {
|
||||||
|
throw exception(ErrorCodeConstants.WORK_REPORT_MONTHLY_SIGN_OFF_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
return signOff;
|
||||||
|
}
|
||||||
|
|
||||||
private ProjectReportDO validateReadableProjectReport(Long id) {
|
private ProjectReportDO validateReadableProjectReport(Long id) {
|
||||||
ProjectReportDO report = validateProjectReportExists(id);
|
ProjectReportDO report = validateProjectReportExists(id);
|
||||||
validateReadable(report.getProjectOwnerId(), report.getSupervisorUserId());
|
validateReadable(report.getProjectOwnerId(), report.getSupervisorUserId());
|
||||||
@@ -1438,6 +1618,7 @@ public class WorkReportCommonService {
|
|||||||
record.setConclusion(statusLog.getToStatus());
|
record.setConclusion(statusLog.getToStatus());
|
||||||
record.setOpinion(normalizeReason(reqVO));
|
record.setOpinion(normalizeReason(reqVO));
|
||||||
if (WorkReportConstants.ACTION_APPROVE.equals(actionCode)) {
|
if (WorkReportConstants.ACTION_APPROVE.equals(actionCode)) {
|
||||||
|
UserSignatureRespDTO userSignature = getUserSignature(SecurityFrameworkUtils.getLoginUserId());
|
||||||
record.setMeetingDate(reqVO.getMeetingDate());
|
record.setMeetingDate(reqVO.getMeetingDate());
|
||||||
record.setStrengthDesc(normalizeNullableText(reqVO.getStrengthDesc()));
|
record.setStrengthDesc(normalizeNullableText(reqVO.getStrengthDesc()));
|
||||||
record.setStrengthExample(normalizeNullableText(reqVO.getStrengthExample()));
|
record.setStrengthExample(normalizeNullableText(reqVO.getStrengthExample()));
|
||||||
@@ -1446,15 +1627,32 @@ public class WorkReportCommonService {
|
|||||||
record.setImprovementSuggestion(normalizeNullableText(reqVO.getImprovementSuggestion()));
|
record.setImprovementSuggestion(normalizeNullableText(reqVO.getImprovementSuggestion()));
|
||||||
record.setPerformanceResult(normalizeNullableText(reqVO.getPerformanceResult()));
|
record.setPerformanceResult(normalizeNullableText(reqVO.getPerformanceResult()));
|
||||||
record.setEmployeeSignName(normalizeNullableText(reqVO.getEmployeeSignName()));
|
record.setEmployeeSignName(normalizeNullableText(reqVO.getEmployeeSignName()));
|
||||||
|
record.setEmployeeSignatureFileId(null);
|
||||||
record.setEmployeeSignedDate(reqVO.getEmployeeSignedDate());
|
record.setEmployeeSignedDate(reqVO.getEmployeeSignedDate());
|
||||||
record.setSupervisorSignName(normalizeNullableText(reqVO.getSupervisorSignName()));
|
record.setSupervisorSignName(defaultText(SecurityFrameworkUtils.getLoginUserNickname()));
|
||||||
record.setSupervisorSignedDate(reqVO.getSupervisorSignedDate());
|
record.setSupervisorSignatureFileId(userSignature == null ? null : userSignature.getFileId());
|
||||||
|
record.setSupervisorSignedDate(LocalDate.now());
|
||||||
}
|
}
|
||||||
record.setAuditorUserId(SecurityFrameworkUtils.getLoginUserId());
|
record.setAuditorUserId(SecurityFrameworkUtils.getLoginUserId());
|
||||||
record.setAuditorName(defaultText(SecurityFrameworkUtils.getLoginUserNickname()));
|
record.setAuditorName(defaultText(SecurityFrameworkUtils.getLoginUserNickname()));
|
||||||
monthlyReportApprovalRecordMapper.insert(record);
|
monthlyReportApprovalRecordMapper.insert(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeMonthlySignOffRecord(Long signOffId, Long monthlyReportId, Long approvalRecordId, Long batchNo,
|
||||||
|
String actionType, String fromStatus, String toStatus) {
|
||||||
|
MonthlyReportSignOffRecordDO record = new MonthlyReportSignOffRecordDO();
|
||||||
|
record.setSignOffId(signOffId);
|
||||||
|
record.setMonthlyReportId(monthlyReportId);
|
||||||
|
record.setApprovalRecordId(approvalRecordId);
|
||||||
|
record.setBatchNo(batchNo);
|
||||||
|
record.setActionType(actionType);
|
||||||
|
record.setFromSignOffStatus(fromStatus);
|
||||||
|
record.setToSignOffStatus(toStatus);
|
||||||
|
record.setOperatorUserId(SecurityFrameworkUtils.getLoginUserId());
|
||||||
|
record.setOperatorName(defaultText(SecurityFrameworkUtils.getLoginUserNickname()));
|
||||||
|
monthlyReportSignOffRecordMapper.insert(record);
|
||||||
|
}
|
||||||
|
|
||||||
private void writeProjectApprovalRecord(ProjectReportDO report, WorkReportStatusLogDO statusLog, String reason) {
|
private void writeProjectApprovalRecord(ProjectReportDO report, WorkReportStatusLogDO statusLog, String reason) {
|
||||||
ProjectReportApprovalRecordDO record = new ProjectReportApprovalRecordDO();
|
ProjectReportApprovalRecordDO record = new ProjectReportApprovalRecordDO();
|
||||||
record.setProjectReportId(report.getId());
|
record.setProjectReportId(report.getId());
|
||||||
@@ -1513,6 +1711,11 @@ public class WorkReportCommonService {
|
|||||||
private MonthlyReportRespVO toMonthlyRespVO(MonthlyReportDO report, boolean withChildren) {
|
private MonthlyReportRespVO toMonthlyRespVO(MonthlyReportDO report, boolean withChildren) {
|
||||||
MonthlyReportRespVO respVO = BeanUtils.toBean(report, MonthlyReportRespVO.class);
|
MonthlyReportRespVO respVO = BeanUtils.toBean(report, MonthlyReportRespVO.class);
|
||||||
applyStatusView(respVO, getStatusModel(report.getStatusCode()));
|
applyStatusView(respVO, getStatusModel(report.getStatusCode()));
|
||||||
|
String signOffStatus = StringUtils.hasText(report.getSignOffStatus())
|
||||||
|
? report.getSignOffStatus()
|
||||||
|
: SignOffConstants.STATUS_NOT_STARTED;
|
||||||
|
respVO.setSignOffStatus(signOffStatus);
|
||||||
|
respVO.setSignOffStatusName(employeeSignOffStatusService.statusName(signOffStatus));
|
||||||
if (withChildren) {
|
if (withChildren) {
|
||||||
respVO.setReviewItems(BeanUtils.toBean(
|
respVO.setReviewItems(BeanUtils.toBean(
|
||||||
personalReportReviewItemMapper.selectListByReport(WorkReportConstants.REPORT_TYPE_MONTHLY, report.getId()),
|
personalReportReviewItemMapper.selectListByReport(WorkReportConstants.REPORT_TYPE_MONTHLY, report.getId()),
|
||||||
@@ -1704,6 +1907,19 @@ public class WorkReportCommonService {
|
|||||||
return StringUtils.hasText(value) ? value.trim() : "";
|
return StringUtils.hasText(value) ? value.trim() : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isIssueAllowed(String signOffStatus) {
|
||||||
|
return !StringUtils.hasText(signOffStatus)
|
||||||
|
|| SignOffConstants.STATUS_NOT_STARTED.equals(signOffStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserSignatureRespDTO getUserSignature(Long userId) {
|
||||||
|
if (userId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
CommonResult<UserSignatureRespDTO> result = userSignatureApi.getByUserId(userId);
|
||||||
|
return result == null ? null : result.getCheckedData();
|
||||||
|
}
|
||||||
|
|
||||||
private <T> List<T> defaultList(List<T> list) {
|
private <T> List<T> defaultList(List<T> list) {
|
||||||
return list == null ? Collections.emptyList() : list;
|
return list == null ? Collections.emptyList() : list;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.Month
|
|||||||
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportRefreshDraftReqVO;
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportRefreshDraftReqVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportRespVO;
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportSaveReqVO;
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportSaveReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportSignOffConfirmReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportSignOffDetailRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusActionReqVO;
|
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.common.vo.WorkReportStatusLogRespVO;
|
||||||
|
|
||||||
@@ -32,12 +34,18 @@ public interface MonthlyReportService {
|
|||||||
|
|
||||||
PageResult<MonthlyReportRespVO> getMonthlyApprovalPage(MonthlyReportPageReqVO reqVO);
|
PageResult<MonthlyReportRespVO> getMonthlyApprovalPage(MonthlyReportPageReqVO reqVO);
|
||||||
|
|
||||||
|
PageResult<MonthlyReportRespVO> getMonthlySignOffPage(MonthlyReportPageReqVO reqVO);
|
||||||
|
|
||||||
|
MonthlyReportSignOffDetailRespVO getMonthlySignOffDetail(Long id);
|
||||||
|
|
||||||
void submitMonthlyReport(Long id);
|
void submitMonthlyReport(Long id);
|
||||||
|
|
||||||
void approveMonthlyReport(Long id, MonthlyReportApproveReqVO reqVO);
|
void approveMonthlyReport(Long id, MonthlyReportApproveReqVO reqVO);
|
||||||
|
|
||||||
void rejectMonthlyReport(Long id, WorkReportStatusActionReqVO reqVO);
|
void rejectMonthlyReport(Long id, WorkReportStatusActionReqVO reqVO);
|
||||||
|
|
||||||
|
void confirmMonthlySignOff(Long id, MonthlyReportSignOffConfirmReqVO reqVO);
|
||||||
|
|
||||||
void deleteMonthlyReport(Long id);
|
void deleteMonthlyReport(Long id);
|
||||||
|
|
||||||
List<WorkReportStatusLogRespVO> getMonthlyStatusLogs(Long id);
|
List<WorkReportStatusLogRespVO> getMonthlyStatusLogs(Long id);
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.Month
|
|||||||
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportRefreshDraftReqVO;
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportRefreshDraftReqVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportRespVO;
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportSaveReqVO;
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportSaveReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportSignOffConfirmReqVO;
|
||||||
|
import com.njcn.rdms.module.project.controller.admin.workreport.monthly.vo.MonthlyReportSignOffDetailRespVO;
|
||||||
import com.njcn.rdms.module.project.controller.admin.workreport.common.vo.WorkReportStatusActionReqVO;
|
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.common.vo.WorkReportStatusLogRespVO;
|
||||||
import com.njcn.rdms.module.project.service.workreport.common.WorkReportCommonService;
|
import com.njcn.rdms.module.project.service.workreport.common.WorkReportCommonService;
|
||||||
@@ -71,6 +73,16 @@ public class MonthlyReportServiceImpl implements MonthlyReportService {
|
|||||||
return workReportCommonService.getMonthlyApprovalPage(reqVO);
|
return workReportCommonService.getMonthlyApprovalPage(reqVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<MonthlyReportRespVO> getMonthlySignOffPage(MonthlyReportPageReqVO reqVO) {
|
||||||
|
return workReportCommonService.getMonthlySignOffPage(reqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MonthlyReportSignOffDetailRespVO getMonthlySignOffDetail(Long id) {
|
||||||
|
return workReportCommonService.getMonthlySignOffDetail(id);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void submitMonthlyReport(Long id) {
|
public void submitMonthlyReport(Long id) {
|
||||||
workReportCommonService.submitMonthlyReport(id);
|
workReportCommonService.submitMonthlyReport(id);
|
||||||
@@ -86,6 +98,11 @@ public class MonthlyReportServiceImpl implements MonthlyReportService {
|
|||||||
workReportCommonService.rejectMonthlyReport(id, reqVO);
|
workReportCommonService.rejectMonthlyReport(id, reqVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void confirmMonthlySignOff(Long id, MonthlyReportSignOffConfirmReqVO reqVO) {
|
||||||
|
workReportCommonService.confirmMonthlySignOff(id, reqVO);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteMonthlyReport(Long id) {
|
public void deleteMonthlyReport(Long id) {
|
||||||
workReportCommonService.deleteMonthlyReport(id);
|
workReportCommonService.deleteMonthlyReport(id);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.njcn.rdms.module.system.api.file;
|
package com.njcn.rdms.module.system.api.file;
|
||||||
|
|
||||||
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||||
|
import com.njcn.rdms.module.system.api.file.dto.FileContentCreateReqDTO;
|
||||||
import com.njcn.rdms.module.system.api.file.dto.FileRespDTO;
|
import com.njcn.rdms.module.system.api.file.dto.FileRespDTO;
|
||||||
import com.njcn.rdms.module.system.enums.ApiConstants;
|
import com.njcn.rdms.module.system.enums.ApiConstants;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@@ -8,6 +9,8 @@ import io.swagger.v3.oas.annotations.Parameter;
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
@FeignClient(name = ApiConstants.NAME)
|
@FeignClient(name = ApiConstants.NAME)
|
||||||
@@ -31,4 +34,8 @@ public interface FileApi {
|
|||||||
@Parameter(name = "id", description = "文件 ID", required = true)
|
@Parameter(name = "id", description = "文件 ID", required = true)
|
||||||
CommonResult<byte[]> getFileContent(@RequestParam("id") Long id);
|
CommonResult<byte[]> getFileContent(@RequestParam("id") Long id);
|
||||||
|
|
||||||
|
@PostMapping(PREFIX + "/create-by-content")
|
||||||
|
@Operation(summary = "通过文件字节创建文件")
|
||||||
|
CommonResult<Long> createFileByContent(@RequestBody FileContentCreateReqDTO reqDTO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.njcn.rdms.module.system.api.file.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Schema(description = "RPC 服务 - 文件字节创建 Request DTO")
|
||||||
|
@Data
|
||||||
|
public class FileContentCreateReqDTO {
|
||||||
|
|
||||||
|
@Schema(description = "文件内容", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private byte[] content;
|
||||||
|
|
||||||
|
@Schema(description = "文件名", example = "2026-06_张三.xlsx")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "目录", example = "rdms/performance")
|
||||||
|
private String directory;
|
||||||
|
|
||||||
|
@Schema(description = "MIME 类型", example = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||||
|
private String type;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.njcn.rdms.module.system.api.user;
|
||||||
|
|
||||||
|
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||||
|
import com.njcn.rdms.module.system.api.user.dto.UserSignatureRespDTO;
|
||||||
|
import com.njcn.rdms.module.system.enums.ApiConstants;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
|
@FeignClient(name = ApiConstants.NAME)
|
||||||
|
@Tag(name = "RPC 服务 - 用户电子签名")
|
||||||
|
public interface UserSignatureApi {
|
||||||
|
|
||||||
|
String PREFIX = ApiConstants.PREFIX + "/user-signature";
|
||||||
|
|
||||||
|
@GetMapping(PREFIX + "/get")
|
||||||
|
@Operation(summary = "根据用户 ID 查询电子签名")
|
||||||
|
@Parameter(name = "userId", description = "用户 ID", required = true)
|
||||||
|
CommonResult<UserSignatureRespDTO> getByUserId(@RequestParam("userId") Long userId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.njcn.rdms.module.system.api.user.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Schema(description = "RPC 服务 - 用户电子签名 Response DTO")
|
||||||
|
@Data
|
||||||
|
public class UserSignatureRespDTO {
|
||||||
|
|
||||||
|
@Schema(description = "主键", example = "1")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "用户 ID", example = "1024")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@Schema(description = "文件 ID", example = "2048")
|
||||||
|
private Long fileId;
|
||||||
|
|
||||||
|
@Schema(description = "文件名", example = "zhangsan-sign.png")
|
||||||
|
private String fileName;
|
||||||
|
|
||||||
|
@Schema(description = "状态", example = "0")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "备注")
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package com.njcn.rdms.module.system.api.file;
|
|||||||
|
|
||||||
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||||
import com.njcn.rdms.framework.common.util.object.BeanUtils;
|
import com.njcn.rdms.framework.common.util.object.BeanUtils;
|
||||||
|
import com.njcn.rdms.module.system.api.file.dto.FileContentCreateReqDTO;
|
||||||
import com.njcn.rdms.module.system.api.file.dto.FileRespDTO;
|
import com.njcn.rdms.module.system.api.file.dto.FileRespDTO;
|
||||||
import com.njcn.rdms.module.system.dal.dataobject.file.FileDO;
|
import com.njcn.rdms.module.system.dal.dataobject.file.FileDO;
|
||||||
import com.njcn.rdms.module.system.service.file.FileService;
|
import com.njcn.rdms.module.system.service.file.FileService;
|
||||||
@@ -45,4 +46,10 @@ public class FileApiImpl implements FileApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonResult<Long> createFileByContent(FileContentCreateReqDTO reqDTO) {
|
||||||
|
FileDO file = fileService.createFile(reqDTO.getContent(), reqDTO.getName(), reqDTO.getDirectory(), reqDTO.getType());
|
||||||
|
return success(file.getId());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.njcn.rdms.module.system.api.user;
|
||||||
|
|
||||||
|
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||||
|
import com.njcn.rdms.framework.common.util.object.BeanUtils;
|
||||||
|
import com.njcn.rdms.module.system.api.user.dto.UserSignatureRespDTO;
|
||||||
|
import com.njcn.rdms.module.system.dal.dataobject.user.UserSignatureDO;
|
||||||
|
import com.njcn.rdms.module.system.service.user.UserSignatureService;
|
||||||
|
import io.swagger.v3.oas.annotations.Hidden;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@Validated
|
||||||
|
@Hidden
|
||||||
|
public class UserSignatureApiImpl implements UserSignatureApi {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserSignatureService userSignatureService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonResult<UserSignatureRespDTO> getByUserId(Long userId) {
|
||||||
|
UserSignatureDO signature = userSignatureService.getByUserId(userId);
|
||||||
|
return success(BeanUtils.toBean(signature, UserSignatureRespDTO.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package com.njcn.rdms.module.system.controller.admin.user;
|
||||||
|
|
||||||
|
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||||
|
import com.njcn.rdms.framework.common.util.object.BeanUtils;
|
||||||
|
import com.njcn.rdms.module.system.controller.admin.user.vo.signature.UserSignatureRespVO;
|
||||||
|
import com.njcn.rdms.module.system.controller.admin.user.vo.signature.UserSignatureSaveReqVO;
|
||||||
|
import com.njcn.rdms.module.system.dal.dataobject.user.UserSignatureDO;
|
||||||
|
import com.njcn.rdms.module.system.service.user.UserSignatureService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
|
||||||
|
import static com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||||
|
|
||||||
|
@Tag(name = "管理后台 - 用户电子签名")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/system/user-signatures")
|
||||||
|
@Validated
|
||||||
|
public class UserSignatureController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserSignatureService userSignatureService;
|
||||||
|
|
||||||
|
@GetMapping("/get")
|
||||||
|
@Operation(summary = "获取用户电子签名")
|
||||||
|
@Parameter(name = "userId", description = "用户 ID", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:user-signature:query')")
|
||||||
|
public CommonResult<UserSignatureRespVO> get(@RequestParam("userId") Long userId) {
|
||||||
|
return success(toRespVO(userSignatureService.getByUserId(userId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/save")
|
||||||
|
@Operation(summary = "保存用户电子签名")
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:user-signature:update')")
|
||||||
|
public CommonResult<Boolean> save(@Valid @RequestBody UserSignatureSaveReqVO reqVO) {
|
||||||
|
userSignatureService.save(reqVO.getUserId(), reqVO.getFileId(), reqVO.getFileName(), reqVO.getStatus(), reqVO.getRemark());
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/delete")
|
||||||
|
@Operation(summary = "删除用户电子签名")
|
||||||
|
@Parameter(name = "userId", description = "用户 ID", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:user-signature:update')")
|
||||||
|
public CommonResult<Boolean> delete(@RequestParam("userId") Long userId) {
|
||||||
|
userSignatureService.deleteByUserId(userId);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/my")
|
||||||
|
@Operation(summary = "获取当前登录用户电子签名")
|
||||||
|
public CommonResult<UserSignatureRespVO> my() {
|
||||||
|
return success(toRespVO(userSignatureService.getByUserId(getLoginUserId())));
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserSignatureRespVO toRespVO(UserSignatureDO signature) {
|
||||||
|
return BeanUtils.toBean(signature, UserSignatureRespVO.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.njcn.rdms.module.system.controller.admin.user.vo.signature;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 用户电子签名 Response VO")
|
||||||
|
@Data
|
||||||
|
public class UserSignatureRespVO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
private Long fileId;
|
||||||
|
|
||||||
|
private String fileName;
|
||||||
|
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.njcn.rdms.module.system.controller.admin.user.vo.signature;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 用户电子签名保存 Request VO")
|
||||||
|
@Data
|
||||||
|
public class UserSignatureSaveReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
|
@NotNull(message = "用户 ID 不能为空")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@Schema(description = "电子签文件 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||||
|
@NotNull(message = "电子签文件 ID 不能为空")
|
||||||
|
private Long fileId;
|
||||||
|
|
||||||
|
@Schema(description = "文件名", example = "zhangsan-sign.png")
|
||||||
|
@Size(max = 255, message = "文件名长度不能超过 255 个字符")
|
||||||
|
private String fileName;
|
||||||
|
|
||||||
|
@Schema(description = "状态", example = "0")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "备注")
|
||||||
|
@Size(max = 255, message = "备注长度不能超过 255 个字符")
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.njcn.rdms.module.system.dal.dataobject.user;
|
||||||
|
|
||||||
|
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("system_user_signature")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class UserSignatureDO extends BaseDO {
|
||||||
|
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
private Long fileId;
|
||||||
|
|
||||||
|
private String fileName;
|
||||||
|
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.njcn.rdms.module.system.dal.mysql.user;
|
||||||
|
|
||||||
|
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import com.njcn.rdms.module.system.dal.dataobject.user.UserSignatureDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface UserSignatureMapper extends BaseMapperX<UserSignatureDO> {
|
||||||
|
|
||||||
|
default UserSignatureDO selectByUserId(Long userId) {
|
||||||
|
return selectOne(new LambdaQueryWrapperX<UserSignatureDO>()
|
||||||
|
.eq(UserSignatureDO::getUserId, userId));
|
||||||
|
}
|
||||||
|
|
||||||
|
default int deleteByUserId(Long userId) {
|
||||||
|
return delete(new LambdaQueryWrapperX<UserSignatureDO>()
|
||||||
|
.eq(UserSignatureDO::getUserId, userId));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.njcn.rdms.module.system.service.user;
|
||||||
|
|
||||||
|
import com.njcn.rdms.module.system.dal.dataobject.user.UserSignatureDO;
|
||||||
|
|
||||||
|
public interface UserSignatureService {
|
||||||
|
|
||||||
|
UserSignatureDO getByUserId(Long userId);
|
||||||
|
|
||||||
|
void save(Long userId, Long fileId, String fileName, Integer status, String remark);
|
||||||
|
|
||||||
|
void deleteByUserId(Long userId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package com.njcn.rdms.module.system.service.user;
|
||||||
|
|
||||||
|
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
|
||||||
|
import com.njcn.rdms.module.system.dal.dataobject.file.FileDO;
|
||||||
|
import com.njcn.rdms.module.system.dal.dataobject.user.UserSignatureDO;
|
||||||
|
import com.njcn.rdms.module.system.dal.mysql.user.UserSignatureMapper;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import static com.njcn.rdms.framework.common.util.collection.CollectionUtils.singleton;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class UserSignatureServiceImpl implements UserSignatureService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserSignatureMapper userSignatureMapper;
|
||||||
|
@Resource
|
||||||
|
private AdminUserService adminUserService;
|
||||||
|
@Resource
|
||||||
|
private com.njcn.rdms.module.system.service.file.FileService fileService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserSignatureDO getByUserId(Long userId) {
|
||||||
|
if (userId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return userSignatureMapper.selectByUserId(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void save(Long userId, Long fileId, String fileName, Integer status, String remark) {
|
||||||
|
adminUserService.validateUserList(singleton(userId));
|
||||||
|
FileDO file = fileService.getFile(fileId);
|
||||||
|
|
||||||
|
UserSignatureDO existing = userSignatureMapper.selectByUserId(userId);
|
||||||
|
UserSignatureDO target = new UserSignatureDO();
|
||||||
|
if (existing != null) {
|
||||||
|
target.setId(existing.getId());
|
||||||
|
}
|
||||||
|
target.setUserId(userId);
|
||||||
|
target.setFileId(fileId);
|
||||||
|
target.setFileName(StringUtils.hasText(fileName) ? fileName.trim() : file.getName());
|
||||||
|
target.setStatus(status == null ? CommonStatusEnum.ENABLE.getStatus() : status);
|
||||||
|
target.setRemark(StringUtils.hasText(remark) ? remark.trim() : null);
|
||||||
|
if (existing == null) {
|
||||||
|
userSignatureMapper.insert(target);
|
||||||
|
} else {
|
||||||
|
userSignatureMapper.updateById(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void deleteByUserId(Long userId) {
|
||||||
|
if (userId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
userSignatureMapper.deleteByUserId(userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user