From 18d64880108671e86368241f69cc26b1273ac6f8 Mon Sep 17 00:00:00 2001 From: zch Date: Thu, 18 Jun 2026 11:01:29 +0800 Subject: [PATCH] =?UTF-8?q?feat(oa-erp):=20=E6=96=B0=E5=A2=9E=E8=BD=AF?= =?UTF-8?q?=E4=BB=B6=E9=83=A8=E4=B8=B4=E6=97=B6=E4=BB=BB=E5=8A=A1=E5=8F=8A?= =?UTF-8?q?=E5=8F=98=E6=9B=B4=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 实现临时任务全生命周期管理,包含任务创建、审批、关闭、变更记录与审批功能,配套完整的CRUD接口与前端路由。 --- .../ErpTempTaskChangeController.java | 116 ++++ .../erp/controller/ErpTempTaskController.java | 172 +++++ .../dromara/oa/erp/domain/ErpTempTask.java | 240 +++++++ .../oa/erp/domain/ErpTempTaskChange.java | 124 ++++ .../oa/erp/domain/bo/ErpTempTaskBo.java | 268 ++++++++ .../oa/erp/domain/bo/ErpTempTaskChangeBo.java | 121 ++++ .../oa/erp/domain/vo/ErpTempTaskChangeVo.java | 148 ++++ .../oa/erp/domain/vo/ErpTempTaskVo.java | 306 +++++++++ .../erp/mapper/ErpTempTaskChangeMapper.java | 153 +++++ .../oa/erp/mapper/ErpTempTaskMapper.java | 135 ++++ .../service/IErpTempTaskChangeService.java | 69 ++ .../oa/erp/service/IErpTempTaskService.java | 111 +++ .../impl/ErpTempTaskChangeServiceImpl.java | 149 +++++ .../service/impl/ErpTempTaskServiceImpl.java | 632 ++++++++++++++++++ .../mapper/oa/erp/ErpTempTaskChangeMapper.xml | 296 ++++++++ .../mapper/oa/erp/ErpTempTaskMapper.xml | 438 ++++++++++++ 16 files changed, 3478 insertions(+) create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpTempTaskChangeController.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpTempTaskController.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpTempTask.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpTempTaskChange.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpTempTaskBo.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpTempTaskChangeBo.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpTempTaskChangeVo.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpTempTaskVo.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpTempTaskChangeMapper.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpTempTaskMapper.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpTempTaskChangeService.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpTempTaskService.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpTempTaskChangeServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpTempTaskServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpTempTaskChangeMapper.xml create mode 100644 ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpTempTaskMapper.xml diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpTempTaskChangeController.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpTempTaskChangeController.java new file mode 100644 index 00000000..67457c86 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpTempTaskChangeController.java @@ -0,0 +1,116 @@ +package org.dromara.oa.erp.controller; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.oa.erp.domain.vo.ErpTempTaskChangeVo; +import org.dromara.oa.erp.domain.bo.ErpTempTaskChangeBo; +import org.dromara.oa.erp.service.IErpTempTaskChangeService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 临时任务变更记录 + * 前端访问路由地址为:/oa/erp/erpTempTaskChange + * + * @author zch + * @date 2026-06-17 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/erp/erpTempTaskChange") +public class ErpTempTaskChangeController extends BaseController { + + private final IErpTempTaskChangeService erpTempTaskChangeService; + + /** + * 查询临时任务变更记录列表 + */ + @SaCheckPermission("oa:erp:erpTempTaskChange:list") + @GetMapping("/list") + public TableDataInfo list(ErpTempTaskChangeBo bo, PageQuery pageQuery) { + return erpTempTaskChangeService.queryPageList(bo, pageQuery); + } + + /** + * 导出临时任务变更记录列表 + */ + @SaCheckPermission("oa:erp:erpTempTaskChange:export") + @Log(title = "临时任务变更记录", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(ErpTempTaskChangeBo bo, HttpServletResponse response) { + List list = erpTempTaskChangeService.queryList(bo); + ExcelUtil.exportExcel(list, "临时任务变更记录", ErpTempTaskChangeVo.class, response); + } + + /** + * 获取临时任务变更记录详细信息 + * + * @param changeId 主键 + */ + @SaCheckPermission("oa:erp:erpTempTaskChange:query") + @GetMapping("/{changeId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable("changeId") Long changeId) { + return R.ok(erpTempTaskChangeService.queryById(changeId)); + } + + /** + * 新增临时任务变更记录 + */ + @SaCheckPermission("oa:erp:erpTempTaskChange:add") + @Log(title = "临时任务变更记录", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ErpTempTaskChangeBo bo) { + return toAjax(erpTempTaskChangeService.insertByBo(bo)); + } + + /** + * 修改临时任务变更记录 + */ + @SaCheckPermission("oa:erp:erpTempTaskChange:edit") + @Log(title = "临时任务变更记录", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ErpTempTaskChangeBo bo) { + return toAjax(erpTempTaskChangeService.updateByBo(bo)); + } + + /** + * 删除临时任务变更记录 + * + * @param changeIds 主键串 + */ + @SaCheckPermission("oa:erp:erpTempTaskChange:remove") + @Log(title = "临时任务变更记录", businessType = BusinessType.DELETE) + @DeleteMapping("/{changeIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable("changeIds") Long[] changeIds) { + return toAjax(erpTempTaskChangeService.deleteWithValidByIds(List.of(changeIds), true)); + } + + /** + * 下拉框查询临时任务变更记录列表 + */ + @GetMapping("/getErpTempTaskChangeList") + public R> getErpTempTaskChangeList(ErpTempTaskChangeBo bo) { + List list = erpTempTaskChangeService.queryList(bo); + return R.ok(list); + } + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpTempTaskController.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpTempTaskController.java new file mode 100644 index 00000000..055bab8e --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpTempTaskController.java @@ -0,0 +1,172 @@ +package org.dromara.oa.erp.controller; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.oa.erp.domain.bo.ErpTempTaskChangeBo; +import org.dromara.oa.erp.domain.vo.ErpTempTaskChangeVo; +import org.dromara.oa.erp.domain.vo.ErpTempTaskVo; +import org.dromara.oa.erp.domain.bo.ErpTempTaskBo; +import org.dromara.oa.erp.service.IErpTempTaskService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 软件部临时任务主 + * 前端访问路由地址为:/oa/erp/tempTask + * + * @author zch + * @date 2026-06-17 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/erp/tempTask") +public class ErpTempTaskController extends BaseController { + + private final IErpTempTaskService erpTempTaskService; + + /** + * 查询软件部临时任务主列表 + */ + @SaCheckPermission("oa:erp:tempTask:list") + @GetMapping("/list") + public TableDataInfo list(ErpTempTaskBo bo, PageQuery pageQuery) { + return erpTempTaskService.queryPageList(bo, pageQuery); + } + + /** + * 导出软件部临时任务主列表 + */ + @SaCheckPermission("oa:erp:tempTask:export") + @Log(title = "软件部临时任务主", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(ErpTempTaskBo bo, HttpServletResponse response) { + List list = erpTempTaskService.queryList(bo); + ExcelUtil.exportExcel(list, "软件部临时任务主", ErpTempTaskVo.class, response); + } + + /** + * 获取软件部临时任务主详细信息 + * + * @param tempTaskId 主键 + */ + @SaCheckPermission("oa:erp:tempTask:query") + @GetMapping("/{tempTaskId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable("tempTaskId") Long tempTaskId) { + return R.ok(erpTempTaskService.queryById(tempTaskId)); + } + + /** + * 新增软件部临时任务主 + */ + @SaCheckPermission("oa:erp:tempTask:add") + @Log(title = "软件部临时任务主", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ErpTempTaskBo bo) { + return toAjax(erpTempTaskService.insertByBo(bo)); + } + + /** + * 修改软件部临时任务主 + */ + @SaCheckPermission("oa:erp:tempTask:edit") + @Log(title = "软件部临时任务主", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ErpTempTaskBo bo) { + return toAjax(erpTempTaskService.updateByBo(bo)); + } + + /** + * 删除软件部临时任务主 + * + * @param tempTaskIds 主键串 + */ + @SaCheckPermission("oa:erp:tempTask:remove") + @Log(title = "软件部临时任务主", businessType = BusinessType.DELETE) + @DeleteMapping("/{tempTaskIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable("tempTaskIds") Long[] tempTaskIds) { + return toAjax(erpTempTaskService.deleteWithValidByIds(List.of(tempTaskIds), true)); + } + + /** + * 下拉框查询软件部临时任务主列表 + */ + @GetMapping("/getErpTempTaskList") + public R> getErpTempTaskList(ErpTempTaskBo bo) { + List list = erpTempTaskService.queryList(bo); + return R.ok(list); + } + + /** + * 提交临时任务并发起审批流程 + */ + @SaCheckPermission("oa:erp:tempTask:submit") + @Log(title = "软件部临时任务提交审批", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PostMapping("/submit") + public R submit(@RequestBody ErpTempTaskBo bo) { + return R.ok(erpTempTaskService.tempTaskSubmitAndFlowStart(bo)); + } + + /** + * 主执行人关闭临时任务,写入实际工时和完成结果 + */ + @SaCheckPermission("oa:erp:tempTask:close") + @Log(title = "软件部临时任务关闭", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PostMapping("/close") + public R close(@RequestBody ErpTempTaskBo bo) { + return toAjax(erpTempTaskService.closeTask(bo)); + } + + /** + * 查询临时任务变更历史 + */ + @SaCheckPermission("oa:erp:tempTask:query") + @GetMapping("/{tempTaskId}/changes") + public R> changes(@NotNull(message = "主键不能为空") + @PathVariable("tempTaskId") Long tempTaskId) { + return R.ok(erpTempTaskService.queryChangeList(tempTaskId)); + } + + /** + * 发起临时任务变更 + */ + @SaCheckPermission("oa:erp:tempTask:change") + @Log(title = "软件部临时任务变更", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/change") + public R change(@RequestBody ErpTempTaskChangeBo bo) { + return toAjax(erpTempTaskService.saveChange(bo)); + } + + /** + * 审批临时任务变更 + */ + @SaCheckPermission("oa:erp:tempTask:changeApprove") + @Log(title = "软件部临时任务变更审批", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PostMapping("/change/approve") + public R approveChange(@RequestBody ErpTempTaskChangeBo bo) { + return toAjax(erpTempTaskService.approveChange(bo)); + } + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpTempTask.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpTempTask.java new file mode 100644 index 00000000..fd275cbe --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpTempTask.java @@ -0,0 +1,240 @@ +package org.dromara.oa.erp.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.math.BigDecimal; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.io.Serial; + +/** + * 软件部临时任务主对象 erp_temp_task + * + * @author zch + * @date 2026-06-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("erp_temp_task") +public class ErpTempTask extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 临时任务ID + */ + @TableId(value = "temp_task_id", type = IdType.ASSIGN_ID) + private Long tempTaskId; + + /** + * 任务编号(LSRW+yyyyMMdd+4位,草稿即生成且全程不变) + */ + private String tempTaskCode; + + /** + * 任务标题 + */ + private String taskTitle; + + /** + * 任务描述(发起必填) + */ + private String taskDesc; + + /** + * 优先级:1普通 2较急 3紧急 4特急 + */ + private String priority; + + /** + * 紧急原因(优先级为紧急/特急时必填) + */ + private String urgentReason; + + /** + * 需求时间=发起方期望最晚完成时间(发起必填) + */ + private Date requireTime; + + /** + * 确认完成时间=领导审核确认的承诺完成时间 + */ + private Date confirmFinishTime; + + /** + * 实际开始时间(仅记周期,不计工时) + */ + private Date actualStartTime; + + /** + * 实际结束/关闭时间(仅记周期,不计工时) + */ + private Date actualFinishTime; + + /** + * 主报工项目ID + */ + private Long projectId; + + /** + * 项目编号快照 + */ + private String projectCode; + + /** + * 项目名称快照 + */ + private String projectName; + + /** + * 项目经理用户ID快照 + */ + private Long pmId; + + /** + * 项目经理姓名快照 + */ + private String pmName; + + /** + * 关联合同ID(选填) + */ + private Long contractId; + + /** + * 合同编号快照 + */ + private String contractCode; + + /** + * 发起人ID + */ + private Long requesterId; + + /** + * 发起人姓名快照 + */ + private String requesterName; + + /** + * 发起部门ID + */ + private Long requestDeptId; + + /** + * 发起部门名称快照 + */ + private String requestDeptName; + + /** + * 指派人/建议承接人ID(非必填) + */ + private Long dispatcherId; + + /** + * 指派人姓名快照 + */ + private String dispatcherName; + + /** + * 软件部领导/审批人ID(审核/加批/变更审批) + */ + private Long softwareLeaderId; + + /** + * 软件部领导姓名快照 + */ + private String softwareLeaderName; + + /** + * 主执行人ID(唯一,领导审核确定) + */ + private Long assigneeId; + + /** + * 主执行人姓名快照 + */ + private String assigneeName; + + /** + * 预计工时/小时(指派人确认阶段补齐,领导审核认可) + */ + private BigDecimal estimateWorkload; + + /** + * 实际消耗工时/小时(关闭时填写,0需说明,最小0.5) + */ + private BigDecimal actualWorkload; + + /** + * 完成结果:1已完成 2不执行/终止 3部分完成后终止(仅闭环写入) + */ + private String finishResult; + + /** + * 不执行/终止原因:1无需处理 2重复任务 3需求取消 4条件不满足 5资源不支持 6范围不合理 7其他 + */ + private String terminateReason; + + /** + * 完成说明(关闭必填;0工时/终止其他原因在此补充) + */ + private String finishRemark; + + /** + * 关联原任务ID + */ + private Long relatedTaskId; + + /** + * 关联原任务编号快照 + */ + private String relatedTaskCode; + + /** + * 关联原因:1关闭后异议 2遗漏补充 3返工处理 4换人承接 5需求延续 6重新发起 7其他 + */ + private String relateReason; + + /** + * 关联原因补充说明 + */ + private String relateRemark; + + /** + * 业务状态:1暂存 2进行中(审批/执行) 3已结束 4作废 + */ + private String taskStatus; + + /** + * 流程状态:draft/waiting/finish/back/cancel/invalid/termination + */ + private String flowStatus; + + /** + * 抄送人员用户ID(多个逗号分隔,实际抄送由工作流承载) + */ + private String ccUserIds; + + /** + * 附件ID(非必填,多个逗号分隔) + */ + private String ossId; + + /** + * 备注 + */ + private String remark; + + /** + * 删除标志(0存在 1删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpTempTaskChange.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpTempTaskChange.java new file mode 100644 index 00000000..09ee755e --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpTempTaskChange.java @@ -0,0 +1,124 @@ +package org.dromara.oa.erp.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.io.Serial; + +/** + * 临时任务变更记录对象 erp_temp_task_change + * + * @author zch + * @date 2026-06-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("erp_temp_task_change") +public class ErpTempTaskChange extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 变更记录ID + */ + @TableId(value = "change_id", type = IdType.AUTO) + private Long changeId; + + /** + * 临时任务ID + */ + private Long tempTaskId; + + /** + * 任务编号快照 + */ + private String tempTaskCode; + + /** + * 变更项类型:1任务描述 2工时 3需求时间 4指派人/执行人 5可报工项目 6执行范围 7终止/不执行 + */ + private String changeType; + + /** + * 变更原因 + */ + private String changeReason; + + /** + * 变更前内容 + */ + private String beforeContent; + + /** + * 变更后内容 + */ + private String afterContent; + + /** + * 工时影响(变更后预计工时/增减) + */ + private String workloadEffect; + + /** + * 时间影响(是否影响需求/确认完成时间) + */ + private String timeEffect; + + /** + * 执行影响说明(是否影响排期/其他任务/范围) + */ + private String scopeEffect; + + /** + * 变更发起人ID(发起人/执行人/软件部领导) + */ + private Long changeUserId; + + /** + * 变更发起人姓名快照 + */ + private String changeUserName; + + /** + * 审批结论:1通过 2不通过 3退回补充 4终止/不执行 + */ + private String approveResult; + + /** + * 审批人ID(软件部领导) + */ + private Long approverId; + + /** + * 审批人姓名快照 + */ + private String approverName; + + /** + * 审批意见 + */ + private String approveComment; + + /** + * 审批时间 + */ + private Date approveTime; + + /** + * 变更审批流程状态(如走独立审批) + */ + private String flowStatus; + + /** + * 删除标志 + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpTempTaskBo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpTempTaskBo.java new file mode 100644 index 00000000..fc6ea025 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpTempTaskBo.java @@ -0,0 +1,268 @@ +package org.dromara.oa.erp.domain.bo; + +import org.dromara.oa.erp.domain.ErpTempTask; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import cn.hutool.core.util.ObjectUtil; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; +import java.math.BigDecimal; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.dromara.workflow.api.domain.RemoteFlowInstanceBizExt; + +/** + * 软件部临时任务主业务对象 erp_temp_task + * + * @author zch + * @date 2026-06-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ErpTempTask.class, reverseConvertGenerate = false) +public class ErpTempTaskBo extends BaseEntity { + + /** + * 临时任务ID + */ + @NotNull(message = "临时任务ID不能为空", groups = { EditGroup.class }) + private Long tempTaskId; + + /** + * 任务编号(LSRW+yyyyMMdd+4位,草稿即生成且全程不变) + */ + private String tempTaskCode; + + /** + * 任务标题 + */ + private String taskTitle; + + /** + * 任务描述(发起必填) + */ + @NotBlank(message = "任务描述(发起必填)不能为空", groups = { AddGroup.class, EditGroup.class }) + private String taskDesc; + + /** + * 优先级:1普通 2较急 3紧急 4特急 + */ + private String priority; + + /** + * 紧急原因(优先级为紧急/特急时必填) + */ + private String urgentReason; + + /** + * 需求时间=发起方期望最晚完成时间(发起必填) + */ + @NotNull(message = "需求时间=发起方期望最晚完成时间(发起必填)不能为空", groups = { AddGroup.class, EditGroup.class }) + private Date requireTime; + + /** + * 确认完成时间=领导审核确认的承诺完成时间 + */ + private Date confirmFinishTime; + + /** + * 实际开始时间(仅记周期,不计工时) + */ + private Date actualStartTime; + + /** + * 实际结束/关闭时间(仅记周期,不计工时) + */ + private Date actualFinishTime; + + /** + * 主报工项目ID + */ + private Long projectId; + + /** + * 项目编号快照 + */ + private String projectCode; + + /** + * 项目名称快照 + */ + private String projectName; + + /** + * 项目经理用户ID快照 + */ + private Long pmId; + + /** + * 项目经理姓名快照 + */ + private String pmName; + + /** + * 关联合同ID(选填) + */ + private Long contractId; + + /** + * 合同编号快照 + */ + private String contractCode; + + /** + * 发起人ID + */ + private Long requesterId; + + /** + * 发起人姓名快照 + */ + private String requesterName; + + /** + * 发起部门ID + */ + private Long requestDeptId; + + /** + * 发起部门名称快照 + */ + private String requestDeptName; + + /** + * 指派人/建议承接人ID(非必填) + */ + private Long dispatcherId; + + /** + * 指派人姓名快照 + */ + private String dispatcherName; + + /** + * 软件部领导/审批人ID(审核/加批/变更审批) + */ + private Long softwareLeaderId; + + /** + * 软件部领导姓名快照 + */ + private String softwareLeaderName; + + /** + * 主执行人ID(唯一,领导审核确定) + */ + private Long assigneeId; + + /** + * 主执行人姓名快照 + */ + private String assigneeName; + + /** + * 预计工时/小时(指派人确认阶段补齐,领导审核认可) + */ + private BigDecimal estimateWorkload; + + /** + * 实际消耗工时/小时(关闭时填写,0需说明,最小0.5) + */ + private BigDecimal actualWorkload; + + /** + * 完成结果:1已完成 2不执行/终止 3部分完成后终止(仅闭环写入) + */ + private String finishResult; + + /** + * 不执行/终止原因:1无需处理 2重复任务 3需求取消 4条件不满足 5资源不支持 6范围不合理 7其他 + */ + private String terminateReason; + + /** + * 完成说明(关闭必填;0工时/终止其他原因在此补充) + */ + private String finishRemark; + + /** + * 关联原任务ID + */ + private Long relatedTaskId; + + /** + * 关联原任务编号快照 + */ + private String relatedTaskCode; + + /** + * 关联原因:1关闭后异议 2遗漏补充 3返工处理 4换人承接 5需求延续 6重新发起 7其他 + */ + private String relateReason; + + /** + * 关联原因补充说明 + */ + private String relateRemark; + + /** + * 业务状态:1暂存 2进行中(审批/执行) 3已结束 4作废 + */ + private String taskStatus; + + /** + * 流程状态:draft/waiting/finish/back/cancel/invalid/termination + */ + private String flowStatus; + + /** + * 抄送人员用户ID(多个逗号分隔,实际抄送由工作流承载) + */ + private String ccUserIds; + + /** + * 附件ID(非必填,多个逗号分隔) + */ + private String ossId; + + /** + * 备注 + */ + private String remark; + + /** + * 工作流编码,临时任务固定为 OATT + */ + private String flowCode; + + /** + * 工作流变量 + */ + private Map variables; + + /** + * 审批中心展示扩展 + */ + private RemoteFlowInstanceBizExt bizExt; + + public Map getVariables() { + if (variables == null) { + variables = new HashMap<>(16); + } + variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + return variables; + } + + public RemoteFlowInstanceBizExt getBizExt() { + if (ObjectUtil.isNull(bizExt)) { + bizExt = new RemoteFlowInstanceBizExt(); + } + return bizExt; + } + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpTempTaskChangeBo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpTempTaskChangeBo.java new file mode 100644 index 00000000..73cefe59 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpTempTaskChangeBo.java @@ -0,0 +1,121 @@ +package org.dromara.oa.erp.domain.bo; + +import org.dromara.oa.erp.domain.ErpTempTaskChange; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 临时任务变更记录业务对象 erp_temp_task_change + * + * @author zch + * @date 2026-06-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ErpTempTaskChange.class, reverseConvertGenerate = false) +public class ErpTempTaskChangeBo extends BaseEntity { + + /** + * 变更记录ID + */ + @NotNull(message = "变更记录ID不能为空", groups = { EditGroup.class }) + private Long changeId; + + /** + * 临时任务ID + */ + @NotNull(message = "临时任务ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long tempTaskId; + + /** + * 任务编号快照 + */ + private String tempTaskCode; + + /** + * 变更项类型:1任务描述 2工时 3需求时间 4指派人/执行人 5可报工项目 6执行范围 7终止/不执行 + */ + @NotBlank(message = "变更项类型:1任务描述 2工时 3需求时间 4指派人/执行人 5可报工项目 6执行范围 7终止/不执行不能为空", groups = { AddGroup.class, EditGroup.class }) + private String changeType; + + /** + * 变更原因 + */ + @NotBlank(message = "变更原因不能为空", groups = { AddGroup.class, EditGroup.class }) + private String changeReason; + + /** + * 变更前内容 + */ + private String beforeContent; + + /** + * 变更后内容 + */ + private String afterContent; + + /** + * 工时影响(变更后预计工时/增减) + */ + private String workloadEffect; + + /** + * 时间影响(是否影响需求/确认完成时间) + */ + private String timeEffect; + + /** + * 执行影响说明(是否影响排期/其他任务/范围) + */ + private String scopeEffect; + + /** + * 变更发起人ID(发起人/执行人/软件部领导) + */ + @NotNull(message = "变更发起人ID(发起人/执行人/软件部领导)不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long changeUserId; + + /** + * 变更发起人姓名快照 + */ + private String changeUserName; + + /** + * 审批结论:1通过 2不通过 3退回补充 4终止/不执行 + */ + private String approveResult; + + /** + * 审批人ID(软件部领导) + */ + private Long approverId; + + /** + * 审批人姓名快照 + */ + private String approverName; + + /** + * 审批意见 + */ + private String approveComment; + + /** + * 审批时间 + */ + private Date approveTime; + + /** + * 变更审批流程状态(如走独立审批) + */ + private String flowStatus; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpTempTaskChangeVo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpTempTaskChangeVo.java new file mode 100644 index 00000000..ccf88b16 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpTempTaskChangeVo.java @@ -0,0 +1,148 @@ +package org.dromara.oa.erp.domain.vo; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.dromara.oa.erp.domain.ErpTempTaskChange; +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 临时任务变更记录视图对象 erp_temp_task_change + * + * @author zch + * @date 2026-06-17 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ErpTempTaskChange.class) +public class ErpTempTaskChangeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 变更记录ID + */ + @ExcelProperty(value = "变更记录ID") + private Long changeId; + + /** + * 临时任务ID + */ + @ExcelProperty(value = "临时任务ID") + private Long tempTaskId; + + /** + * 任务编号快照 + */ + @ExcelProperty(value = "任务编号快照") + private String tempTaskCode; + + /** + * 变更项类型:1任务描述 2工时 3需求时间 4指派人/执行人 5可报工项目 6执行范围 7终止/不执行 + */ + @ExcelProperty(value = "变更项类型:1任务描述 2工时 3需求时间 4指派人/执行人 5可报工项目 6执行范围 7终止/不执行") + private String changeType; + + /** + * 变更原因 + */ + @ExcelProperty(value = "变更原因") + private String changeReason; + + /** + * 变更前内容 + */ + @ExcelProperty(value = "变更前内容") + private String beforeContent; + + /** + * 变更后内容 + */ + @ExcelProperty(value = "变更后内容") + private String afterContent; + + /** + * 工时影响(变更后预计工时/增减) + */ + @ExcelProperty(value = "工时影响", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "变=更后预计工时/增减") + private String workloadEffect; + + /** + * 时间影响(是否影响需求/确认完成时间) + */ + @ExcelProperty(value = "时间影响", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "是=否影响需求/确认完成时间") + private String timeEffect; + + /** + * 执行影响说明(是否影响排期/其他任务/范围) + */ + @ExcelProperty(value = "执行影响说明", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "是=否影响排期/其他任务/范围") + private String scopeEffect; + + /** + * 变更发起人ID(发起人/执行人/软件部领导) + */ + @ExcelProperty(value = "变更发起人ID", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "发=起人/执行人/软件部领导") + private Long changeUserId; + + /** + * 变更发起人姓名快照 + */ + @ExcelProperty(value = "变更发起人姓名快照") + private String changeUserName; + + /** + * 审批结论:1通过 2不通过 3退回补充 4终止/不执行 + */ + @ExcelProperty(value = "审批结论:1通过 2不通过 3退回补充 4终止/不执行") + private String approveResult; + + /** + * 审批人ID(软件部领导) + */ + @ExcelProperty(value = "审批人ID", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "软=件部领导") + private Long approverId; + + /** + * 审批人姓名快照 + */ + @ExcelProperty(value = "审批人姓名快照") + private String approverName; + + /** + * 审批意见 + */ + @ExcelProperty(value = "审批意见") + private String approveComment; + + /** + * 审批时间 + */ + @ExcelProperty(value = "审批时间") + private Date approveTime; + + /** + * 变更审批流程状态(如走独立审批) + */ + @ExcelProperty(value = "变更审批流程状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "如=走独立审批") + private String flowStatus; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpTempTaskVo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpTempTaskVo.java new file mode 100644 index 00000000..23a67e4a --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpTempTaskVo.java @@ -0,0 +1,306 @@ +package org.dromara.oa.erp.domain.vo; + +import java.math.BigDecimal; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.dromara.oa.erp.domain.ErpTempTask; +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 软件部临时任务主视图对象 erp_temp_task + * + * @author zch + * @date 2026-06-17 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ErpTempTask.class) +public class ErpTempTaskVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 临时任务ID + */ + @ExcelProperty(value = "临时任务ID") + private Long tempTaskId; + + /** + * 任务编号(LSRW+yyyyMMdd+4位,草稿即生成且全程不变) + */ + @ExcelProperty(value = "任务编号", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "L=SRW+yyyyMMdd+4位,草稿即生成且全程不变") + private String tempTaskCode; + + /** + * 任务标题 + */ + @ExcelProperty(value = "任务标题") + private String taskTitle; + + /** + * 任务描述(发起必填) + */ + @ExcelProperty(value = "任务描述", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "发=起必填") + private String taskDesc; + + /** + * 优先级:1普通 2较急 3紧急 4特急 + */ + @ExcelProperty(value = "优先级:1普通 2较急 3紧急 4特急") + private String priority; + + /** + * 紧急原因(优先级为紧急/特急时必填) + */ + @ExcelProperty(value = "紧急原因", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "优=先级为紧急/特急时必填") + private String urgentReason; + + /** + * 需求时间=发起方期望最晚完成时间(发起必填) + */ + @ExcelProperty(value = "需求时间=发起方期望最晚完成时间", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "发=起必填") + private Date requireTime; + + /** + * 确认完成时间=领导审核确认的承诺完成时间 + */ + @ExcelProperty(value = "确认完成时间=领导审核确认的承诺完成时间") + private Date confirmFinishTime; + + /** + * 实际开始时间(仅记周期,不计工时) + */ + @ExcelProperty(value = "实际开始时间", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "仅=记周期,不计工时") + private Date actualStartTime; + + /** + * 实际结束/关闭时间(仅记周期,不计工时) + */ + @ExcelProperty(value = "实际结束/关闭时间", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "仅=记周期,不计工时") + private Date actualFinishTime; + + /** + * 主报工项目ID + */ + @ExcelProperty(value = "主报工项目ID") + private Long projectId; + + /** + * 项目编号快照 + */ + @ExcelProperty(value = "项目编号快照") + private String projectCode; + + /** + * 项目名称快照 + */ + @ExcelProperty(value = "项目名称快照") + private String projectName; + + /** + * 项目经理用户ID快照 + */ + @ExcelProperty(value = "项目经理用户ID快照") + private Long pmId; + + /** + * 项目经理姓名快照 + */ + @ExcelProperty(value = "项目经理姓名快照") + private String pmName; + + /** + * 关联合同ID(选填) + */ + @ExcelProperty(value = "关联合同ID", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "选=填") + private Long contractId; + + /** + * 合同编号快照 + */ + @ExcelProperty(value = "合同编号快照") + private String contractCode; + + /** + * 发起人ID + */ + @ExcelProperty(value = "发起人ID") + private Long requesterId; + + /** + * 发起人姓名快照 + */ + @ExcelProperty(value = "发起人姓名快照") + private String requesterName; + + /** + * 发起部门ID + */ + @ExcelProperty(value = "发起部门ID") + private Long requestDeptId; + + /** + * 发起部门名称快照 + */ + @ExcelProperty(value = "发起部门名称快照") + private String requestDeptName; + + /** + * 指派人/建议承接人ID(非必填) + */ + @ExcelProperty(value = "指派人/建议承接人ID", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "非=必填") + private Long dispatcherId; + + /** + * 指派人姓名快照 + */ + @ExcelProperty(value = "指派人姓名快照") + private String dispatcherName; + + /** + * 软件部领导/审批人ID(审核/加批/变更审批) + */ + @ExcelProperty(value = "软件部领导/审批人ID", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "审=核/加批/变更审批") + private Long softwareLeaderId; + + /** + * 软件部领导姓名快照 + */ + @ExcelProperty(value = "软件部领导姓名快照") + private String softwareLeaderName; + + /** + * 主执行人ID(唯一,领导审核确定) + */ + @ExcelProperty(value = "主执行人ID", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "唯=一,领导审核确定") + private Long assigneeId; + + /** + * 主执行人姓名快照 + */ + @ExcelProperty(value = "主执行人姓名快照") + private String assigneeName; + + /** + * 预计工时/小时(指派人确认阶段补齐,领导审核认可) + */ + @ExcelProperty(value = "预计工时/小时", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "指=派人确认阶段补齐,领导审核认可") + private BigDecimal estimateWorkload; + + /** + * 实际消耗工时/小时(关闭时填写,0需说明,最小0.5) + */ + @ExcelProperty(value = "实际消耗工时/小时", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "关=闭时填写,0需说明,最小0.5") + private BigDecimal actualWorkload; + + /** + * 完成结果:1已完成 2不执行/终止 3部分完成后终止(仅闭环写入) + */ + @ExcelProperty(value = "完成结果:1已完成 2不执行/终止 3部分完成后终止", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "仅=闭环写入") + private String finishResult; + + /** + * 不执行/终止原因:1无需处理 2重复任务 3需求取消 4条件不满足 5资源不支持 6范围不合理 7其他 + */ + @ExcelProperty(value = "不执行/终止原因:1无需处理 2重复任务 3需求取消 4条件不满足 5资源不支持 6范围不合理 7其他") + private String terminateReason; + + /** + * 完成说明(关闭必填;0工时/终止其他原因在此补充) + */ + @ExcelProperty(value = "完成说明", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "关=闭必填;0工时/终止其他原因在此补充") + private String finishRemark; + + /** + * 关联原任务ID + */ + @ExcelProperty(value = "关联原任务ID") + private Long relatedTaskId; + + /** + * 关联原任务编号快照 + */ + @ExcelProperty(value = "关联原任务编号快照") + private String relatedTaskCode; + + /** + * 关联原因:1关闭后异议 2遗漏补充 3返工处理 4换人承接 5需求延续 6重新发起 7其他 + */ + @ExcelProperty(value = "关联原因:1关闭后异议 2遗漏补充 3返工处理 4换人承接 5需求延续 6重新发起 7其他") + private String relateReason; + + /** + * 关联原因补充说明 + */ + @ExcelProperty(value = "关联原因补充说明") + private String relateRemark; + + /** + * 业务状态:1暂存 2进行中(审批/执行) 3已结束 4作废 + */ + @ExcelProperty(value = "业务状态:1暂存 2进行中(审批/执行) 3已结束 4作废") + private String taskStatus; + + /** + * 流程状态:draft/waiting/finish/back/cancel/invalid/termination + */ + @ExcelProperty(value = "流程状态:draft/waiting/finish/back/cancel/invalid/termination") + private String flowStatus; + + /** + * 抄送人员用户ID(多个逗号分隔,实际抄送由工作流承载) + */ + @ExcelProperty(value = "抄送人员用户ID", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "多=个逗号分隔,实际抄送由工作流承载") + private String ccUserIds; + + /** + * 附件ID(非必填,多个逗号分隔) + */ + @ExcelProperty(value = "附件ID", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "非=必填,多个逗号分隔") + private String ossId; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 变更记录数量 + */ + private Long changeCount; + + /** + * 待审批变更数量 + */ + private Long pendingChangeCount; + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpTempTaskChangeMapper.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpTempTaskChangeMapper.java new file mode 100644 index 00000000..a98952eb --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpTempTaskChangeMapper.java @@ -0,0 +1,153 @@ +package org.dromara.oa.erp.mapper; + +import java.util.List; +import java.util.Collection; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; +import org.dromara.oa.erp.domain.ErpTempTaskChange; +import org.dromara.oa.erp.domain.vo.ErpTempTaskChangeVo; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 临时任务变更记录Mapper接口 + * + * @author zch + * @date 2026-06-17 + */ +public interface ErpTempTaskChangeMapper extends BaseMapperPlus { + + /** + * 查询临时任务变更记录列表 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 临时任务变更记录集合 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "t.create_dept"), + @DataColumn(key = "userName", value = "t.create_by") + }) + public Page selectCustomErpTempTaskChangeVoList(@Param("page") Page page, @Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 查询临时任务变更记录列表 + * + * @param queryWrapper 条件 + * @return 临时任务变更记录集合 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "t.create_dept"), + @DataColumn(key = "userName", value = "t.create_by") + }) + public List selectCustomErpTempTaskChangeVoList(@Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 根据ID查询临时任务变更记录详情 + * + * @param changeId 主键ID + * @return 临时任务变更记录对象 + */ + ErpTempTaskChangeVo selectCustomErpTempTaskChangeVoById(@Param("changeId") Long changeId); + + /** + * 根据ID列表批量查询临时任务变更记录 + * + * @param ids ID集合 + * @return 临时任务变更记录集合 + */ + List selectCustomErpTempTaskChangeVoByIds(@Param("ids") Collection ids); + + /** + * 统计临时任务变更记录记录数 + * + * @param queryWrapper 查询条件 + * @return 记录总数 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "t.create_dept"), + @DataColumn(key = "userName", value = "t.create_by") + }) + Long countCustomErpTempTaskChange(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 分页查询临时任务变更记录(自定义条件) + * + * @param page 分页对象 + * @param queryWrapper 查询条件 + * @return 分页结果 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "t.create_dept"), + @DataColumn(key = "userName", value = "t.create_by") + }) + Page selectCustomErpTempTaskChangeVoPage(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 批量插入临时任务变更记录 + * + * @param list 临时任务变更记录对象集合 + * @return 影响行数 + */ + int batchInsertErpTempTaskChange(@Param("list") List list); + + /** + * 批量更新临时任务变更记录 + * + * @param list 临时任务变更记录对象集合 + * @return 影响行数 + */ + int batchUpdateErpTempTaskChange(@Param("list") List list); + + /** + * 根据自定义条件删除临时任务变更记录 + * + * @param queryWrapper 删除条件 + * @return 影响行数 + */ + int deleteCustomErpTempTaskChange(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据ID列表批量删除临时任务变更记录 + * + * @param ids ID集合 + * @return 影响行数 + */ + int deleteCustomErpTempTaskChangeByIds(@Param("ids") Collection ids); + + /** + * 检查临时任务变更记录是否存在 + * + * @param queryWrapper 查询条件 + * @return 是否存在 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "t.create_dept"), + @DataColumn(key = "userName", value = "t.create_by") + }) + Boolean existsErpTempTaskChange(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 按临时任务查询变更历史 + * + * @param tempTaskId 临时任务ID + * @return 变更历史 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "t.create_dept"), + @DataColumn(key = "userName", value = "t.create_by") + }) + List selectByTempTaskId(@Param("tempTaskId") Long tempTaskId); + + /** + * 统计临时任务待审批变更 + * + * @param tempTaskId 临时任务ID + * @return 待审批变更数量 + */ + Long countPendingByTempTaskId(@Param("tempTaskId") Long tempTaskId); +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpTempTaskMapper.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpTempTaskMapper.java new file mode 100644 index 00000000..8e0c1e99 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpTempTaskMapper.java @@ -0,0 +1,135 @@ +package org.dromara.oa.erp.mapper; + +import java.util.List; +import java.util.Collection; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; +import org.dromara.oa.erp.domain.ErpTempTask; +import org.dromara.oa.erp.domain.vo.ErpTempTaskVo; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 软件部临时任务主Mapper接口 + * + * @author zch + * @date 2026-06-17 + */ +public interface ErpTempTaskMapper extends BaseMapperPlus { + + /** + * 查询软件部临时任务主列表 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 软件部临时任务主集合 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "t.create_dept"), + @DataColumn(key = "userName", value = "t.create_by") + }) + public Page selectCustomErpTempTaskVoList(@Param("page") Page page, @Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 查询软件部临时任务主列表 + * + * @param queryWrapper 条件 + * @return 软件部临时任务主集合 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "t.create_dept"), + @DataColumn(key = "userName", value = "t.create_by") + }) + public List selectCustomErpTempTaskVoList(@Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 根据ID查询软件部临时任务主详情 + * + * @param tempTaskId 主键ID + * @return 软件部临时任务主对象 + */ + ErpTempTaskVo selectCustomErpTempTaskVoById(@Param("tempTaskId") Long tempTaskId); + + /** + * 根据ID列表批量查询软件部临时任务主 + * + * @param ids ID集合 + * @return 软件部临时任务主集合 + */ + List selectCustomErpTempTaskVoByIds(@Param("ids") Collection ids); + + /** + * 统计软件部临时任务主记录数 + * + * @param queryWrapper 查询条件 + * @return 记录总数 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "t.create_dept"), + @DataColumn(key = "userName", value = "t.create_by") + }) + Long countCustomErpTempTask(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 分页查询软件部临时任务主(自定义条件) + * + * @param page 分页对象 + * @param queryWrapper 查询条件 + * @return 分页结果 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "t.create_dept"), + @DataColumn(key = "userName", value = "t.create_by") + }) + Page selectCustomErpTempTaskVoPage(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 批量插入软件部临时任务主 + * + * @param list 软件部临时任务主对象集合 + * @return 影响行数 + */ + int batchInsertErpTempTask(@Param("list") List list); + + /** + * 批量更新软件部临时任务主 + * + * @param list 软件部临时任务主对象集合 + * @return 影响行数 + */ + int batchUpdateErpTempTask(@Param("list") List list); + + /** + * 根据自定义条件删除软件部临时任务主 + * + * @param queryWrapper 删除条件 + * @return 影响行数 + */ + int deleteCustomErpTempTask(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据ID列表批量删除软件部临时任务主 + * + * @param ids ID集合 + * @return 影响行数 + */ + int deleteCustomErpTempTaskByIds(@Param("ids") Collection ids); + + /** + * 检查软件部临时任务主是否存在 + * + * @param queryWrapper 查询条件 + * @return 是否存在 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "t.create_dept"), + @DataColumn(key = "userName", value = "t.create_by") + }) + Boolean existsErpTempTask(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpTempTaskChangeService.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpTempTaskChangeService.java new file mode 100644 index 00000000..fff7128d --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpTempTaskChangeService.java @@ -0,0 +1,69 @@ +package org.dromara.oa.erp.service; + +import org.dromara.oa.erp.domain.ErpTempTaskChange; +import org.dromara.oa.erp.domain.vo.ErpTempTaskChangeVo; +import org.dromara.oa.erp.domain.bo.ErpTempTaskChangeBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 临时任务变更记录Service接口 + * + * @author zch + * @date 2026-06-17 + */ +public interface IErpTempTaskChangeService { + + /** + * 查询临时任务变更记录 + * + * @param changeId 主键 + * @return 临时任务变更记录 + */ + ErpTempTaskChangeVo queryById(Long changeId); + + /** + * 分页查询临时任务变更记录列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 临时任务变更记录分页列表 + */ + TableDataInfo queryPageList(ErpTempTaskChangeBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的临时任务变更记录列表 + * + * @param bo 查询条件 + * @return 临时任务变更记录列表 + */ + List queryList(ErpTempTaskChangeBo bo); + + /** + * 新增临时任务变更记录 + * + * @param bo 临时任务变更记录 + * @return 是否新增成功 + */ + Boolean insertByBo(ErpTempTaskChangeBo bo); + + /** + * 修改临时任务变更记录 + * + * @param bo 临时任务变更记录 + * @return 是否修改成功 + */ + Boolean updateByBo(ErpTempTaskChangeBo bo); + + /** + * 校验并批量删除临时任务变更记录信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpTempTaskService.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpTempTaskService.java new file mode 100644 index 00000000..b1dc27a0 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpTempTaskService.java @@ -0,0 +1,111 @@ +package org.dromara.oa.erp.service; + +import org.dromara.oa.erp.domain.ErpTempTask; +import org.dromara.oa.erp.domain.bo.ErpTempTaskChangeBo; +import org.dromara.oa.erp.domain.vo.ErpTempTaskChangeVo; +import org.dromara.oa.erp.domain.vo.ErpTempTaskVo; +import org.dromara.oa.erp.domain.bo.ErpTempTaskBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 软件部临时任务主Service接口 + * + * @author zch + * @date 2026-06-17 + */ +public interface IErpTempTaskService { + + /** + * 查询软件部临时任务主 + * + * @param tempTaskId 主键 + * @return 软件部临时任务主 + */ + ErpTempTaskVo queryById(Long tempTaskId); + + /** + * 分页查询软件部临时任务主列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 软件部临时任务主分页列表 + */ + TableDataInfo queryPageList(ErpTempTaskBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的软件部临时任务主列表 + * + * @param bo 查询条件 + * @return 软件部临时任务主列表 + */ + List queryList(ErpTempTaskBo bo); + + /** + * 新增软件部临时任务主 + * + * @param bo 软件部临时任务主 + * @return 是否新增成功 + */ + Boolean insertByBo(ErpTempTaskBo bo); + + /** + * 修改软件部临时任务主 + * + * @param bo 软件部临时任务主 + * @return 是否修改成功 + */ + Boolean updateByBo(ErpTempTaskBo bo); + + /** + * 提交临时任务并发起工作流 + * + * @param bo 临时任务 + * @return 临时任务详情 + */ + ErpTempTaskVo tempTaskSubmitAndFlowStart(ErpTempTaskBo bo); + + /** + * 主执行人关闭临时任务,写入业务闭环结果 + * + * @param bo 临时任务关闭信息 + * @return 是否关闭成功 + */ + Boolean closeTask(ErpTempTaskBo bo); + + /** + * 查询临时任务变更历史 + * + * @param tempTaskId 临时任务ID + * @return 变更历史 + */ + List queryChangeList(Long tempTaskId); + + /** + * 发起临时任务变更记录 + * + * @param bo 变更记录 + * @return 是否保存成功 + */ + Boolean saveChange(ErpTempTaskChangeBo bo); + + /** + * 审批临时任务变更记录 + * + * @param bo 变更审批信息 + * @return 是否审批成功 + */ + Boolean approveChange(ErpTempTaskChangeBo bo); + + /** + * 校验并批量删除软件部临时任务主信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpTempTaskChangeServiceImpl.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpTempTaskChangeServiceImpl.java new file mode 100644 index 00000000..d0323924 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpTempTaskChangeServiceImpl.java @@ -0,0 +1,149 @@ +package org.dromara.oa.erp.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; + import org.dromara.common.mybatis.core.page.TableDataInfo; + import org.dromara.common.mybatis.core.page.PageQuery; + import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.yulichang.toolkit.JoinWrappers; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.dromara.oa.erp.domain.bo.ErpTempTaskChangeBo; +import org.dromara.oa.erp.domain.vo.ErpTempTaskChangeVo; +import org.dromara.oa.erp.domain.ErpTempTaskChange; +import org.dromara.oa.erp.mapper.ErpTempTaskChangeMapper; +import org.dromara.oa.erp.service.IErpTempTaskChangeService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 临时任务变更记录Service业务层处理 + * + * @author zch + * @date 2026-06-17 + */ +@RequiredArgsConstructor +@Service +public class ErpTempTaskChangeServiceImpl implements IErpTempTaskChangeService { + + private final ErpTempTaskChangeMapper baseMapper; + + /** + * 查询临时任务变更记录 + * + * @param changeId 主键 + * @return 临时任务变更记录 + */ + @Override + public ErpTempTaskChangeVo queryById(Long changeId){ + return baseMapper.selectVoById(changeId); + } + + /** + * 分页查询临时任务变更记录列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 临时任务变更记录分页列表 + */ + @Override + public TableDataInfo queryPageList(ErpTempTaskChangeBo bo, PageQuery pageQuery) { + MPJLambdaWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectCustomErpTempTaskChangeVoList(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的临时任务变更记录列表 + * + * @param bo 查询条件 + * @return 临时任务变更记录列表 + */ + @Override + public List queryList(ErpTempTaskChangeBo bo) { + MPJLambdaWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectCustomErpTempTaskChangeVoList(lqw); + } + + private MPJLambdaWrapper buildQueryWrapper(ErpTempTaskChangeBo bo) { + Map params = bo.getParams(); + MPJLambdaWrapper lqw = JoinWrappers.lambda(ErpTempTaskChange.class) + .selectAll(ErpTempTaskChange.class) + .eq(ErpTempTaskChange::getDelFlag, "0") + .eq(bo.getTempTaskId() != null, ErpTempTaskChange::getTempTaskId, bo.getTempTaskId()) + .eq(StringUtils.isNotBlank(bo.getTempTaskCode()), ErpTempTaskChange::getTempTaskCode, bo.getTempTaskCode()) + .eq(StringUtils.isNotBlank(bo.getChangeType()), ErpTempTaskChange::getChangeType, bo.getChangeType()) + .eq(StringUtils.isNotBlank(bo.getChangeReason()), ErpTempTaskChange::getChangeReason, bo.getChangeReason()) + .eq(StringUtils.isNotBlank(bo.getBeforeContent()), ErpTempTaskChange::getBeforeContent, bo.getBeforeContent()) + .eq(StringUtils.isNotBlank(bo.getAfterContent()), ErpTempTaskChange::getAfterContent, bo.getAfterContent()) + .eq(StringUtils.isNotBlank(bo.getWorkloadEffect()), ErpTempTaskChange::getWorkloadEffect, bo.getWorkloadEffect()) + .eq(StringUtils.isNotBlank(bo.getTimeEffect()), ErpTempTaskChange::getTimeEffect, bo.getTimeEffect()) + .eq(StringUtils.isNotBlank(bo.getScopeEffect()), ErpTempTaskChange::getScopeEffect, bo.getScopeEffect()) + .eq(bo.getChangeUserId() != null, ErpTempTaskChange::getChangeUserId, bo.getChangeUserId()) + .like(StringUtils.isNotBlank(bo.getChangeUserName()), ErpTempTaskChange::getChangeUserName, bo.getChangeUserName()) + .eq(StringUtils.isNotBlank(bo.getApproveResult()), ErpTempTaskChange::getApproveResult, bo.getApproveResult()) + .eq(bo.getApproverId() != null, ErpTempTaskChange::getApproverId, bo.getApproverId()) + .like(StringUtils.isNotBlank(bo.getApproverName()), ErpTempTaskChange::getApproverName, bo.getApproverName()) + .eq(StringUtils.isNotBlank(bo.getApproveComment()), ErpTempTaskChange::getApproveComment, bo.getApproveComment()) + .eq(bo.getApproveTime() != null, ErpTempTaskChange::getApproveTime, bo.getApproveTime()) + .eq(StringUtils.isNotBlank(bo.getFlowStatus()), ErpTempTaskChange::getFlowStatus, bo.getFlowStatus()) +; + return lqw; + } + + /** + * 新增临时任务变更记录 + * + * @param bo 临时任务变更记录 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(ErpTempTaskChangeBo bo) { + ErpTempTaskChange add = MapstructUtils.convert(bo, ErpTempTaskChange.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setChangeId(add.getChangeId()); + } + return flag; + } + + /** + * 修改临时任务变更记录 + * + * @param bo 临时任务变更记录 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(ErpTempTaskChangeBo bo) { + ErpTempTaskChange update = MapstructUtils.convert(bo, ErpTempTaskChange.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(ErpTempTaskChange entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除临时任务变更记录信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpTempTaskServiceImpl.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpTempTaskServiceImpl.java new file mode 100644 index 00000000..15f2d582 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpTempTaskServiceImpl.java @@ -0,0 +1,632 @@ +package org.dromara.oa.erp.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import cn.hutool.core.convert.Convert; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.yulichang.toolkit.JoinWrappers; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import lombok.extern.slf4j.Slf4j; +import lombok.RequiredArgsConstructor; +import org.apache.dubbo.config.annotation.DubboReference; +import org.apache.seata.spring.annotation.GlobalTransactional; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.oa.erp.domain.ErpTempTaskChange; +import org.dromara.oa.erp.mapper.ErpTempTaskChangeMapper; +import org.dromara.system.api.RemoteCodeRuleService; +import org.dromara.workflow.api.RemoteWorkflowService; +import org.dromara.workflow.api.domain.RemoteStartProcess; +import org.dromara.workflow.api.event.ProcessEvent; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; +import org.dromara.oa.erp.domain.bo.ErpTempTaskBo; +import org.dromara.oa.erp.domain.bo.ErpTempTaskChangeBo; +import org.dromara.oa.erp.domain.vo.ErpTempTaskChangeVo; +import org.dromara.oa.erp.domain.vo.ErpTempTaskVo; +import org.dromara.oa.erp.domain.ErpTempTask; +import org.dromara.oa.erp.mapper.ErpTempTaskMapper; +import org.dromara.oa.erp.service.IErpTempTaskService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; +import java.util.Date; +import java.util.Objects; +import java.math.BigDecimal; + +/** + * 软件部临时任务主Service业务层处理 + * + * @author zch + * @date 2026-06-17 + */ +@RequiredArgsConstructor +@Service +@Slf4j +public class ErpTempTaskServiceImpl implements IErpTempTaskService { + + private static final String FLOW_CODE = "OATT"; + private static final String CODE_RULE = "LSRW"; + private static final String STATUS_DRAFT = "1"; + private static final String STATUS_RUNNING = "2"; + private static final String STATUS_FINISHED = "3"; + private static final String STATUS_INVALID = "4"; + private static final BigDecimal MIN_WORKLOAD_STEP = new BigDecimal("0.5"); + + private final ErpTempTaskMapper baseMapper; + private final ErpTempTaskChangeMapper changeMapper; + + @DubboReference(timeout = 30000) + private RemoteWorkflowService remoteWorkflowService; + + @DubboReference(timeout = 30000) + private RemoteCodeRuleService remoteCodeRuleService; + + /** + * 查询软件部临时任务主 + * + * @param tempTaskId 主键 + * @return 软件部临时任务主 + */ + @Override + public ErpTempTaskVo queryById(Long tempTaskId){ + return baseMapper.selectCustomErpTempTaskVoById(tempTaskId); + } + + /** + * 分页查询软件部临时任务主列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 软件部临时任务主分页列表 + */ + @Override + public TableDataInfo queryPageList(ErpTempTaskBo bo, PageQuery pageQuery) { + MPJLambdaWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectCustomErpTempTaskVoList(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的软件部临时任务主列表 + * + * @param bo 查询条件 + * @return 软件部临时任务主列表 + */ + @Override + public List queryList(ErpTempTaskBo bo) { + MPJLambdaWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectCustomErpTempTaskVoList(lqw); + } + + private MPJLambdaWrapper buildQueryWrapper(ErpTempTaskBo bo) { + Map params = bo.getParams(); + MPJLambdaWrapper lqw = JoinWrappers.lambda(ErpTempTask.class) + .selectAll(ErpTempTask.class) + .eq(ErpTempTask::getDelFlag, "0") + .eq(StringUtils.isNotBlank(bo.getTempTaskCode()), ErpTempTask::getTempTaskCode, bo.getTempTaskCode()) + .eq(StringUtils.isNotBlank(bo.getTaskTitle()), ErpTempTask::getTaskTitle, bo.getTaskTitle()) + .eq(StringUtils.isNotBlank(bo.getTaskDesc()), ErpTempTask::getTaskDesc, bo.getTaskDesc()) + .eq(StringUtils.isNotBlank(bo.getPriority()), ErpTempTask::getPriority, bo.getPriority()) + .eq(StringUtils.isNotBlank(bo.getUrgentReason()), ErpTempTask::getUrgentReason, bo.getUrgentReason()) + .eq(bo.getRequireTime() != null, ErpTempTask::getRequireTime, bo.getRequireTime()) + .eq(bo.getConfirmFinishTime() != null, ErpTempTask::getConfirmFinishTime, bo.getConfirmFinishTime()) + .eq(bo.getActualStartTime() != null, ErpTempTask::getActualStartTime, bo.getActualStartTime()) + .eq(bo.getActualFinishTime() != null, ErpTempTask::getActualFinishTime, bo.getActualFinishTime()) + .eq(bo.getProjectId() != null, ErpTempTask::getProjectId, bo.getProjectId()) + .eq(StringUtils.isNotBlank(bo.getProjectCode()), ErpTempTask::getProjectCode, bo.getProjectCode()) + .like(StringUtils.isNotBlank(bo.getProjectName()), ErpTempTask::getProjectName, bo.getProjectName()) + .eq(bo.getPmId() != null, ErpTempTask::getPmId, bo.getPmId()) + .like(StringUtils.isNotBlank(bo.getPmName()), ErpTempTask::getPmName, bo.getPmName()) + .eq(bo.getContractId() != null, ErpTempTask::getContractId, bo.getContractId()) + .eq(StringUtils.isNotBlank(bo.getContractCode()), ErpTempTask::getContractCode, bo.getContractCode()) + .eq(bo.getRequesterId() != null, ErpTempTask::getRequesterId, bo.getRequesterId()) + .like(StringUtils.isNotBlank(bo.getRequesterName()), ErpTempTask::getRequesterName, bo.getRequesterName()) + .eq(bo.getRequestDeptId() != null, ErpTempTask::getRequestDeptId, bo.getRequestDeptId()) + .like(StringUtils.isNotBlank(bo.getRequestDeptName()), ErpTempTask::getRequestDeptName, bo.getRequestDeptName()) + .eq(bo.getDispatcherId() != null, ErpTempTask::getDispatcherId, bo.getDispatcherId()) + .like(StringUtils.isNotBlank(bo.getDispatcherName()), ErpTempTask::getDispatcherName, bo.getDispatcherName()) + .eq(bo.getSoftwareLeaderId() != null, ErpTempTask::getSoftwareLeaderId, bo.getSoftwareLeaderId()) + .like(StringUtils.isNotBlank(bo.getSoftwareLeaderName()), ErpTempTask::getSoftwareLeaderName, bo.getSoftwareLeaderName()) + .eq(bo.getAssigneeId() != null, ErpTempTask::getAssigneeId, bo.getAssigneeId()) + .like(StringUtils.isNotBlank(bo.getAssigneeName()), ErpTempTask::getAssigneeName, bo.getAssigneeName()) + .eq(bo.getEstimateWorkload() != null, ErpTempTask::getEstimateWorkload, bo.getEstimateWorkload()) + .eq(bo.getActualWorkload() != null, ErpTempTask::getActualWorkload, bo.getActualWorkload()) + .eq(StringUtils.isNotBlank(bo.getFinishResult()), ErpTempTask::getFinishResult, bo.getFinishResult()) + .eq(StringUtils.isNotBlank(bo.getTerminateReason()), ErpTempTask::getTerminateReason, bo.getTerminateReason()) + .eq(StringUtils.isNotBlank(bo.getFinishRemark()), ErpTempTask::getFinishRemark, bo.getFinishRemark()) + .eq(bo.getRelatedTaskId() != null, ErpTempTask::getRelatedTaskId, bo.getRelatedTaskId()) + .eq(StringUtils.isNotBlank(bo.getRelatedTaskCode()), ErpTempTask::getRelatedTaskCode, bo.getRelatedTaskCode()) + .eq(StringUtils.isNotBlank(bo.getRelateReason()), ErpTempTask::getRelateReason, bo.getRelateReason()) + .eq(StringUtils.isNotBlank(bo.getRelateRemark()), ErpTempTask::getRelateRemark, bo.getRelateRemark()) + .eq(StringUtils.isNotBlank(bo.getTaskStatus()), ErpTempTask::getTaskStatus, bo.getTaskStatus()) + .eq(StringUtils.isNotBlank(bo.getFlowStatus()), ErpTempTask::getFlowStatus, bo.getFlowStatus()) + .eq(StringUtils.isNotBlank(bo.getCcUserIds()), ErpTempTask::getCcUserIds, bo.getCcUserIds()) + .eq(StringUtils.isNotBlank(bo.getOssId()), ErpTempTask::getOssId, bo.getOssId()) +; + return lqw; + } + + /** + * 新增软件部临时任务主 + * + * @param bo 软件部临时任务主 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(ErpTempTaskBo bo) { + prepareDraft(bo); + ErpTempTask add = MapstructUtils.convert(bo, ErpTempTask.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setTempTaskId(add.getTempTaskId()); + } + return flag; + } + + /** + * 修改软件部临时任务主 + * + * @param bo 软件部临时任务主 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(ErpTempTaskBo bo) { + checkEditable(bo.getTempTaskId()); + prepareDraft(bo); + ErpTempTask update = MapstructUtils.convert(bo, ErpTempTask.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + @Override + @GlobalTransactional(rollbackFor = Exception.class) + public ErpTempTaskVo tempTaskSubmitAndFlowStart(ErpTempTaskBo bo) { + validBeforeSubmit(bo); + prepareDraft(bo); + bo.setTaskStatus(STATUS_RUNNING); + bo.setFlowStatus(BusinessStatusEnum.WAITING.getStatus()); + + boolean saved; + if (bo.getTempTaskId() == null) { + ErpTempTask add = MapstructUtils.convert(bo, ErpTempTask.class); + validEntityBeforeSave(add); + saved = baseMapper.insert(add) > 0; + bo.setTempTaskId(add.getTempTaskId()); + } else { + checkEditable(bo.getTempTaskId()); + ErpTempTask update = MapstructUtils.convert(bo, ErpTempTask.class); + validEntityBeforeSave(update); + saved = baseMapper.updateById(update) > 0; + } + if (!saved || bo.getTempTaskId() == null) { + throw new ServiceException("临时任务保存失败,无法发起流程"); + } + + RemoteStartProcess startProcess = new RemoteStartProcess(); + startProcess.setBusinessId(bo.getTempTaskId().toString()); + startProcess.setFlowCode(FLOW_CODE); + startProcess.setVariables(buildWorkflowVariables(bo)); + bo.getBizExt().setBusinessId(startProcess.getBusinessId()); + bo.getBizExt().setBusinessCode(bo.getTempTaskCode()); + bo.getBizExt().setBusinessTitle(buildBusinessTitle(bo)); + startProcess.setBizExt(bo.getBizExt()); + + boolean started = remoteWorkflowService.startCompleteTask(startProcess); + if (!started) { + throw new ServiceException("流程发起异常"); + } + return baseMapper.selectCustomErpTempTaskVoById(bo.getTempTaskId()); + } + + @Override + public Boolean closeTask(ErpTempTaskBo bo) { + if (bo.getTempTaskId() == null) { + throw new ServiceException("临时任务ID不能为空"); + } + ErpTempTask task = baseMapper.selectById(bo.getTempTaskId()); + if (task == null) { + throw new ServiceException("临时任务不存在"); + } + if (StringUtils.isNotBlank(task.getFinishResult())) { + throw new ServiceException("临时任务已闭环,不能重复关闭"); + } + Long userId = LoginHelper.getUserId(); + if (task.getAssigneeId() != null && !Objects.equals(task.getAssigneeId(), userId)) { + throw new ServiceException("只有主执行人可以关闭临时任务"); + } + if (hasPendingChange(task.getTempTaskId())) { + throw new ServiceException("存在待审批变更,不允许关闭,请先完成变更审批"); + } + validBeforeClose(bo); + + ErpTempTask update = new ErpTempTask(); + update.setTempTaskId(task.getTempTaskId()); + update.setActualWorkload(bo.getActualWorkload()); + update.setFinishResult(bo.getFinishResult()); + update.setTerminateReason(bo.getTerminateReason()); + update.setFinishRemark(bo.getFinishRemark()); + update.setActualFinishTime(new Date()); + update.setTaskStatus(STATUS_FINISHED); + return baseMapper.updateById(update) > 0; + } + + @Override + public List queryChangeList(Long tempTaskId) { + if (tempTaskId == null) { + throw new ServiceException("临时任务ID不能为空"); + } + return changeMapper.selectByTempTaskId(tempTaskId); + } + + @Override + public Boolean saveChange(ErpTempTaskChangeBo bo) { + validBeforeChange(bo); + ErpTempTask task = baseMapper.selectById(bo.getTempTaskId()); + if (task == null) { + throw new ServiceException("临时任务不存在"); + } + if (StringUtils.isNotBlank(task.getFinishResult())) { + throw new ServiceException("临时任务已闭环,不能发起变更"); + } + if (STATUS_DRAFT.equals(task.getTaskStatus())) { + throw new ServiceException("草稿任务请直接修改,不需要发起变更"); + } + ErpTempTaskChange add = MapstructUtils.convert(bo, ErpTempTaskChange.class); + add.setTempTaskCode(task.getTempTaskCode()); + add.setChangeUserId(LoginHelper.getUserId()); + if (StringUtils.isBlank(add.getChangeUserName()) && LoginHelper.getLoginUser() != null) { + add.setChangeUserName(LoginHelper.getLoginUser().getNickname()); + } + add.setApproveResult(null); + add.setApproverId(null); + add.setApproverName(null); + add.setApproveTime(null); + add.setFlowStatus(BusinessStatusEnum.WAITING.getStatus()); + return changeMapper.insert(add) > 0; + } + + @Override + public Boolean approveChange(ErpTempTaskChangeBo bo) { + if (bo.getChangeId() == null) { + throw new ServiceException("变更记录ID不能为空"); + } + if (StringUtils.isBlank(bo.getApproveResult())) { + throw new ServiceException("变更审批结论不能为空"); + } + ErpTempTaskChange change = changeMapper.selectById(bo.getChangeId()); + if (change == null) { + throw new ServiceException("变更记录不存在"); + } + if (StringUtils.isNotBlank(change.getApproveResult())) { + throw new ServiceException("变更记录已审批,不能重复处理"); + } + ErpTempTask task = baseMapper.selectById(change.getTempTaskId()); + if (task == null) { + throw new ServiceException("临时任务不存在"); + } + if (StringUtils.isNotBlank(task.getFinishResult())) { + throw new ServiceException("临时任务已闭环,不能审批变更"); + } + ErpTempTaskChange update = new ErpTempTaskChange(); + update.setChangeId(change.getChangeId()); + update.setApproveResult(bo.getApproveResult()); + update.setApproveComment(bo.getApproveComment()); + update.setApproverId(LoginHelper.getUserId()); + if (LoginHelper.getLoginUser() != null) { + update.setApproverName(LoginHelper.getLoginUser().getNickname()); + } + update.setApproveTime(new Date()); + update.setFlowStatus(BusinessStatusEnum.FINISH.getStatus()); + boolean flag = changeMapper.updateById(update) > 0; + if (flag && "1".equals(bo.getApproveResult())) { + applyApprovedChange(task, change); + } + return flag; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(ErpTempTask entity){ + if (entity == null) { + throw new ServiceException("临时任务数据不能为空"); + } + if (StringUtils.isBlank(entity.getTaskDesc())) { + throw new ServiceException("任务描述不能为空"); + } + if (entity.getRequireTime() == null) { + throw new ServiceException("需求时间不能为空"); + } + if (("3".equals(entity.getPriority()) || "4".equals(entity.getPriority())) + && StringUtils.isBlank(entity.getUrgentReason())) { + throw new ServiceException("优先级为紧急或特急时必须填写紧急原因"); + } + if (entity.getRelatedTaskId() != null) { + validRelatedTask(entity.getRelatedTaskId()); + if (StringUtils.isBlank(entity.getRelateReason())) { + throw new ServiceException("关联原任务时必须选择关联原因"); + } + } + } + + /** + * 校验并批量删除软件部临时任务主信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + for (Long id : ids) { + ErpTempTask task = baseMapper.selectById(id); + if (task == null) { + continue; + } + if (StringUtils.isNotBlank(task.getFinishResult())) { + throw new ServiceException("已结束临时任务不能删除"); + } + String flowStatus = task.getFlowStatus(); + if (StringUtils.isNotBlank(flowStatus) + && !BusinessStatusEnum.DRAFT.getStatus().equals(flowStatus) + && !BusinessStatusEnum.BACK.getStatus().equals(flowStatus) + && !BusinessStatusEnum.CANCEL.getStatus().equals(flowStatus)) { + throw new ServiceException("非草稿/退回/撤销状态临时任务不能删除"); + } + } + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 临时任务流程状态回写。完成结果不在这里写,必须由关闭动作显式写入。 + */ + @EventListener(condition = "#processEvent.flowCode == 'OATT'") + public void processHandler(ProcessEvent processEvent) { + TenantHelper.dynamic(processEvent.getTenantId(), () -> { + ErpTempTask task = baseMapper.selectById(Long.valueOf(processEvent.getBusinessId())); + if (task == null) { + log.warn("临时任务不存在, businessId: {}", processEvent.getBusinessId()); + return; + } + task.setFlowStatus(processEvent.getStatus()); + if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.WAITING.getStatus())) { + task.setTaskStatus(STATUS_RUNNING); + } else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.FINISH.getStatus())) { + task.setTaskStatus(STATUS_FINISHED); + } else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.INVALID.getStatus()) + || Objects.equals(processEvent.getStatus(), BusinessStatusEnum.TERMINATION.getStatus())) { + task.setTaskStatus(STATUS_INVALID); + } else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.BACK.getStatus()) + || Objects.equals(processEvent.getStatus(), BusinessStatusEnum.CANCEL.getStatus())) { + task.setTaskStatus(STATUS_DRAFT); + } + baseMapper.updateById(task); + }); + } + + private void prepareDraft(ErpTempTaskBo bo) { + if (StringUtils.isBlank(bo.getTempTaskCode())) { + String tempTaskCode = remoteCodeRuleService.selectCodeRuleCode(CODE_RULE); + if (StringUtils.isBlank(tempTaskCode)) { + throw new ServiceException("生成临时任务编号失败"); + } + bo.setTempTaskCode(tempTaskCode); + } + if (bo.getRequesterId() == null) { + bo.setRequesterId(LoginHelper.getUserId()); + } + if (StringUtils.isBlank(bo.getRequesterName()) && LoginHelper.getLoginUser() != null) { + bo.setRequesterName(LoginHelper.getLoginUser().getNickname()); + } + if (bo.getRequestDeptId() == null) { + bo.setRequestDeptId(LoginHelper.getDeptId()); + } + if (StringUtils.isBlank(bo.getRequestDeptName()) && LoginHelper.getLoginUser() != null) { + bo.setRequestDeptName(LoginHelper.getLoginUser().getDeptName()); + } + if (StringUtils.isBlank(bo.getPriority())) { + bo.setPriority("1"); + } + if (StringUtils.isBlank(bo.getTaskStatus())) { + bo.setTaskStatus(STATUS_DRAFT); + } + if (StringUtils.isBlank(bo.getFlowStatus())) { + bo.setFlowStatus(BusinessStatusEnum.DRAFT.getStatus()); + } + bo.setFlowCode(FLOW_CODE); + } + + private void validBeforeSubmit(ErpTempTaskBo bo) { + if (bo == null) { + throw new ServiceException("临时任务数据不能为空"); + } + if (StringUtils.isBlank(bo.getTaskDesc())) { + throw new ServiceException("任务描述不能为空"); + } + if (bo.getRequireTime() == null) { + throw new ServiceException("需求时间不能为空"); + } + if (("3".equals(bo.getPriority()) || "4".equals(bo.getPriority())) + && StringUtils.isBlank(bo.getUrgentReason())) { + throw new ServiceException("优先级为紧急或特急时必须填写紧急原因"); + } + } + + private Map buildWorkflowVariables(ErpTempTaskBo bo) { + Map variables = bo.getVariables(); + variables.put("ignore", true); + variables.put("has_dispatcher", bo.getDispatcherId() == null ? "0" : "1"); + variables.putIfAbsent("extra_approval_required", "0"); + variables.putIfAbsent("has_change", "0"); + variables.put("dispatcherId", bo.getDispatcherId()); + variables.put("requesterId", bo.getRequesterId()); + variables.put("requestDeptId", bo.getRequestDeptId()); + variables.put("softwareLeaderId", bo.getSoftwareLeaderId()); + variables.put("assigneeId", bo.getAssigneeId()); + variables.put("ccUserIds", bo.getCcUserIds()); + variables.put("taskTitle", bo.getTaskTitle()); + variables.put("taskDesc", bo.getTaskDesc()); + variables.put("priority", bo.getPriority()); + variables.put("urgentReason", bo.getUrgentReason()); + variables.put("requireTime", bo.getRequireTime()); + variables.put("confirmFinishTime", bo.getConfirmFinishTime()); + variables.put("projectId", bo.getProjectId()); + variables.put("contractId", bo.getContractId()); + variables.put("estimateWorkload", bo.getEstimateWorkload()); + variables.put("actualWorkload", bo.getActualWorkload()); + variables.put("finishResult", bo.getFinishResult()); + variables.put("terminateReason", bo.getTerminateReason()); + variables.put("finishRemark", bo.getFinishRemark()); + variables.put("relatedTaskId", bo.getRelatedTaskId()); + variables.put("relateReason", bo.getRelateReason()); + variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + return variables; + } + + private String buildBusinessTitle(ErpTempTaskBo bo) { + String title = StringUtils.isNotBlank(bo.getTaskDesc()) ? bo.getTaskDesc() : bo.getTaskTitle(); + StringBuilder builder = new StringBuilder(); + builder.append(StringUtils.blankToDefault(bo.getTempTaskCode(), "临时任务")); + if (StringUtils.isNotBlank(title)) { + builder.append("-").append(StringUtils.substring(title, 0, 30)); + } + if (StringUtils.isNotBlank(bo.getRequesterName())) { + builder.append("-发起人:").append(bo.getRequesterName()); + } + if (StringUtils.isNotBlank(bo.getProjectName())) { + builder.append("-项目:").append(bo.getProjectName()); + } + if (StringUtils.isNotBlank(bo.getPriority())) { + builder.append("-优先级:").append(bo.getPriority()); + } + return builder.toString(); + } + + private void validBeforeClose(ErpTempTaskBo bo) { + if (bo.getActualWorkload() == null) { + throw new ServiceException("实际消耗工时不能为空"); + } + if (bo.getActualWorkload().compareTo(BigDecimal.ZERO) < 0) { + throw new ServiceException("实际消耗工时不能小于0"); + } + if (bo.getActualWorkload().remainder(MIN_WORKLOAD_STEP).compareTo(BigDecimal.ZERO) != 0) { + throw new ServiceException("实际消耗工时最小粒度为0.5小时"); + } + if (bo.getActualWorkload().compareTo(BigDecimal.ZERO) == 0 && StringUtils.isBlank(bo.getFinishRemark())) { + throw new ServiceException("实际消耗工时为0时必须在完成说明中补充原因"); + } + if (StringUtils.isBlank(bo.getFinishResult())) { + throw new ServiceException("完成结果不能为空"); + } + if (StringUtils.isBlank(bo.getFinishRemark())) { + throw new ServiceException("完成说明不能为空"); + } + if (("2".equals(bo.getFinishResult()) || "3".equals(bo.getFinishResult())) && StringUtils.isBlank(bo.getTerminateReason())) { + throw new ServiceException("完成结果为不执行/终止或部分完成后终止时必须选择终止原因"); + } + if ("7".equals(bo.getTerminateReason()) && StringUtils.isBlank(bo.getFinishRemark())) { + throw new ServiceException("终止原因为其他时必须在完成说明中补充原因"); + } + } + + private void checkEditable(Long tempTaskId) { + if (tempTaskId == null) { + return; + } + ErpTempTask existing = baseMapper.selectById(tempTaskId); + if (existing == null) { + throw new ServiceException("临时任务不存在"); + } + if (StringUtils.isNotBlank(existing.getFinishResult())) { + throw new ServiceException("临时任务已闭环,不能修改"); + } + String flowStatus = existing.getFlowStatus(); + if (StringUtils.isNotBlank(flowStatus) + && !BusinessStatusEnum.DRAFT.getStatus().equals(flowStatus) + && !BusinessStatusEnum.BACK.getStatus().equals(flowStatus) + && !BusinessStatusEnum.CANCEL.getStatus().equals(flowStatus)) { + throw new ServiceException("当前流程状态不允许编辑"); + } + } + + private void validRelatedTask(Long relatedTaskId) { + ErpTempTask related = baseMapper.selectById(relatedTaskId); + if (related == null) { + throw new ServiceException("关联的原任务不存在"); + } + if (StringUtils.isBlank(related.getFinishResult())) { + throw new ServiceException("关联的原任务尚未结束,未结束任务必须在原流程内处理"); + } + } + + private boolean hasPendingChange(Long tempTaskId) { + Long count = changeMapper.countPendingByTempTaskId(tempTaskId); + return count != null && count > 0; + } + + private void validBeforeChange(ErpTempTaskChangeBo bo) { + if (bo == null) { + throw new ServiceException("变更记录不能为空"); + } + if (bo.getTempTaskId() == null) { + throw new ServiceException("临时任务ID不能为空"); + } + if (StringUtils.isBlank(bo.getChangeType())) { + throw new ServiceException("变更类型不能为空"); + } + if (StringUtils.isBlank(bo.getChangeReason())) { + throw new ServiceException("变更原因不能为空"); + } + if (StringUtils.isBlank(bo.getBeforeContent()) && StringUtils.isBlank(bo.getAfterContent())) { + throw new ServiceException("变更前内容和变更后内容不能同时为空"); + } + } + + private void applyApprovedChange(ErpTempTask task, ErpTempTaskChange change) { + ErpTempTask update = new ErpTempTask(); + update.setTempTaskId(task.getTempTaskId()); + if ("1".equals(change.getChangeType()) && StringUtils.isNotBlank(change.getAfterContent())) { + update.setTaskDesc(change.getAfterContent()); + } else if ("2".equals(change.getChangeType()) && StringUtils.isNotBlank(change.getAfterContent())) { + update.setEstimateWorkload(parseWorkload(change.getAfterContent())); + } else if ("3".equals(change.getChangeType()) && StringUtils.isNotBlank(change.getAfterContent())) { + update.setConfirmFinishTime(parseDate(change.getAfterContent())); + } else if ("4".equals(change.getChangeType()) && StringUtils.isNotBlank(change.getAfterContent())) { + update.setAssigneeId(Convert.toLong(change.getAfterContent())); + } else if ("5".equals(change.getChangeType()) && StringUtils.isNotBlank(change.getAfterContent())) { + update.setProjectId(Convert.toLong(change.getAfterContent())); + } else if ("7".equals(change.getChangeType())) { + update.setFinishResult("2"); + update.setTerminateReason(StringUtils.isNotBlank(change.getAfterContent()) ? change.getAfterContent() : "7"); + } else { + return; + } + baseMapper.updateById(update); + } + + private BigDecimal parseWorkload(String value) { + try { + return new BigDecimal(value); + } catch (NumberFormatException e) { + throw new ServiceException("变更后的预计工时必须为数字"); + } + } + + private Date parseDate(String value) { + Date date = DateUtils.parseDate(value); + if (date == null) { + throw new ServiceException("变更后的时间格式不正确"); + } + return date; + } +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpTempTaskChangeMapper.xml b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpTempTaskChangeMapper.xml new file mode 100644 index 00000000..d5a4dcfc --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpTempTaskChangeMapper.xml @@ -0,0 +1,296 @@ + + + + + + + + + + + + + + + + + + + + + + + insert into erp_temp_task_change( + tenant_id, + + temp_task_id, + + temp_task_code, + + change_type, + + change_reason, + + before_content, + + after_content, + + workload_effect, + + time_effect, + + scope_effect, + + change_user_id, + + change_user_name, + + approve_result, + + approver_id, + + approver_name, + + approve_comment, + + approve_time, + + flow_status, + + del_flag, + + create_dept, + + create_by, + + create_time, + + update_by, + + update_time + + ) + values + + ( + #{item.tenantId}, + + #{item.tempTaskId}, + + #{item.tempTaskCode}, + + #{item.changeType}, + + #{item.changeReason}, + + #{item.beforeContent}, + + #{item.afterContent}, + + #{item.workloadEffect}, + + #{item.timeEffect}, + + #{item.scopeEffect}, + + #{item.changeUserId}, + + #{item.changeUserName}, + + #{item.approveResult}, + + #{item.approverId}, + + #{item.approverName}, + + #{item.approveComment}, + + #{item.approveTime}, + + #{item.flowStatus}, + + #{item.delFlag}, + + #{item.createDept}, + + #{item.createBy}, + + #{item.createTime}, + + #{item.updateBy}, + + #{item.updateTime} + + ) + + + + + + + update erp_temp_task_change t + + + t.tenant_id = #{item.tenantId}, + + + t.temp_task_id = #{item.tempTaskId}, + + + t.temp_task_code = #{item.tempTaskCode}, + + + t.change_type = #{item.changeType}, + + + t.change_reason = #{item.changeReason}, + + + t.before_content = #{item.beforeContent}, + + + t.after_content = #{item.afterContent}, + + + t.workload_effect = #{item.workloadEffect}, + + + t.time_effect = #{item.timeEffect}, + + + t.scope_effect = #{item.scopeEffect}, + + + t.change_user_id = #{item.changeUserId}, + + + t.change_user_name = #{item.changeUserName}, + + + t.approve_result = #{item.approveResult}, + + + t.approver_id = #{item.approverId}, + + + t.approver_name = #{item.approverName}, + + + t.approve_comment = #{item.approveComment}, + + + t.approve_time = #{item.approveTime}, + + + t.flow_status = #{item.flowStatus}, + + + t.del_flag = #{item.delFlag}, + + + t.create_dept = #{item.createDept}, + + + t.create_by = #{item.createBy}, + + + t.create_time = #{item.createTime}, + + + t.update_by = #{item.updateBy}, + + + t.update_time = #{item.updateTime} + + + where t.change_id = #{item.changeId} + + + + + + delete from erp_temp_task_change t + + + AND ${ew.sqlSegment} + + + + + + + delete from erp_temp_task_change t + where t.change_id in + + #{id} + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpTempTaskMapper.xml b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpTempTaskMapper.xml new file mode 100644 index 00000000..f765fea8 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpTempTaskMapper.xml @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + + + + + + + + + insert into erp_temp_task( + tenant_id, + + temp_task_code, + + task_title, + + task_desc, + + priority, + + urgent_reason, + + require_time, + + confirm_finish_time, + + actual_start_time, + + actual_finish_time, + + project_id, + + project_code, + + project_name, + + pm_id, + + pm_name, + + contract_id, + + contract_code, + + requester_id, + + requester_name, + + request_dept_id, + + request_dept_name, + + dispatcher_id, + + dispatcher_name, + + software_leader_id, + + software_leader_name, + + assignee_id, + + assignee_name, + + estimate_workload, + + actual_workload, + + finish_result, + + terminate_reason, + + finish_remark, + + related_task_id, + + related_task_code, + + relate_reason, + + relate_remark, + + task_status, + + flow_status, + + cc_user_ids, + + oss_id, + + remark, + + del_flag, + + create_dept, + + create_by, + + create_time, + + update_by, + + update_time + + ) + values + + ( + #{item.tenantId}, + + #{item.tempTaskCode}, + + #{item.taskTitle}, + + #{item.taskDesc}, + + #{item.priority}, + + #{item.urgentReason}, + + #{item.requireTime}, + + #{item.confirmFinishTime}, + + #{item.actualStartTime}, + + #{item.actualFinishTime}, + + #{item.projectId}, + + #{item.projectCode}, + + #{item.projectName}, + + #{item.pmId}, + + #{item.pmName}, + + #{item.contractId}, + + #{item.contractCode}, + + #{item.requesterId}, + + #{item.requesterName}, + + #{item.requestDeptId}, + + #{item.requestDeptName}, + + #{item.dispatcherId}, + + #{item.dispatcherName}, + + #{item.softwareLeaderId}, + + #{item.softwareLeaderName}, + + #{item.assigneeId}, + + #{item.assigneeName}, + + #{item.estimateWorkload}, + + #{item.actualWorkload}, + + #{item.finishResult}, + + #{item.terminateReason}, + + #{item.finishRemark}, + + #{item.relatedTaskId}, + + #{item.relatedTaskCode}, + + #{item.relateReason}, + + #{item.relateRemark}, + + #{item.taskStatus}, + + #{item.flowStatus}, + + #{item.ccUserIds}, + + #{item.ossId}, + + #{item.remark}, + + #{item.delFlag}, + + #{item.createDept}, + + #{item.createBy}, + + #{item.createTime}, + + #{item.updateBy}, + + #{item.updateTime} + + ) + + + + + + + update erp_temp_task t + + + t.tenant_id = #{item.tenantId}, + + + t.temp_task_code = #{item.tempTaskCode}, + + + t.task_title = #{item.taskTitle}, + + + t.task_desc = #{item.taskDesc}, + + + t.priority = #{item.priority}, + + + t.urgent_reason = #{item.urgentReason}, + + + t.require_time = #{item.requireTime}, + + + t.confirm_finish_time = #{item.confirmFinishTime}, + + + t.actual_start_time = #{item.actualStartTime}, + + + t.actual_finish_time = #{item.actualFinishTime}, + + + t.project_id = #{item.projectId}, + + + t.project_code = #{item.projectCode}, + + + t.project_name = #{item.projectName}, + + + t.pm_id = #{item.pmId}, + + + t.pm_name = #{item.pmName}, + + + t.contract_id = #{item.contractId}, + + + t.contract_code = #{item.contractCode}, + + + t.requester_id = #{item.requesterId}, + + + t.requester_name = #{item.requesterName}, + + + t.request_dept_id = #{item.requestDeptId}, + + + t.request_dept_name = #{item.requestDeptName}, + + + t.dispatcher_id = #{item.dispatcherId}, + + + t.dispatcher_name = #{item.dispatcherName}, + + + t.software_leader_id = #{item.softwareLeaderId}, + + + t.software_leader_name = #{item.softwareLeaderName}, + + + t.assignee_id = #{item.assigneeId}, + + + t.assignee_name = #{item.assigneeName}, + + + t.estimate_workload = #{item.estimateWorkload}, + + + t.actual_workload = #{item.actualWorkload}, + + + t.finish_result = #{item.finishResult}, + + + t.terminate_reason = #{item.terminateReason}, + + + t.finish_remark = #{item.finishRemark}, + + + t.related_task_id = #{item.relatedTaskId}, + + + t.related_task_code = #{item.relatedTaskCode}, + + + t.relate_reason = #{item.relateReason}, + + + t.relate_remark = #{item.relateRemark}, + + + t.task_status = #{item.taskStatus}, + + + t.flow_status = #{item.flowStatus}, + + + t.cc_user_ids = #{item.ccUserIds}, + + + t.oss_id = #{item.ossId}, + + + t.remark = #{item.remark}, + + + t.del_flag = #{item.delFlag}, + + + t.create_dept = #{item.createDept}, + + + t.create_by = #{item.createBy}, + + + t.create_time = #{item.createTime}, + + + t.update_by = #{item.updateBy}, + + + t.update_time = #{item.updateTime} + + + where t.temp_task_id = #{item.tempTaskId} + + + + + + delete from erp_temp_task t + + + AND ${ew.sqlSegment} + + + + + + + delete from erp_temp_task t + where t.temp_task_id in + + #{id} + + + + + + + +