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_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_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 ==========
|
||||
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_ACTION_REASON_REQUIRED = new ErrorCode(1_008_011_018, "「{}」操作必须填写原因");
|
||||
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_EXPORT = "project:performance-sheet:export";
|
||||
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_PROJECT_OWNER = "project:work-report:project-owner";
|
||||
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.PerformanceSheetCreateReqVO;
|
||||
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.PerformanceSheetPrefillRespVO;
|
||||
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.PerformanceSheetSignOffReqVO;
|
||||
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.PerformanceSheetStatusLogRespVO;
|
||||
@@ -124,6 +127,21 @@ public class PerformanceSheetController {
|
||||
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")
|
||||
@Operation(summary = "下载单条绩效表")
|
||||
@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")
|
||||
private String statusCode;
|
||||
|
||||
@Schema(description = "下签状态编码", example = "pending_employee_confirm")
|
||||
private String signOffStatus;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ public class PerformanceSheetRespVO {
|
||||
private Integer fileVersion;
|
||||
private String statusCode;
|
||||
private String statusName;
|
||||
private String signOffStatus;
|
||||
private String signOffStatusName;
|
||||
private BigDecimal actualScoreTotal;
|
||||
private BigDecimal baseScoreTotal;
|
||||
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.MonthlyReportRespVO;
|
||||
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.monthly.MonthlyReportService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@@ -111,6 +113,20 @@ public class MonthlyReportController {
|
||||
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")
|
||||
@Operation(summary = "提交月报")
|
||||
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_UPDATE + "')")
|
||||
@@ -137,6 +153,15 @@ public class MonthlyReportController {
|
||||
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}")
|
||||
@Operation(summary = "删除月报")
|
||||
@PreAuthorize("@ss.hasPermission('" + WorkReportConstants.PERMISSION_DELETE + "')")
|
||||
|
||||
@@ -36,10 +36,14 @@ public class MonthlyReportApprovalRecordRespVO {
|
||||
|
||||
private String employeeSignName;
|
||||
|
||||
private Long employeeSignatureFileId;
|
||||
|
||||
private LocalDate employeeSignedDate;
|
||||
|
||||
private String supervisorSignName;
|
||||
|
||||
private Long supervisorSignatureFileId;
|
||||
|
||||
private LocalDate supervisorSignedDate;
|
||||
|
||||
private Long auditorUserId;
|
||||
|
||||
@@ -14,4 +14,7 @@ public class MonthlyReportPageReqVO extends WorkReportBasePageReqVO {
|
||||
|
||||
@Schema(description = "团队视角下的填报人用户编号列表")
|
||||
private List<Long> reporterIds;
|
||||
|
||||
@Schema(description = "下签状态编码", example = "pending_employee_confirm")
|
||||
private String signOffStatus;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ public class MonthlyReportRespVO {
|
||||
private LocalDate periodEndDate;
|
||||
private String statusCode;
|
||||
private String statusName;
|
||||
private String signOffStatus;
|
||||
private String signOffStatusName;
|
||||
private Boolean allowEdit;
|
||||
private Boolean terminal;
|
||||
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 signOffStatus;
|
||||
|
||||
private BigDecimal actualScoreTotal;
|
||||
|
||||
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)
|
||||
private String employeeSignName;
|
||||
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private Long employeeSignatureFileId;
|
||||
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private LocalDate employeeSignedDate;
|
||||
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private String supervisorSignName;
|
||||
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private Long supervisorSignatureFileId;
|
||||
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private LocalDate supervisorSignedDate;
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@ public class MonthlyReportDO extends BaseDO {
|
||||
|
||||
private String statusCode;
|
||||
|
||||
private String signOffStatus;
|
||||
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
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;
|
||||
|
||||
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.mapper.BaseMapperX;
|
||||
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.dal.dataobject.performance.PerformanceSheetDO;
|
||||
@@ -102,6 +102,14 @@ public interface PerformanceSheetMapper extends BaseMapperX<PerformanceSheetDO>
|
||||
.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) {
|
||||
return new LambdaQueryWrapperX<PerformanceSheetDO>()
|
||||
.geIfPresent(PerformanceSheetDO::getPeriodMonth, reqVO.getPeriodMonthStart())
|
||||
@@ -111,6 +119,7 @@ public interface PerformanceSheetMapper extends BaseMapperX<PerformanceSheetDO>
|
||||
.likeIfPresent(PerformanceSheetDO::getEmployeeDeptName, reqVO.getEmployeeDeptName())
|
||||
.eqIfPresent(PerformanceSheetDO::getManagerId, reqVO.getManagerId())
|
||||
.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>()
|
||||
.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));
|
||||
}
|
||||
|
||||
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,
|
||||
Long reporterId) {
|
||||
return update(update, new LambdaQueryWrapperX<MonthlyReportDO>()
|
||||
@@ -177,6 +185,7 @@ public interface MonthlyReportMapper extends BaseMapperX<MonthlyReportDO> {
|
||||
private LambdaQueryWrapperX<MonthlyReportDO> buildPageQuery(MonthlyReportPageReqVO reqVO) {
|
||||
LambdaQueryWrapperX<MonthlyReportDO> wrapper = new LambdaQueryWrapperX<MonthlyReportDO>()
|
||||
.eqIfPresent(MonthlyReportDO::getStatusCode, reqVO.getStatusCode())
|
||||
.eqIfPresent(MonthlyReportDO::getSignOffStatus, reqVO.getSignOffStatus())
|
||||
.betweenIfPresent(MonthlyReportDO::getPeriodStartDate, reqVO.getPeriodStartDate())
|
||||
.betweenIfPresent(MonthlyReportDO::getSubmitTime, reqVO.getSubmitTime());
|
||||
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.user.AdminUserApi;
|
||||
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.context.annotation.Configuration;
|
||||
|
||||
@@ -22,6 +23,6 @@ import org.springframework.context.annotation.Configuration;
|
||||
{AdminUserApi.class, ObjectPermissionApi.class, DictDataApi.class, FileApi.class,
|
||||
PermissionApi.class, OrgLeaderApi.class, UserVisibilityConfigApi.class,
|
||||
DeptApi.class, PostApi.class, UserManagementRelationApi.class,
|
||||
NotifyMessageSendApi.class})
|
||||
NotifyMessageSendApi.class, UserSignatureApi.class})
|
||||
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.PerformanceSheetCreateReqVO;
|
||||
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.PerformanceSheetPrefillRespVO;
|
||||
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.PerformanceSheetSignOffReqVO;
|
||||
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.PerformanceSheetStatusLogRespVO;
|
||||
@@ -36,6 +39,10 @@ public interface PerformanceSheetService {
|
||||
|
||||
void reject(Long id, PerformanceSheetStatusActionReqVO reqVO);
|
||||
|
||||
PerformanceSheetImportZipRespVO importZip(PerformanceSheetImportZipReqVO reqVO) throws Exception;
|
||||
|
||||
Long signOff(PerformanceSheetSignOffReqVO reqVO);
|
||||
|
||||
PerformanceDownloadFile download(Long id);
|
||||
|
||||
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.module.project.constant.PerformanceExcelCellConstants;
|
||||
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.PerformanceSheetCreateReqVO;
|
||||
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.PerformanceSheetPrefillRespVO;
|
||||
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.PerformanceSheetSignOffReqVO;
|
||||
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.PerformanceSheetStatusLogRespVO;
|
||||
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.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.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.ObjectStatusTransitionDO;
|
||||
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.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.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.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.framework.notify.NotifySendEvent;
|
||||
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.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.dto.DeptRespDTO;
|
||||
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.UserManagementRelationApi;
|
||||
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.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.YearMonth;
|
||||
@@ -95,6 +115,8 @@ import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
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.invalidParamException;
|
||||
@@ -116,12 +138,22 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
||||
@Resource
|
||||
private PerformanceSheetResponseRecordMapper performanceSheetResponseRecordMapper;
|
||||
@Resource
|
||||
private PerformanceSheetSignOffMapper performanceSheetSignOffMapper;
|
||||
@Resource
|
||||
private PerformanceSheetSignOffRecordMapper performanceSheetSignOffRecordMapper;
|
||||
@Resource
|
||||
private EmployeeSignOffBatchMapper employeeSignOffBatchMapper;
|
||||
@Resource
|
||||
private MonthlyReportApprovalRecordMapper monthlyReportApprovalRecordMapper;
|
||||
@Resource
|
||||
private ObjectStatusModelMapper objectStatusModelMapper;
|
||||
@Resource
|
||||
private ObjectStatusTransitionMapper objectStatusTransitionMapper;
|
||||
@Resource
|
||||
private StatusActionTextResolver statusActionTextResolver;
|
||||
@Resource
|
||||
private EmployeeSignOffStatusService employeeSignOffStatusService;
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
@Resource
|
||||
private DeptApi deptApi;
|
||||
@@ -130,9 +162,13 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
||||
@Resource
|
||||
private FileApi fileApi;
|
||||
@Resource
|
||||
private WorkReportCommonService workReportCommonService;
|
||||
@Resource
|
||||
private TeamDashboardAccessService teamDashboardAccessService;
|
||||
@Resource
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
@Resource
|
||||
private TransactionTemplate transactionTemplate;
|
||||
|
||||
@Override
|
||||
public PageResult<PerformanceSheetRespVO> getSheetPage(PerformanceSheetPageReqVO reqVO) {
|
||||
@@ -183,6 +219,7 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
||||
sheet.setFileName(buildPerformanceFileName(periodMonth, employee.getNickname()));
|
||||
sheet.setFileVersion(0);
|
||||
sheet.setStatusCode(getInitialStatusCode());
|
||||
sheet.setSignOffStatus(SignOffConstants.STATUS_NOT_STARTED);
|
||||
performanceSheetMapper.insert(sheet);
|
||||
return sheet.getId();
|
||||
}
|
||||
@@ -248,6 +285,158 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
||||
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
|
||||
public PerformanceDownloadFile download(Long id) {
|
||||
PerformanceSheetDO sheet = validateReadableSheet(id);
|
||||
@@ -393,23 +582,38 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
||||
private PerformanceSheetDO processEmployeeResponse(Long id, String actionType, String reason) {
|
||||
PerformanceSheetDO current = validateSheetExists(id);
|
||||
validateEmployeeOnly(current.getEmployeeId());
|
||||
PerformanceEmployeeResponseContext responseContext = resolvePerformanceEmployeeResponseContext(current);
|
||||
ObjectStatusTransitionDO transition = validateTransition(current.getStatusCode(), actionType, reason);
|
||||
PerformanceSheetDO update = new PerformanceSheetDO();
|
||||
update.setStatusCode(transition.getToStatusCode());
|
||||
if (PerformanceConstants.STATUS_CONFIRMED.equals(transition.getToStatusCode())) {
|
||||
update.setConfirmedTime(LocalDateTime.now());
|
||||
if (responseContext.signOffFlow()) {
|
||||
update.setSignOffStatus(SignOffConstants.STATUS_EMPLOYEE_CONFIRMED);
|
||||
}
|
||||
} else if (PerformanceConstants.STATUS_REJECTED.equals(transition.getToStatusCode())) {
|
||||
update.setRejectedTime(LocalDateTime.now());
|
||||
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) {
|
||||
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_STATUS_CONCURRENT_MODIFIED);
|
||||
}
|
||||
if (responseContext.signOffFlow()) {
|
||||
updatePerformanceSignOffAfterEmployeeAction(current, responseContext.signOff(), actionType, reason);
|
||||
}
|
||||
PerformanceSheetDO after = merge(current, update);
|
||||
PerformanceSheetStatusLogDO statusLog = writeStatusLog(after, 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;
|
||||
}
|
||||
|
||||
@@ -527,6 +731,11 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
||||
private PerformanceSheetRespVO toRespVO(PerformanceSheetDO sheet) {
|
||||
PerformanceSheetRespVO respVO = BeanUtils.toBean(sheet, PerformanceSheetRespVO.class);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1095,16 +1304,21 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
||||
Sheet sourceSheet = workbook.getSheetAt(0);
|
||||
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
|
||||
DataFormatter formatter = new DataFormatter();
|
||||
return readSelectedCellValues(sourceSheet, evaluator, formatter, cellAddresses);
|
||||
}
|
||||
}
|
||||
|
||||
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(sourceSheet, evaluator, formatter, cellAddress);
|
||||
String value = readCellDisplayValue(sheet, evaluator, formatter, cellAddress);
|
||||
if (value != null) {
|
||||
cellValues.put(cellAddress, value);
|
||||
}
|
||||
}
|
||||
return cellValues;
|
||||
}
|
||||
}
|
||||
|
||||
private String readCellDisplayValue(Sheet sheet,
|
||||
FormulaEvaluator evaluator,
|
||||
@@ -1123,6 +1337,348 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
||||
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) {
|
||||
PerformanceSheetDO merged = BeanUtils.toBean(source, PerformanceSheetDO.class);
|
||||
if (update.getStatusCode() != null) {
|
||||
@@ -1140,6 +1696,9 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
||||
if (update.getLastStatusReason() != null) {
|
||||
merged.setLastStatusReason(update.getLastStatusReason());
|
||||
}
|
||||
if (update.getSignOffStatus() != null) {
|
||||
merged.setSignOffStatus(update.getSignOffStatus());
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
@@ -1258,4 +1817,13 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
||||
private final Map<Font, Font> fontCache = new IdentityHashMap<>();
|
||||
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.security.core.util.SecurityFrameworkUtils;
|
||||
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.framework.notify.NotifySendEvent;
|
||||
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.monthly.MonthlyReportApprovalRecordDO;
|
||||
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.ProjectReportCurrentItemDO;
|
||||
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.monthly.MonthlyReportApprovalRecordMapper;
|
||||
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.ProjectReportCurrentItemMapper;
|
||||
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.WeeklyReportTravelSegmentMapper;
|
||||
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.team.TeamDashboardAccessService;
|
||||
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.user.UserSignatureApi;
|
||||
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.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.UserManagementRelationApi;
|
||||
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 jakarta.annotation.Resource;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
@@ -109,6 +117,10 @@ public class WorkReportCommonService {
|
||||
@Resource
|
||||
private MonthlyReportApprovalRecordMapper monthlyReportApprovalRecordMapper;
|
||||
@Resource
|
||||
private MonthlyReportSignOffMapper monthlyReportSignOffMapper;
|
||||
@Resource
|
||||
private MonthlyReportSignOffRecordMapper monthlyReportSignOffRecordMapper;
|
||||
@Resource
|
||||
private ProjectReportApprovalRecordMapper projectReportApprovalRecordMapper;
|
||||
@Resource
|
||||
private WorkReportStatusLogMapper workReportStatusLogMapper;
|
||||
@@ -121,6 +133,8 @@ public class WorkReportCommonService {
|
||||
@Resource
|
||||
private StatusActionTextResolver statusActionTextResolver;
|
||||
@Resource
|
||||
private EmployeeSignOffStatusService employeeSignOffStatusService;
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
@Resource
|
||||
private DeptApi deptApi;
|
||||
@@ -129,6 +143,8 @@ public class WorkReportCommonService {
|
||||
@Resource
|
||||
private UserManagementRelationApi userManagementRelationApi;
|
||||
@Resource
|
||||
private UserSignatureApi userSignatureApi;
|
||||
@Resource
|
||||
private ObjectPermissionApi objectPermissionApi;
|
||||
@Resource
|
||||
private ProjectMapper projectMapper;
|
||||
@@ -368,6 +384,7 @@ public class WorkReportCommonService {
|
||||
MonthlyReportDO report = new MonthlyReportDO();
|
||||
applyMonthlySaveFields(report, reqVO, profile);
|
||||
report.setStatusCode(getInitialStatusCode());
|
||||
report.setSignOffStatus(SignOffConstants.STATUS_NOT_STARTED);
|
||||
monthlyReportMapper.insert(report);
|
||||
replaceMonthlyChildren(report.getId(), reqVO);
|
||||
MonthlyReportDO latest = monthlyReportMapper.selectById(report.getId());
|
||||
@@ -439,6 +456,29 @@ public class WorkReportCommonService {
|
||||
.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)
|
||||
public void submitMonthlyReport(Long id) {
|
||||
MonthlyReportDO current = validateMonthlyReportExists(id);
|
||||
@@ -478,6 +518,55 @@ public class WorkReportCommonService {
|
||||
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)
|
||||
public void deleteMonthlyReport(Long id) {
|
||||
MonthlyReportDO current = validateMonthlyReportExists(id);
|
||||
@@ -513,6 +602,89 @@ public class WorkReportCommonService {
|
||||
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) {
|
||||
CurrentUserProfile profile = loadCurrentUserProfile(true);
|
||||
ProjectDO project = validateProjectExists(projectId);
|
||||
@@ -810,6 +982,14 @@ public class WorkReportCommonService {
|
||||
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) {
|
||||
ProjectReportDO report = validateProjectReportExists(id);
|
||||
validateReadable(report.getProjectOwnerId(), report.getSupervisorUserId());
|
||||
@@ -1438,6 +1618,7 @@ public class WorkReportCommonService {
|
||||
record.setConclusion(statusLog.getToStatus());
|
||||
record.setOpinion(normalizeReason(reqVO));
|
||||
if (WorkReportConstants.ACTION_APPROVE.equals(actionCode)) {
|
||||
UserSignatureRespDTO userSignature = getUserSignature(SecurityFrameworkUtils.getLoginUserId());
|
||||
record.setMeetingDate(reqVO.getMeetingDate());
|
||||
record.setStrengthDesc(normalizeNullableText(reqVO.getStrengthDesc()));
|
||||
record.setStrengthExample(normalizeNullableText(reqVO.getStrengthExample()));
|
||||
@@ -1446,15 +1627,32 @@ public class WorkReportCommonService {
|
||||
record.setImprovementSuggestion(normalizeNullableText(reqVO.getImprovementSuggestion()));
|
||||
record.setPerformanceResult(normalizeNullableText(reqVO.getPerformanceResult()));
|
||||
record.setEmployeeSignName(normalizeNullableText(reqVO.getEmployeeSignName()));
|
||||
record.setEmployeeSignatureFileId(null);
|
||||
record.setEmployeeSignedDate(reqVO.getEmployeeSignedDate());
|
||||
record.setSupervisorSignName(normalizeNullableText(reqVO.getSupervisorSignName()));
|
||||
record.setSupervisorSignedDate(reqVO.getSupervisorSignedDate());
|
||||
record.setSupervisorSignName(defaultText(SecurityFrameworkUtils.getLoginUserNickname()));
|
||||
record.setSupervisorSignatureFileId(userSignature == null ? null : userSignature.getFileId());
|
||||
record.setSupervisorSignedDate(LocalDate.now());
|
||||
}
|
||||
record.setAuditorUserId(SecurityFrameworkUtils.getLoginUserId());
|
||||
record.setAuditorName(defaultText(SecurityFrameworkUtils.getLoginUserNickname()));
|
||||
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) {
|
||||
ProjectReportApprovalRecordDO record = new ProjectReportApprovalRecordDO();
|
||||
record.setProjectReportId(report.getId());
|
||||
@@ -1513,6 +1711,11 @@ public class WorkReportCommonService {
|
||||
private MonthlyReportRespVO toMonthlyRespVO(MonthlyReportDO report, boolean withChildren) {
|
||||
MonthlyReportRespVO respVO = BeanUtils.toBean(report, MonthlyReportRespVO.class);
|
||||
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) {
|
||||
respVO.setReviewItems(BeanUtils.toBean(
|
||||
personalReportReviewItemMapper.selectListByReport(WorkReportConstants.REPORT_TYPE_MONTHLY, report.getId()),
|
||||
@@ -1704,6 +1907,19 @@ public class WorkReportCommonService {
|
||||
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) {
|
||||
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.MonthlyReportRespVO;
|
||||
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.WorkReportStatusLogRespVO;
|
||||
|
||||
@@ -32,12 +34,18 @@ public interface MonthlyReportService {
|
||||
|
||||
PageResult<MonthlyReportRespVO> getMonthlyApprovalPage(MonthlyReportPageReqVO reqVO);
|
||||
|
||||
PageResult<MonthlyReportRespVO> getMonthlySignOffPage(MonthlyReportPageReqVO reqVO);
|
||||
|
||||
MonthlyReportSignOffDetailRespVO getMonthlySignOffDetail(Long id);
|
||||
|
||||
void submitMonthlyReport(Long id);
|
||||
|
||||
void approveMonthlyReport(Long id, MonthlyReportApproveReqVO reqVO);
|
||||
|
||||
void rejectMonthlyReport(Long id, WorkReportStatusActionReqVO reqVO);
|
||||
|
||||
void confirmMonthlySignOff(Long id, MonthlyReportSignOffConfirmReqVO reqVO);
|
||||
|
||||
void deleteMonthlyReport(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.MonthlyReportRespVO;
|
||||
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.WorkReportStatusLogRespVO;
|
||||
import com.njcn.rdms.module.project.service.workreport.common.WorkReportCommonService;
|
||||
@@ -71,6 +73,16 @@ public class MonthlyReportServiceImpl implements MonthlyReportService {
|
||||
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
|
||||
public void submitMonthlyReport(Long id) {
|
||||
workReportCommonService.submitMonthlyReport(id);
|
||||
@@ -86,6 +98,11 @@ public class MonthlyReportServiceImpl implements MonthlyReportService {
|
||||
workReportCommonService.rejectMonthlyReport(id, reqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void confirmMonthlySignOff(Long id, MonthlyReportSignOffConfirmReqVO reqVO) {
|
||||
workReportCommonService.confirmMonthlySignOff(id, reqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteMonthlyReport(Long id) {
|
||||
workReportCommonService.deleteMonthlyReport(id);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.njcn.rdms.module.system.api.file;
|
||||
|
||||
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.enums.ApiConstants;
|
||||
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 org.springframework.cloud.openfeign.FeignClient;
|
||||
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;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME)
|
||||
@@ -31,4 +34,8 @@ public interface FileApi {
|
||||
@Parameter(name = "id", description = "文件 ID", required = true)
|
||||
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.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.dal.dataobject.file.FileDO;
|
||||
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