diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectPlanController.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectPlanController.java new file mode 100644 index 00000000..4e9b3c25 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectPlanController.java @@ -0,0 +1,130 @@ +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.ErpProjectPlanVo; +import org.dromara.oa.erp.domain.bo.ErpProjectPlanBo; +import org.dromara.oa.erp.service.IErpProjectPlanService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 项目计划 + * 前端访问路由地址为:/oa/erp/erpProjectPlan + * + * @author Yinq + * @date 2025-10-30 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/erp/erpProjectPlan") +public class ErpProjectPlanController extends BaseController { + + private final IErpProjectPlanService erpProjectPlanService; + + /** + * 查询项目计划列表 + */ + @SaCheckPermission("oa/erp:erpProjectPlan:list") + @GetMapping("/list") + public TableDataInfo list(ErpProjectPlanBo bo, PageQuery pageQuery) { + return erpProjectPlanService.queryPageList(bo, pageQuery); + } + + /** + * 导出项目计划列表 + */ + @SaCheckPermission("oa/erp:erpProjectPlan:export") + @Log(title = "项目计划", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(ErpProjectPlanBo bo, HttpServletResponse response) { + List list = erpProjectPlanService.queryList(bo); + ExcelUtil.exportExcel(list, "项目计划", ErpProjectPlanVo.class, response); + } + + /** + * 获取项目计划详细信息 + * + * @param projectPlanId 主键 + */ + @SaCheckPermission("oa/erp:erpProjectPlan:query") + @GetMapping("/{projectPlanId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable("projectPlanId") Long projectPlanId) { + return R.ok(erpProjectPlanService.queryById(projectPlanId)); + } + + /** + * 新增项目计划 + */ + @SaCheckPermission("oa/erp:erpProjectPlan:add") + @Log(title = "项目计划", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ErpProjectPlanBo bo) { + erpProjectPlanService.insertByBo(bo); + return R.ok(erpProjectPlanService.queryById(bo.getProjectPlanId())); + } + + /** + * 修改项目计划 + */ + @SaCheckPermission("oa/erp:erpProjectPlan:edit") + @Log(title = "项目计划", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ErpProjectPlanBo bo) { + return toAjax(erpProjectPlanService.updateByBo(bo)); + } + + /** + * 删除项目计划 + * + * @param projectPlanIds 主键串 + */ + @SaCheckPermission("oa/erp:erpProjectPlan:remove") + @Log(title = "项目计划", businessType = BusinessType.DELETE) + @DeleteMapping("/{projectPlanIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable("projectPlanIds") Long[] projectPlanIds) { + return toAjax(erpProjectPlanService.deleteWithValidByIds(List.of(projectPlanIds), true)); + } + + /** + * 下拉框查询项目计划列表 + */ + @GetMapping("/getErpProjectPlanList") + public R> getErpProjectPlanList(ErpProjectPlanBo bo) { + List list = erpProjectPlanService.queryList(bo); + return R.ok(list); + } + + /** + * 提交项目计划并发起流程 + * @param bo 项目计划 + * @return 项目计划 + */ + @SaCheckPermission("oa/erp:erpProjectPlan:add") + @Log(title = "项目计划", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/projectPlanSubmitAndFlowStart") + public R projectPlanSubmitAndFlowStart(@Validated(AddGroup.class) @RequestBody ErpProjectPlanBo bo) { + return R.ok(erpProjectPlanService.projectPlanSubmitAndFlowStart(bo)); + } + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectPlanStageController.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectPlanStageController.java new file mode 100644 index 00000000..cd1ac5e6 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectPlanStageController.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.ErpProjectPlanStageVo; +import org.dromara.oa.erp.domain.bo.ErpProjectPlanStageBo; +import org.dromara.oa.erp.service.IErpProjectPlanStageService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 项目计划阶段 + * 前端访问路由地址为:/oa/erp/erpProjectPlanStage + * + * @author Yinq + * @date 2025-10-30 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/erp/erpProjectPlanStage") +public class ErpProjectPlanStageController extends BaseController { + + private final IErpProjectPlanStageService erpProjectPlanStageService; + + /** + * 查询项目计划阶段列表 + */ + @SaCheckPermission("oa/erp:erpProjectPlanStage:list") + @GetMapping("/list") + public TableDataInfo list(ErpProjectPlanStageBo bo, PageQuery pageQuery) { + return erpProjectPlanStageService.queryPageList(bo, pageQuery); + } + + /** + * 导出项目计划阶段列表 + */ + @SaCheckPermission("oa/erp:erpProjectPlanStage:export") + @Log(title = "项目计划阶段", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(ErpProjectPlanStageBo bo, HttpServletResponse response) { + List list = erpProjectPlanStageService.queryList(bo); + ExcelUtil.exportExcel(list, "项目计划阶段", ErpProjectPlanStageVo.class, response); + } + + /** + * 获取项目计划阶段详细信息 + * + * @param planStageId 主键 + */ + @SaCheckPermission("oa/erp:erpProjectPlanStage:query") + @GetMapping("/{planStageId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable("planStageId") Long planStageId) { + return R.ok(erpProjectPlanStageService.queryById(planStageId)); + } + + /** + * 新增项目计划阶段 + */ + @SaCheckPermission("oa/erp:erpProjectPlanStage:add") + @Log(title = "项目计划阶段", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ErpProjectPlanStageBo bo) { + return toAjax(erpProjectPlanStageService.insertByBo(bo)); + } + + /** + * 修改项目计划阶段 + */ + @SaCheckPermission("oa/erp:erpProjectPlanStage:edit") + @Log(title = "项目计划阶段", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ErpProjectPlanStageBo bo) { + return toAjax(erpProjectPlanStageService.updateByBo(bo)); + } + + /** + * 删除项目计划阶段 + * + * @param planStageIds 主键串 + */ + @SaCheckPermission("oa/erp:erpProjectPlanStage:remove") + @Log(title = "项目计划阶段", businessType = BusinessType.DELETE) + @DeleteMapping("/{planStageIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable("planStageIds") Long[] planStageIds) { + return toAjax(erpProjectPlanStageService.deleteWithValidByIds(List.of(planStageIds), true)); + } + + /** + * 下拉框查询项目计划阶段列表 + */ + @GetMapping("/getErpProjectPlanStageList") + public R> getErpProjectPlanStageList(ErpProjectPlanStageBo bo) { + List list = erpProjectPlanStageService.queryList(bo); + return R.ok(list); + } + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectPlan.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectPlan.java new file mode 100644 index 00000000..27e3d0de --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectPlan.java @@ -0,0 +1,87 @@ +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.io.Serial; + +/** + * 项目计划对象 erp_project_plan + * + * @author Yinq + * @date 2025-10-30 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("erp_project_plan") +public class ErpProjectPlan extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 项目计划ID + */ + @TableId(value = "project_plan_id", type = IdType.ASSIGN_ID) + private Long projectPlanId; + + /** + * 项目ID + */ + private Long projectId; + + /** + * 项目经理 + */ + private Long managerId; + + /** + * 部门负责人 + */ + private Long chargeId; + + /** + * 付款方式 + */ + private String paymentMethod; + + /** + * 项目计划状态(1暂存 2审批中 3可用) + */ + private String projectPlanStatus; + + /** + * 流程状态 + */ + private String flowStatus; + + /** + * 排序号 + */ + private Long sortOrder; + + /** + * 合同ID(预留) + */ + private Long contractId; + + /** + * 备注 + */ + private String remark; + + /** + * 激活标识(1是 0否) + */ + private String activeFlag; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectPlanStage.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectPlanStage.java new file mode 100644 index 00000000..2a89b4a1 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectPlanStage.java @@ -0,0 +1,129 @@ +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_project_plan_stage + * + * @author Yinq + * @date 2025-10-30 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("erp_project_plan_stage") +public class ErpProjectPlanStage extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 计划阶段ID + */ + @TableId(value = "plan_stage_id", type = IdType.AUTO) + private Long planStageId; + + /** + * 项目ID + */ + private Long projectId; + + /** + * 项目计划ID + */ + private Long projectPlanId; + + /** + * 项目阶段 + */ + private String projectPhases; + + /** + * 计划开始时间 + */ + private Date planStartTime; + + /** + * 计划结束时间 + */ + private Date planEndTime; + + /** + * 回款阶段 + */ + private String collectionStage; + + /** + * 预计回款比例(%) + */ + private Long repaymentRate; + + /** + * 预计回款金额 + */ + private Long repaymentAmount; + + /** + * 预计回款时间 + */ + private Date repaymentTime; + + /** + * 回款延期天数 + */ + private Long delayDay; + + /** + * 应收款日期 + */ + private Date receivableDate; + + /** + * 原因说明 + */ + private String reasonsExplanation; + + /** + * 进度备注 + */ + private String scheduleRemark; + + /** + * 实际开始时间 + */ + private Date realStartTime; + + /** + * 实际结束时间 + */ + private Date realEndTime; + + /** + * 排序号 + */ + private Long sortOrder; + + /** + * 备注 + */ + private String remark; + + /** + * 激活标识(1是 0否) + */ + private String activeFlag; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectPlanBo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectPlanBo.java new file mode 100644 index 00000000..04bd18bb --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectPlanBo.java @@ -0,0 +1,144 @@ +package org.dromara.oa.erp.domain.bo; + +import cn.hutool.core.util.ObjectUtil; +import org.dromara.oa.erp.domain.ErpProjectPlan; +import org.dromara.oa.erp.domain.ErpProjectPlanStage; +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 org.dromara.workflow.api.domain.RemoteFlowInstanceBizExt; +// import org.dromara.workflow.api.domain.RemoteFlowInstanceBizExt; + +import java.util.*; + +/** + * 项目计划业务对象 erp_project_plan + * + * @author Yinq + * @date 2025-10-30 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ErpProjectPlan.class, reverseConvertGenerate = false) +public class ErpProjectPlanBo extends BaseEntity { + + /** + * 项目计划ID + */ + @NotNull(message = "项目计划ID不能为空", groups = { EditGroup.class }) + private Long projectPlanId; + + /** + * 项目ID + */ + private Long projectId; + + /** + * 项目经理 + */ + private Long managerId; + + /** + * 部门负责人 + */ + private Long chargeId; + + /** + * 付款方式 + */ + private String paymentMethod; + + /** + * 项目计划状态(1暂存 2审批中 3可用) + */ + private String projectPlanStatus; + + /** + * 流程状态 + */ + private String flowStatus; + + /** + * 排序号 + */ + private Long sortOrder; + + /** + * 合同ID(预留) + */ + private Long contractId; + + /** + * 备注 + */ + private String remark; + + /** + * 激活标识(1是 0否) + */ + private String activeFlag; + + /** + * 项目计划阶段列表 + */ + private List planStageList; + + /** + * 项目名称 + */ + private String projectName; + + /** + * 项目经理名称 + */ + private String managerName; + + /** + * 部门负责人名称 + */ + private String chargeName; + + /** + * 合同名称 + */ + private String contractName; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 办理人(可不填 用于覆盖当前节点办理人) + */ + private String handler; + + /** + * 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}} + */ + private Map variables; + + /** + * 流程业务扩展信息 + */ + private RemoteFlowInstanceBizExt bizExt; + + public Map getVariables() { + if (variables == null) { + return 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/ErpProjectPlanStageBo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectPlanStageBo.java new file mode 100644 index 00000000..687f4c7f --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectPlanStageBo.java @@ -0,0 +1,122 @@ +package org.dromara.oa.erp.domain.bo; + +import org.dromara.oa.erp.domain.ErpProjectPlanStage; +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_project_plan_stage + * + * @author Yinq + * @date 2025-10-30 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ErpProjectPlanStage.class, reverseConvertGenerate = false) +public class ErpProjectPlanStageBo extends BaseEntity { + + /** + * 计划阶段ID + */ + @NotNull(message = "计划阶段ID不能为空", groups = { EditGroup.class }) + private Long planStageId; + + /** + * 项目ID + */ + private Long projectId; + + /** + * 项目计划ID + */ + private Long projectPlanId; + + /** + * 项目阶段 + */ + private String projectPhases; + + /** + * 计划开始时间 + */ + private Date planStartTime; + + /** + * 计划结束时间 + */ + private Date planEndTime; + + /** + * 回款阶段 + */ + private String collectionStage; + + /** + * 预计回款比例(%) + */ + private Long repaymentRate; + + /** + * 预计回款金额 + */ + private Long repaymentAmount; + + /** + * 预计回款时间 + */ + private Date repaymentTime; + + /** + * 回款延期天数 + */ + private Long delayDay; + + /** + * 应收款日期 + */ + private Date receivableDate; + + /** + * 原因说明 + */ + private String reasonsExplanation; + + /** + * 进度备注 + */ + private String scheduleRemark; + + /** + * 实际开始时间 + */ + private Date realStartTime; + + /** + * 实际结束时间 + */ + private Date realEndTime; + + /** + * 排序号 + */ + private Long sortOrder; + + /** + * 备注 + */ + private String remark; + + /** + * 激活标识(1是 0否) + */ + private String activeFlag; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectPlanStageVo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectPlanStageVo.java new file mode 100644 index 00000000..8c915889 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectPlanStageVo.java @@ -0,0 +1,151 @@ +package org.dromara.oa.erp.domain.vo; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.dromara.oa.erp.domain.ErpProjectPlanStage; +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_project_plan_stage + * + * @author Yinq + * @date 2025-10-30 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ErpProjectPlanStage.class) +public class ErpProjectPlanStageVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 计划阶段ID + */ + @ExcelProperty(value = "计划阶段ID") + private Long planStageId; + + /** + * 项目ID + */ + @ExcelProperty(value = "项目ID") + private Long projectId; + + /** + * 项目计划ID + */ + @ExcelProperty(value = "项目计划ID") + private Long projectPlanId; + + /** + * 项目阶段 + */ + @ExcelProperty(value = "项目阶段") + @ExcelDictFormat(dictType = " project_phases") + private String projectPhases; + + /** + * 计划开始时间 + */ + @ExcelProperty(value = "计划开始时间") + private Date planStartTime; + + /** + * 计划结束时间 + */ + @ExcelProperty(value = "计划结束时间") + private Date planEndTime; + + /** + * 回款阶段 + */ + @ExcelProperty(value = "回款阶段") + @ExcelDictFormat(dictType = " collection_stage") + private String collectionStage; + + /** + * 预计回款比例(%) + */ + @ExcelProperty(value = "预计回款比例(%)") + private Long repaymentRate; + + /** + * 预计回款金额 + */ + @ExcelProperty(value = "预计回款金额") + private Long repaymentAmount; + + /** + * 预计回款时间 + */ + @ExcelProperty(value = "预计回款时间") + private Date repaymentTime; + + /** + * 回款延期天数 + */ + @ExcelProperty(value = "回款延期天数") + private Long delayDay; + + /** + * 应收款日期 + */ + @ExcelProperty(value = "应收款日期") + private Date receivableDate; + + /** + * 原因说明 + */ + @ExcelProperty(value = "原因说明") + private String reasonsExplanation; + + /** + * 进度备注 + */ + @ExcelProperty(value = "进度备注") + private String scheduleRemark; + + /** + * 实际开始时间 + */ + @ExcelProperty(value = "实际开始时间") + private Date realStartTime; + + /** + * 实际结束时间 + */ + @ExcelProperty(value = "实际结束时间") + private Date realEndTime; + + /** + * 排序号 + */ + @ExcelProperty(value = "排序号") + private Long sortOrder; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 激活标识(1是 0否) + */ + @ExcelProperty(value = "激活标识", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "active_flag") + private String activeFlag; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectPlanVo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectPlanVo.java new file mode 100644 index 00000000..57ecddb4 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectPlanVo.java @@ -0,0 +1,129 @@ +package org.dromara.oa.erp.domain.vo; + +import org.dromara.oa.erp.domain.ErpProjectPlan; +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; +import java.util.List; + + + +/** + * 项目计划视图对象 erp_project_plan + * + * @author Yinq + * @date 2025-10-30 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ErpProjectPlan.class) +public class ErpProjectPlanVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 项目计划ID + */ + @ExcelProperty(value = "项目计划ID") + private Long projectPlanId; + + /** + * 项目ID + */ + @ExcelProperty(value = "项目ID") + private Long projectId; + + /** + * 项目经理 + */ + @ExcelProperty(value = "项目经理") + private Long managerId; + + /** + * 部门负责人 + */ + @ExcelProperty(value = "部门负责人") + private Long chargeId; + + /** + * 付款方式 + */ + @ExcelProperty(value = "付款方式") + private String paymentMethod; + + /** + * 项目计划状态(1暂存 2审批中 3可用) + */ + @ExcelProperty(value = "项目计划状态(1暂存 2审批中 3可用)", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "project_plan_status") + private String projectPlanStatus; + + /** + * 流程状态 + */ + @ExcelProperty(value = "流程状态") + private String flowStatus; + + /** + * 排序号 + */ + @ExcelProperty(value = "排序号") + private Long sortOrder; + + /** + * 合同ID(预留) + */ + @ExcelProperty(value = "合同ID(预留)") + private Long contractId; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 激活标识(1是 0否) + */ + @ExcelProperty(value = "激活标识", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "active_flag") + private String activeFlag; + + /** + * 项目计划阶段列表 + */ + private List planStageList; + + /** + * 项目名称 + */ + @ExcelProperty(value = "项目名称") + private String projectName; + + /** + * 项目经理名称 + */ + @ExcelProperty(value = "项目经理名称") + private String managerName; + + /** + * 部门负责人名称 + */ + @ExcelProperty(value = "部门负责人名称") + private String chargeName; + + /** + * 合同名称 + */ + @ExcelProperty(value = "合同名称") + private String contractName; + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectPlanMapper.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectPlanMapper.java new file mode 100644 index 00000000..a850b4de --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectPlanMapper.java @@ -0,0 +1,113 @@ +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.ErpProjectPlan; +import org.dromara.oa.erp.domain.vo.ErpProjectPlanVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 项目计划Mapper接口 + * + * @author Yinq + * @date 2025-10-30 + */ +public interface ErpProjectPlanMapper extends BaseMapperPlus { + + /** + * 查询项目计划列表 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 项目计划集合 + */ + public Page selectCustomErpProjectPlanVoList(@Param("page") Page page, @Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 查询项目计划列表 + * + * @param queryWrapper 条件 + * @return 项目计划集合 + */ + public List selectCustomErpProjectPlanVoList(@Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 根据ID查询项目计划详情 + * + * @param projectPlanId 主键ID + * @return 项目计划对象 + */ + ErpProjectPlanVo selectCustomErpProjectPlanVoById(@Param("projectPlanId") Long projectPlanId); + + /** + * 根据ID列表批量查询项目计划 + * + * @param ids ID集合 + * @return 项目计划集合 + */ + List selectCustomErpProjectPlanVoByIds(@Param("ids") Collection ids); + + /** + * 统计项目计划记录数 + * + * @param queryWrapper 查询条件 + * @return 记录总数 + */ + Long countCustomErpProjectPlan(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 分页查询项目计划(自定义条件) + * + * @param page 分页对象 + * @param queryWrapper 查询条件 + * @return 分页结果 + */ + Page selectCustomErpProjectPlanVoPage(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 批量插入项目计划 + * + * @param list 项目计划对象集合 + * @return 影响行数 + */ + int batchInsertErpProjectPlan(@Param("list") List list); + + /** + * 批量更新项目计划 + * + * @param list 项目计划对象集合 + * @return 影响行数 + */ + int batchUpdateErpProjectPlan(@Param("list") List list); + + /** + * 根据自定义条件删除项目计划 + * + * @param queryWrapper 删除条件 + * @return 影响行数 + */ + int deleteCustomErpProjectPlan(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据ID列表批量删除项目计划 + * + * @param ids ID集合 + * @return 影响行数 + */ + int deleteCustomErpProjectPlanByIds(@Param("ids") Collection ids); + + /** + * 检查项目计划是否存在 + * + * @param queryWrapper 查询条件 + * @return 是否存在 + */ + Boolean existsErpProjectPlan(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectPlanStageMapper.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectPlanStageMapper.java new file mode 100644 index 00000000..f5ae02cf --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectPlanStageMapper.java @@ -0,0 +1,113 @@ +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.ErpProjectPlanStage; +import org.dromara.oa.erp.domain.vo.ErpProjectPlanStageVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 项目计划阶段Mapper接口 + * + * @author Yinq + * @date 2025-10-30 + */ +public interface ErpProjectPlanStageMapper extends BaseMapperPlus { + + /** + * 查询项目计划阶段列表 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 项目计划阶段集合 + */ + public Page selectCustomErpProjectPlanStageVoList(@Param("page") Page page, @Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 查询项目计划阶段列表 + * + * @param queryWrapper 条件 + * @return 项目计划阶段集合 + */ + public List selectCustomErpProjectPlanStageVoList(@Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 根据ID查询项目计划阶段详情 + * + * @param planStageId 主键ID + * @return 项目计划阶段对象 + */ + ErpProjectPlanStageVo selectCustomErpProjectPlanStageVoById(@Param("planStageId") Long planStageId); + + /** + * 根据ID列表批量查询项目计划阶段 + * + * @param ids ID集合 + * @return 项目计划阶段集合 + */ + List selectCustomErpProjectPlanStageVoByIds(@Param("ids") Collection ids); + + /** + * 统计项目计划阶段记录数 + * + * @param queryWrapper 查询条件 + * @return 记录总数 + */ + Long countCustomErpProjectPlanStage(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 分页查询项目计划阶段(自定义条件) + * + * @param page 分页对象 + * @param queryWrapper 查询条件 + * @return 分页结果 + */ + Page selectCustomErpProjectPlanStageVoPage(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 批量插入项目计划阶段 + * + * @param list 项目计划阶段对象集合 + * @return 影响行数 + */ + int batchInsertErpProjectPlanStage(@Param("list") List list); + + /** + * 批量更新项目计划阶段 + * + * @param list 项目计划阶段对象集合 + * @return 影响行数 + */ + int batchUpdateErpProjectPlanStage(@Param("list") List list); + + /** + * 根据自定义条件删除项目计划阶段 + * + * @param queryWrapper 删除条件 + * @return 影响行数 + */ + int deleteCustomErpProjectPlanStage(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据ID列表批量删除项目计划阶段 + * + * @param ids ID集合 + * @return 影响行数 + */ + int deleteCustomErpProjectPlanStageByIds(@Param("ids") Collection ids); + + /** + * 检查项目计划阶段是否存在 + * + * @param queryWrapper 查询条件 + * @return 是否存在 + */ + Boolean existsErpProjectPlanStage(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectPlanService.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectPlanService.java new file mode 100644 index 00000000..319ae2ba --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectPlanService.java @@ -0,0 +1,76 @@ +package org.dromara.oa.erp.service; + +import org.dromara.oa.erp.domain.ErpProjectPlan; +import org.dromara.oa.erp.domain.vo.ErpProjectPlanVo; +import org.dromara.oa.erp.domain.bo.ErpProjectPlanBo; +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 Yinq + * @date 2025-10-30 + */ +public interface IErpProjectPlanService { + + /** + * 查询项目计划 + * + * @param projectPlanId 主键 + * @return 项目计划 + */ + ErpProjectPlanVo queryById(Long projectPlanId); + + /** + * 分页查询项目计划列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 项目计划分页列表 + */ + TableDataInfo queryPageList(ErpProjectPlanBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的项目计划列表 + * + * @param bo 查询条件 + * @return 项目计划列表 + */ + List queryList(ErpProjectPlanBo bo); + + /** + * 新增项目计划 + * + * @param bo 项目计划 + * @return 是否新增成功 + */ + Boolean insertByBo(ErpProjectPlanBo bo); + + /** + * 修改项目计划 + * + * @param bo 项目计划 + * @return 是否修改成功 + */ + Boolean updateByBo(ErpProjectPlanBo bo); + + /** + * 校验并批量删除项目计划信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 提交项目计划并发起流程 + * @param bo 项目计划 + * @return 项目计划 + */ + ErpProjectPlanVo projectPlanSubmitAndFlowStart(ErpProjectPlanBo bo); +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectPlanStageService.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectPlanStageService.java new file mode 100644 index 00000000..08f598d1 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectPlanStageService.java @@ -0,0 +1,69 @@ +package org.dromara.oa.erp.service; + +import org.dromara.oa.erp.domain.ErpProjectPlanStage; +import org.dromara.oa.erp.domain.vo.ErpProjectPlanStageVo; +import org.dromara.oa.erp.domain.bo.ErpProjectPlanStageBo; +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 Yinq + * @date 2025-10-30 + */ +public interface IErpProjectPlanStageService { + + /** + * 查询项目计划阶段 + * + * @param planStageId 主键 + * @return 项目计划阶段 + */ + ErpProjectPlanStageVo queryById(Long planStageId); + + /** + * 分页查询项目计划阶段列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 项目计划阶段分页列表 + */ + TableDataInfo queryPageList(ErpProjectPlanStageBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的项目计划阶段列表 + * + * @param bo 查询条件 + * @return 项目计划阶段列表 + */ + List queryList(ErpProjectPlanStageBo bo); + + /** + * 新增项目计划阶段 + * + * @param bo 项目计划阶段 + * @return 是否新增成功 + */ + Boolean insertByBo(ErpProjectPlanStageBo bo); + + /** + * 修改项目计划阶段 + * + * @param bo 项目计划阶段 + * @return 是否修改成功 + */ + Boolean updateByBo(ErpProjectPlanStageBo 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/ErpProjectPlanServiceImpl.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectPlanServiceImpl.java new file mode 100644 index 00000000..70aa5826 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectPlanServiceImpl.java @@ -0,0 +1,322 @@ +package org.dromara.oa.erp.service.impl; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.map.MapUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.dubbo.config.annotation.DubboReference; +import org.apache.seata.spring.annotation.GlobalTransactional; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.enums.OAStatusEnum; +import org.dromara.common.core.exception.ServiceException; +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.dromara.common.tenant.helper.TenantHelper; +import org.dromara.oa.erp.domain.ErpProjectInfo; +import org.dromara.oa.erp.domain.ErpProjectPlanStage; +import org.dromara.oa.erp.domain.vo.ErpProjectPlanStageVo; +import org.dromara.oa.erp.mapper.ErpProjectPlanStageMapper; +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.dromara.common.satoken.utils.LoginHelper; +import org.springframework.stereotype.Service; +import org.dromara.oa.erp.domain.bo.ErpProjectPlanBo; +import org.dromara.oa.erp.domain.vo.ErpProjectPlanVo; +import org.dromara.oa.erp.domain.ErpProjectPlan; +import org.dromara.oa.erp.mapper.ErpProjectPlanMapper; +import org.dromara.oa.erp.service.IErpProjectPlanService; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 项目计划Service业务层处理 + * + * @author Yinq + * @date 2025-10-30 + */ +@RequiredArgsConstructor +@Service +@Slf4j +public class ErpProjectPlanServiceImpl implements IErpProjectPlanService { + + private final ErpProjectPlanMapper baseMapper; + + private final ErpProjectPlanStageMapper planStageMapper; + + @DubboReference(timeout = 30000) + private RemoteWorkflowService remoteWorkflowService; + + /** + * 查询项目计划 + * + * @param projectPlanId 主键 + * @return 项目计划 + */ + @Override + public ErpProjectPlanVo queryById(Long projectPlanId){ + // 使用自定义方法查询,包含关联数据 + ErpProjectPlanVo projectPlanVo = baseMapper.selectCustomErpProjectPlanVoById(projectPlanId); + // 查询项目计划阶段列表 + MPJLambdaWrapper lqw = JoinWrappers.lambda(ErpProjectPlanStage.class) + .selectAll(ErpProjectPlanStage.class) + .eq("t.del_flag", "0") + .eq(projectPlanId != null, ErpProjectPlanStage::getProjectPlanId, projectPlanId); + List planStageList = planStageMapper.selectVoList(lqw); + projectPlanVo.setPlanStageList(planStageList); + return projectPlanVo; + } + + /** + * 分页查询项目计划列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 项目计划分页列表 + */ + @Override + public TableDataInfo queryPageList(ErpProjectPlanBo bo, PageQuery pageQuery) { + MPJLambdaWrapper lqw = buildQueryWrapper(bo); + // 使用自定义分页查询方法获取包含关联数据的结果 + Page result = baseMapper.selectCustomErpProjectPlanVoList(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的项目计划列表 + * + * @param bo 查询条件 + * @return 项目计划列表 + */ + @Override + public List queryList(ErpProjectPlanBo bo) { + MPJLambdaWrapper lqw = buildQueryWrapper(bo); + // 使用自定义查询方法获取包含关联数据的列表 + return baseMapper.selectCustomErpProjectPlanVoList(lqw); + } + + private MPJLambdaWrapper buildQueryWrapper(ErpProjectPlanBo bo) { + Map params = bo.getParams(); + MPJLambdaWrapper lqw = JoinWrappers.lambda(ErpProjectPlan.class) + .selectAll(ErpProjectPlan.class) + .eq(ErpProjectPlan::getDelFlag, "0") + // 关联项目信息 + .select(ErpProjectInfo::getProjectName) + .leftJoin(ErpProjectInfo.class,ErpProjectInfo::getProjectId, ErpProjectPlan::getProjectId) + .eq(bo.getProjectId() != null, ErpProjectPlan::getProjectId, bo.getProjectId()) + .eq(bo.getManagerId() != null, ErpProjectPlan::getManagerId, bo.getManagerId()) + .eq(bo.getChargeId() != null, ErpProjectPlan::getChargeId, bo.getChargeId()) + .eq(StringUtils.isNotBlank(bo.getPaymentMethod()), ErpProjectPlan::getPaymentMethod, bo.getPaymentMethod()) + .eq(StringUtils.isNotBlank(bo.getProjectPlanStatus()), ErpProjectPlan::getProjectPlanStatus, bo.getProjectPlanStatus()) + .eq(StringUtils.isNotBlank(bo.getFlowStatus()), ErpProjectPlan::getFlowStatus, bo.getFlowStatus()) + .eq(bo.getSortOrder() != null, ErpProjectPlan::getSortOrder, bo.getSortOrder()) + .eq(bo.getContractId() != null, ErpProjectPlan::getContractId, bo.getContractId()) + .eq(StringUtils.isNotBlank(bo.getActiveFlag()), ErpProjectPlan::getActiveFlag, bo.getActiveFlag()); + return lqw; + } + + /** + * 新增项目计划 + * + * @param bo 项目计划 + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByBo(ErpProjectPlanBo bo) { + ErpProjectPlan add = MapstructUtils.convert(bo, ErpProjectPlan.class); + validEntityBeforeSave(add); + // 权限校验:只有项目经理才能提交 + validateProjectManager(bo.getManagerId()); + List planStageList = bo.getPlanStageList(); + boolean flag = baseMapper.insert(add) > 0; + if (flag && planStageList != null && !planStageList.isEmpty()) { + bo.setProjectPlanId(add.getProjectPlanId()); + for (ErpProjectPlanStage planStage : planStageList) { + planStage.setProjectPlanId(add.getProjectPlanId()); + planStage.setProjectId(add.getProjectId()); + planStageMapper.insert(planStage); + } + } + return flag; + } + + /** + * 修改项目计划 + * + * @param bo 项目计划 + * @return 是否修改成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(ErpProjectPlanBo bo) { + // 获取原有数据 + ErpProjectPlan existingPlan = baseMapper.selectById(bo.getProjectPlanId()); + if (existingPlan == null) { + throw new ServiceException("项目计划不存在"); + } + + // 权限校验:只有项目经理才能修改 + validateProjectManager(existingPlan.getManagerId()); + + // 如果不是草稿状态,只允许更新阶段的delayDay和scheduleRemark + if (!"1".equals(existingPlan.getProjectPlanStatus())) { + // 非草稿状态,只更新阶段的特定字段 + List planStageList = bo.getPlanStageList(); + if (planStageList != null && !planStageList.isEmpty()) { + for (ErpProjectPlanStage newStage : planStageList) { + if (newStage.getPlanStageId() != null) { + // 只更新delayDay、scheduleRemark和receivableDate + ErpProjectPlanStage existingStage = planStageMapper.selectById(newStage.getPlanStageId()); + if (existingStage != null) { + existingStage.setDelayDay(newStage.getDelayDay()); + existingStage.setScheduleRemark(newStage.getScheduleRemark()); + existingStage.setReceivableDate(newStage.getReceivableDate()); + planStageMapper.updateById(existingStage); + } + } + } + } + // 不更新主表数据 + return true; + } + + // 草稿状态,允许全面更新 + ErpProjectPlan update = MapstructUtils.convert(bo, ErpProjectPlan.class); + validEntityBeforeSave(update); + List planStageList = bo.getPlanStageList(); + MPJLambdaWrapper lqwRecord = JoinWrappers.lambda(ErpProjectPlanStage.class); + lqwRecord.eq(ErpProjectPlanStage::getProjectPlanId, bo.getProjectPlanId()); + List planStageOldList = planStageMapper.selectList(lqwRecord); + // 如果计划阶段列表不为空且不为空列表,则进行处理 + if (planStageList != null && !planStageList.isEmpty()) { + // 遍历计划阶段列表,设置项目ID并插入或更新数据库记录 + for (ErpProjectPlanStage planStage : planStageList) { + planStage.setProjectId(update.getProjectId()); + planStageMapper.insertOrUpdate(planStage); + } + + // 收集当前计划阶段列表中已存在的计划阶段ID集合 + Set existingPlanStageIds = planStageList.stream() + .map(ErpProjectPlanStage::getPlanStageId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + // 从旧的计划阶段列表中筛选出需要删除的记录(即不在当前列表中的记录) + List filterPlanStageIds = planStageOldList.stream() + .filter(stage -> !existingPlanStageIds.contains(stage.getPlanStageId())) + .toList(); + + // 删除需要移除的计划阶段记录 + for (ErpProjectPlanStage filterPlanStageId : filterPlanStageIds) { + planStageMapper.deleteById(filterPlanStageId.getPlanStageId()); + } + } + + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(ErpProjectPlan entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验项目经理权限:只有项目经理才能提交项目计划 + * + * @param managerId 项目经理ID + */ + private void validateProjectManager(Long managerId) { + // 超级管理员跳过校验 + if (LoginHelper.isSuperAdmin()) { + return; + } + // 普通用户判断当前用户ID是否等于项目经理ID + Long currentUserId = LoginHelper.getUserId(); + if (!currentUserId.equals(managerId)) { + throw new ServiceException("只有项目经理才能提交项目计划"); + } + } + + /** + * 校验并批量删除项目计划信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 提交项目计划并发起流程 + * + * @param bo 项目计划 + * @return 项目计划 + */ + @Override + @GlobalTransactional(rollbackFor = Exception.class) + public ErpProjectPlanVo projectPlanSubmitAndFlowStart(ErpProjectPlanBo bo) { + ErpProjectPlan add = MapstructUtils.convert(bo, ErpProjectPlan.class); + validEntityBeforeSave(add); + // 权限校验:只有项目经理才能提交 + validateProjectManager(bo.getManagerId()); + if (StringUtils.isNull(bo.getProjectPlanId())) { + this.insertByBo(bo); + } else { + this.updateByBo(bo); + } + // 后端发起需要忽略权限 + bo.getVariables().put("ignore", true); + RemoteStartProcess startProcess = new RemoteStartProcess(); + startProcess.setBusinessId(bo.getProjectPlanId().toString()); + startProcess.setFlowCode(bo.getFlowCode()); + startProcess.setVariables(bo.getVariables()); + startProcess.setBizExt(bo.getBizExt()); + bo.getBizExt().setBusinessId(startProcess.getBusinessId()); + boolean flagOne = remoteWorkflowService.startCompleteTask(startProcess); + if (!flagOne) { + throw new ServiceException("流程发起异常"); + } + return MapstructUtils.convert(add, ErpProjectPlanVo.class); + } + + /** + * 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成等) + * + * @param processEvent 参数 + */ + @EventListener(condition = "#processEvent.flowCode =='OAPS'") + public void processHandler(ProcessEvent processEvent) { + TenantHelper.dynamic(processEvent.getTenantId(), () -> { + log.info("当前任务执行了{}", processEvent.toString()); + ErpProjectPlan projectPlan = baseMapper.selectById(Convert.toLong(processEvent.getBusinessId())); + projectPlan.setFlowStatus(processEvent.getStatus()); + Map params = processEvent.getParams(); + if (MapUtil.isNotEmpty(params)) { + // 办理人 + String handler = Convert.toStr(params.get("handler")); + } + if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.FINISH.getStatus())) { + projectPlan.setProjectPlanStatus(OAStatusEnum.COMPLETED.getStatus()); + } + baseMapper.updateById(projectPlan); + }); + } +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectPlanStageServiceImpl.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectPlanStageServiceImpl.java new file mode 100644 index 00000000..07da663f --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectPlanStageServiceImpl.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.ErpProjectPlanStageBo; +import org.dromara.oa.erp.domain.vo.ErpProjectPlanStageVo; +import org.dromara.oa.erp.domain.ErpProjectPlanStage; +import org.dromara.oa.erp.mapper.ErpProjectPlanStageMapper; +import org.dromara.oa.erp.service.IErpProjectPlanStageService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 项目计划阶段Service业务层处理 + * + * @author Yinq + * @date 2025-10-30 + */ +@RequiredArgsConstructor +@Service +public class ErpProjectPlanStageServiceImpl implements IErpProjectPlanStageService { + + private final ErpProjectPlanStageMapper baseMapper; + + /** + * 查询项目计划阶段 + * + * @param planStageId 主键 + * @return 项目计划阶段 + */ + @Override + public ErpProjectPlanStageVo queryById(Long planStageId){ + return baseMapper.selectVoById(planStageId); + } + + /** + * 分页查询项目计划阶段列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 项目计划阶段分页列表 + */ + @Override + public TableDataInfo queryPageList(ErpProjectPlanStageBo bo, PageQuery pageQuery) { + MPJLambdaWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的项目计划阶段列表 + * + * @param bo 查询条件 + * @return 项目计划阶段列表 + */ + @Override + public List queryList(ErpProjectPlanStageBo bo) { + MPJLambdaWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private MPJLambdaWrapper buildQueryWrapper(ErpProjectPlanStageBo bo) { + Map params = bo.getParams(); + MPJLambdaWrapper lqw = JoinWrappers.lambda(ErpProjectPlanStage.class) + .selectAll(ErpProjectPlanStage.class) + .eq(ErpProjectPlanStage::getDelFlag, "0") + .eq(bo.getProjectId() != null, ErpProjectPlanStage::getProjectId, bo.getProjectId()) + .eq(bo.getProjectPlanId() != null, ErpProjectPlanStage::getProjectPlanId, bo.getProjectPlanId()) + .eq(StringUtils.isNotBlank(bo.getProjectPhases()), ErpProjectPlanStage::getProjectPhases, bo.getProjectPhases()) + .eq(bo.getPlanStartTime() != null, ErpProjectPlanStage::getPlanStartTime, bo.getPlanStartTime()) + .eq(bo.getPlanEndTime() != null, ErpProjectPlanStage::getPlanEndTime, bo.getPlanEndTime()) + .eq(StringUtils.isNotBlank(bo.getCollectionStage()), ErpProjectPlanStage::getCollectionStage, bo.getCollectionStage()) + .eq(bo.getRepaymentRate() != null, ErpProjectPlanStage::getRepaymentRate, bo.getRepaymentRate()) + .eq(bo.getRepaymentAmount() != null, ErpProjectPlanStage::getRepaymentAmount, bo.getRepaymentAmount()) + .eq(bo.getRepaymentTime() != null, ErpProjectPlanStage::getRepaymentTime, bo.getRepaymentTime()) + .eq(bo.getDelayDay() != null, ErpProjectPlanStage::getDelayDay, bo.getDelayDay()) + .eq(bo.getReceivableDate() != null, ErpProjectPlanStage::getReceivableDate, bo.getReceivableDate()) + .eq(StringUtils.isNotBlank(bo.getReasonsExplanation()), ErpProjectPlanStage::getReasonsExplanation, bo.getReasonsExplanation()) + .eq(StringUtils.isNotBlank(bo.getScheduleRemark()), ErpProjectPlanStage::getScheduleRemark, bo.getScheduleRemark()) + .eq(bo.getRealStartTime() != null, ErpProjectPlanStage::getRealStartTime, bo.getRealStartTime()) + .eq(bo.getRealEndTime() != null, ErpProjectPlanStage::getRealEndTime, bo.getRealEndTime()) + .eq(bo.getSortOrder() != null, ErpProjectPlanStage::getSortOrder, bo.getSortOrder()) + .eq(StringUtils.isNotBlank(bo.getActiveFlag()), ErpProjectPlanStage::getActiveFlag, bo.getActiveFlag()) +; + return lqw; + } + + /** + * 新增项目计划阶段 + * + * @param bo 项目计划阶段 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(ErpProjectPlanStageBo bo) { + ErpProjectPlanStage add = MapstructUtils.convert(bo, ErpProjectPlanStage.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setPlanStageId(add.getPlanStageId()); + } + return flag; + } + + /** + * 修改项目计划阶段 + * + * @param bo 项目计划阶段 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(ErpProjectPlanStageBo bo) { + ErpProjectPlanStage update = MapstructUtils.convert(bo, ErpProjectPlanStage.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(ErpProjectPlanStage 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/resources/mapper/oa/erp/ErpProjectPlanMapper.xml b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectPlanMapper.xml new file mode 100644 index 00000000..3e86bb18 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectPlanMapper.xml @@ -0,0 +1,307 @@ + + + + + + + + + + + + + + + + + + + + + + + insert into erp_project_plan( + tenant_id, + + project_id, + + manager_id, + + charge_id, + + payment_method, + + project_plan_status, + + flow_status, + + sort_order, + + contract_id, + + remark, + + active_flag, + + del_flag, + + create_dept, + + create_by, + + create_time, + + update_by, + + update_time + + ) + values + + ( + #{item.tenantId}, + + #{item.projectId}, + + #{item.managerId}, + + #{item.chargeId}, + + #{item.paymentMethod}, + + #{item.projectPlanStatus}, + + #{item.flowStatus}, + + #{item.sortOrder}, + + #{item.contractId}, + + #{item.remark}, + + #{item.activeFlag}, + + #{item.delFlag}, + + #{item.createDept}, + + #{item.createBy}, + + #{item.createTime}, + + #{item.updateBy}, + + #{item.updateTime} + + ) + + + + + + + update erp_project_plan + + + tenant_id = #{item.tenantId}, + + + project_id = #{item.projectId}, + + + manager_id = #{item.managerId}, + + + charge_id = #{item.chargeId}, + + + payment_method = #{item.paymentMethod}, + + + project_plan_status = #{item.projectPlanStatus}, + + + flow_status = #{item.flowStatus}, + + + sort_order = #{item.sortOrder}, + + + contract_id = #{item.contractId}, + + + remark = #{item.remark}, + + + active_flag = #{item.activeFlag}, + + + del_flag = #{item.delFlag}, + + + create_dept = #{item.createDept}, + + + create_by = #{item.createBy}, + + + create_time = #{item.createTime}, + + + update_by = #{item.updateBy}, + + + update_time = #{item.updateTime} + + + where project_plan_id = #{item.projectPlanId} + + + + + + delete from erp_project_plan + ${ew.getCustomSqlSegment} + + + + + delete from erp_project_plan + where project_plan_id in + + #{id} + + + + + + + + diff --git a/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectPlanStageMapper.xml b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectPlanStageMapper.xml new file mode 100644 index 00000000..da485b3e --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectPlanStageMapper.xml @@ -0,0 +1,262 @@ + + + + + + + + + + + + + + + + + + + + + + + insert into erp_project_plan_stage( + tenant_id, + + project_id, + + project_plan_id, + + project_phases, + + plan_start_time, + + plan_end_time, + + collection_stage, + + repayment_rate, + + repayment_amount, + + repayment_time, + + delay_day, + + receivable_date, + + reasons_explanation, + + schedule_remark, + + real_start_time, + + real_end_time, + + sort_order, + + remark, + + active_flag, + + del_flag, + + create_dept, + + create_by, + + create_time, + + update_by, + + update_time + + ) + values + + ( + #{item.tenantId}, + + #{item.projectId}, + + #{item.projectPlanId}, + + #{item.projectPhases}, + + #{item.planStartTime}, + + #{item.planEndTime}, + + #{item.collectionStage}, + + #{item.repaymentRate}, + + #{item.repaymentAmount}, + + #{item.repaymentTime}, + + #{item.delayDay}, + + #{item.receivableDate}, + + #{item.reasonsExplanation}, + + #{item.scheduleRemark}, + + #{item.realStartTime}, + + #{item.realEndTime}, + + #{item.sortOrder}, + + #{item.remark}, + + #{item.activeFlag}, + + #{item.delFlag}, + + #{item.createDept}, + + #{item.createBy}, + + #{item.createTime}, + + #{item.updateBy}, + + #{item.updateTime} + + ) + + + + + + + update erp_project_plan_stage + + + tenant_id = #{item.tenantId}, + + + project_id = #{item.projectId}, + + + project_plan_id = #{item.projectPlanId}, + + + project_phases = #{item.projectPhases}, + + + plan_start_time = #{item.planStartTime}, + + + plan_end_time = #{item.planEndTime}, + + + collection_stage = #{item.collectionStage}, + + + repayment_rate = #{item.repaymentRate}, + + + repayment_amount = #{item.repaymentAmount}, + + + repayment_time = #{item.repaymentTime}, + + + delay_day = #{item.delayDay}, + + + receivable_date = #{item.receivableDate}, + + + reasons_explanation = #{item.reasonsExplanation}, + + + schedule_remark = #{item.scheduleRemark}, + + + real_start_time = #{item.realStartTime}, + + + real_end_time = #{item.realEndTime}, + + + sort_order = #{item.sortOrder}, + + + remark = #{item.remark}, + + + active_flag = #{item.activeFlag}, + + + del_flag = #{item.delFlag}, + + + create_dept = #{item.createDept}, + + + create_by = #{item.createBy}, + + + create_time = #{item.createTime}, + + + update_by = #{item.updateBy}, + + + update_time = #{item.updateTime} + + + where plan_stage_id = #{item.planStageId} + + + + + + delete from erp_project_plan_stage + ${ew.getCustomSqlSegment} + + + + + delete from erp_project_plan_stage + where plan_stage_id in + + #{id} + + + + + + + +