From a5db8b62c75eb21e006fbd23b39f7469e4b19a4f Mon Sep 17 00:00:00 2001 From: "zangch@mesnac.com" Date: Tue, 11 Nov 2025 15:40:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(oa/erp):=20=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=A1=B9=E7=9B=AE=E5=8F=98=E6=9B=B4=E7=94=B3?= =?UTF-8?q?=E8=AF=B7=E5=8F=8A=E9=A2=84=E7=AE=97=E5=8F=98=E6=9B=B4=E6=98=8E?= =?UTF-8?q?=E7=BB=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 项目计划变更(erp_project_change、erp_project_change_budget、erp_project_change_progress) - 实现项目预算变更明细的增删改查接口与服务层逻辑 - 实现项目变更申请的完整流程控制接口,包括提交审批功能 - 完成项目变更模块的权限配置与基础数据校验规则 --- .../oa/crm/domain/dto/QuoteTemplateDto.java | 93 ++++ .../crm/domain/dto/QuoteTemplateItemDto.java | 51 ++ .../domain/dto/QuoteTemplateMaterialDto.java | 58 +++ .../ErpProjectChangeBudgetController.java | 116 +++++ .../ErpProjectChangeController.java | 139 ++++++ .../ErpProjectChangeProgressController.java | 116 +++++ .../oa/erp/domain/ErpProjectChange.java | 149 ++++++ .../oa/erp/domain/ErpProjectChangeBudget.java | 85 ++++ .../erp/domain/ErpProjectChangeProgress.java | 97 ++++ .../oa/erp/domain/bo/ErpProjectChangeBo.java | 195 ++++++++ .../domain/bo/ErpProjectChangeBudgetBo.java | 78 +++ .../domain/bo/ErpProjectChangeProgressBo.java | 86 ++++ .../domain/vo/ErpProjectChangeBudgetVo.java | 94 ++++ .../domain/vo/ErpProjectChangeProgressVo.java | 109 +++++ .../oa/erp/domain/vo/ErpProjectChangeVo.java | 204 ++++++++ .../mapper/ErpProjectChangeBudgetMapper.java | 113 +++++ .../oa/erp/mapper/ErpProjectChangeMapper.java | 131 ++++++ .../ErpProjectChangeProgressMapper.java | 113 +++++ .../IErpProjectChangeBudgetService.java | 69 +++ .../IErpProjectChangeProgressService.java | 69 +++ .../erp/service/IErpProjectChangeService.java | 85 ++++ .../ErpProjectChangeBudgetServiceImpl.java | 139 ++++++ .../ErpProjectChangeProgressServiceImpl.java | 140 ++++++ .../impl/ErpProjectChangeServiceImpl.java | 445 ++++++++++++++++++ .../oa/erp/ErpProjectChangeBudgetMapper.xml | 192 ++++++++ .../mapper/oa/erp/ErpProjectChangeMapper.xml | 333 +++++++++++++ .../oa/erp/ErpProjectChangeProgressMapper.xml | 199 ++++++++ .../src/main/resources/报价单模板.md | 22 + .../src/main/resources/报价单模板.xlsx | Bin 0 -> 79471 bytes 29 files changed, 3720 insertions(+) create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/dto/QuoteTemplateDto.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/dto/QuoteTemplateItemDto.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/dto/QuoteTemplateMaterialDto.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectChangeBudgetController.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectChangeController.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectChangeProgressController.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectChange.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectChangeBudget.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectChangeProgress.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectChangeBo.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectChangeBudgetBo.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectChangeProgressBo.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectChangeBudgetVo.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectChangeProgressVo.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectChangeVo.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectChangeBudgetMapper.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectChangeMapper.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectChangeProgressMapper.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectChangeBudgetService.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectChangeProgressService.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectChangeService.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectChangeBudgetServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectChangeProgressServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectChangeServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectChangeBudgetMapper.xml create mode 100644 ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectChangeMapper.xml create mode 100644 ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectChangeProgressMapper.xml create mode 100644 ruoyi-modules/ruoyi-oa/src/main/resources/报价单模板.md create mode 100644 ruoyi-modules/ruoyi-oa/src/main/resources/报价单模板.xlsx diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/dto/QuoteTemplateDto.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/dto/QuoteTemplateDto.java new file mode 100644 index 00000000..e2586e18 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/dto/QuoteTemplateDto.java @@ -0,0 +1,93 @@ +package org.dromara.oa.crm.domain.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 报价单模板DTO + * 用于Excel模板导出的字段映射 + * + * @author Yinq + * @date 2025-10-30 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class QuoteTemplateDto { + + /** + * 客户方联系人 + */ + private String customerContactName; + + /** + * 标题(报价单名称) + */ + private String title; + + /** + * 报价日期 + */ + private String quoteDate; + + /** + * 含税信息 + */ + private String taxIncludedInfo; + + /** + * 付款方式 + */ + private String paymentMethod; + + /** + * 交货期 + */ + private String deliveryPeriod; + + /** + * 交货方式 + */ + private String deliveryMethod; + + /** + * 报价有效期 + */ + private String validDays; + + /** + * 未税总价 + */ + private String totalBeforeTax; + + /** + * 税额 + */ + private String totalTax; + + /** + * 含税总价 + */ + private String totalIncludingTax; + + /** + * 总价大写 + */ + private String totalInChinese; + + /** + * 供货方联系人 + */ + private String supplierContactName; + + /** + * 供货方联系电话 + */ + private String supplierContactPhone; + + /** + * 供货方电子邮箱 + */ + private String supplierContactEmail; +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/dto/QuoteTemplateItemDto.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/dto/QuoteTemplateItemDto.java new file mode 100644 index 00000000..57f9c3d1 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/dto/QuoteTemplateItemDto.java @@ -0,0 +1,51 @@ +package org.dromara.oa.crm.domain.dto; + +import cn.idev.excel.annotation.ExcelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 报价单模板明细项 DTO + * 用于 EasyExcel 模板填充 + * + * @author Yinq + * @date 2025-10-29 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class QuoteTemplateItemDto implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** 序号 */ + private Long seq; + + /** 产品名称 */ + private String productName; + + /** 型号/说明 */ + private String modelDesc; + + /** 数量 */ + private BigDecimal quantity; + + /** 单位 */ + private String unit; + + /** 单价(含税) */ + private BigDecimal price; + + /** 小计(含税) */ + private BigDecimal subtotal; + + /** 备注 */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/dto/QuoteTemplateMaterialDto.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/dto/QuoteTemplateMaterialDto.java new file mode 100644 index 00000000..cbddbdb1 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/dto/QuoteTemplateMaterialDto.java @@ -0,0 +1,58 @@ +package org.dromara.oa.crm.domain.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 报价单模板物料明细DTO + * 用于Excel模板导出的物料明细字段映射 + * + * @author Yinq + * @date 2025-10-30 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class QuoteTemplateMaterialDto { + + /** + * 序号 + */ + private String seq; + + /** + * 产品/服务名称 + */ + private String productName; + + /** + * 型号/说明 + */ + private String modelDesc; + + /** + * 数量 + */ + private String quantity; + + /** + * 单位 + */ + private String unit; + + /** + * 单价 + */ + private String price; + + /** + * 小计(含税) + */ + private String subtotal; + + /** + * 备注 + */ + private String remark; +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectChangeBudgetController.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectChangeBudgetController.java new file mode 100644 index 00000000..16a178c0 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectChangeBudgetController.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.ErpProjectChangeBudgetVo; +import org.dromara.oa.erp.domain.bo.ErpProjectChangeBudgetBo; +import org.dromara.oa.erp.service.IErpProjectChangeBudgetService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 项目预算变更明细 + * 前端访问路由地址为:/oa/erp/erpProjectChangeBudget + * + * @author Yinq + * @date 2025-11-10 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/erpProjectChangeBudget") +public class ErpProjectChangeBudgetController extends BaseController { + + private final IErpProjectChangeBudgetService erpProjectChangeBudgetService; + + /** + * 查询项目预算变更明细列表 + */ + @SaCheckPermission("oa/erp:erpProjectChangeBudget:list") + @GetMapping("/list") + public TableDataInfo list(ErpProjectChangeBudgetBo bo, PageQuery pageQuery) { + return erpProjectChangeBudgetService.queryPageList(bo, pageQuery); + } + + /** + * 导出项目预算变更明细列表 + */ + @SaCheckPermission("oa/erp:erpProjectChangeBudget:export") + @Log(title = "项目预算变更明细", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(ErpProjectChangeBudgetBo bo, HttpServletResponse response) { + List list = erpProjectChangeBudgetService.queryList(bo); + ExcelUtil.exportExcel(list, "项目预算变更明细", ErpProjectChangeBudgetVo.class, response); + } + + /** + * 获取项目预算变更明细详细信息 + * + * @param changeBudgetId 主键 + */ + @SaCheckPermission("oa/erp:erpProjectChangeBudget:query") + @GetMapping("/{changeBudgetId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable("changeBudgetId") Long changeBudgetId) { + return R.ok(erpProjectChangeBudgetService.queryById(changeBudgetId)); + } + + /** + * 新增项目预算变更明细 + */ + @SaCheckPermission("oa/erp:erpProjectChangeBudget:add") + @Log(title = "项目预算变更明细", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ErpProjectChangeBudgetBo bo) { + return toAjax(erpProjectChangeBudgetService.insertByBo(bo)); + } + + /** + * 修改项目预算变更明细 + */ + @SaCheckPermission("oa/erp:erpProjectChangeBudget:edit") + @Log(title = "项目预算变更明细", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ErpProjectChangeBudgetBo bo) { + return toAjax(erpProjectChangeBudgetService.updateByBo(bo)); + } + + /** + * 删除项目预算变更明细 + * + * @param changeBudgetIds 主键串 + */ + @SaCheckPermission("oa/erp:erpProjectChangeBudget:remove") + @Log(title = "项目预算变更明细", businessType = BusinessType.DELETE) + @DeleteMapping("/{changeBudgetIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable("changeBudgetIds") Long[] changeBudgetIds) { + return toAjax(erpProjectChangeBudgetService.deleteWithValidByIds(List.of(changeBudgetIds), true)); + } + + /** + * 下拉框查询项目预算变更明细列表 + */ + @GetMapping("/getErpProjectChangeBudgetList") + public R> getErpProjectChangeBudgetList(ErpProjectChangeBudgetBo bo) { + List list = erpProjectChangeBudgetService.queryList(bo); + return R.ok(list); + } + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectChangeController.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectChangeController.java new file mode 100644 index 00000000..60a74ee8 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectChangeController.java @@ -0,0 +1,139 @@ +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.ErpProjectChangeVo; +import org.dromara.oa.erp.domain.bo.ErpProjectChangeBo; +import org.dromara.oa.erp.service.IErpProjectChangeService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 项目变更申请 + * 前端访问路由地址为:/oa/erp/erpProjectChange + * + * @author Yinq + * @date 2025-11-10 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/erp/erpProjectChange") +public class ErpProjectChangeController extends BaseController { + + private final IErpProjectChangeService erpProjectChangeService; + + /** + * 查询项目变更申请列表 + */ + @SaCheckPermission("oa/erp:erpProjectChange:list") + @GetMapping("/list") + public TableDataInfo list(ErpProjectChangeBo bo, PageQuery pageQuery) { + return erpProjectChangeService.queryPageList(bo, pageQuery); + } + + /** + * 导出项目变更申请列表 + */ + @SaCheckPermission("oa/erp:erpProjectChange:export") + @Log(title = "项目变更申请", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(ErpProjectChangeBo bo, HttpServletResponse response) { + List list = erpProjectChangeService.queryList(bo); + ExcelUtil.exportExcel(list, "项目变更申请", ErpProjectChangeVo.class, response); + } + + /** + * 获取项目变更申请详细信息 + * + * @param projectChangeId 主键 + */ + @SaCheckPermission("oa/erp:erpProjectChange:query") + @GetMapping("/{projectChangeId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable("projectChangeId") Long projectChangeId) { + return R.ok(erpProjectChangeService.queryById(projectChangeId)); + } + + /** + * 新增项目变更申请 + */ + @SaCheckPermission("oa/erp:erpProjectChange:add") + @Log(title = "项目变更申请", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ErpProjectChangeBo bo) { + return toAjax(erpProjectChangeService.insertByBo(bo)); + } + + /** + * 修改项目变更申请 + */ + @SaCheckPermission("oa/erp:erpProjectChange:edit") + @Log(title = "项目变更申请", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ErpProjectChangeBo bo) { + return toAjax(erpProjectChangeService.updateByBo(bo)); + } + + /** + * 删除项目变更申请 + * + * @param projectChangeIds 主键串 + */ + @SaCheckPermission("oa/erp:erpProjectChange:remove") + @Log(title = "项目变更申请", businessType = BusinessType.DELETE) + @DeleteMapping("/{projectChangeIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable("projectChangeIds") Long[] projectChangeIds) { + return toAjax(erpProjectChangeService.deleteWithValidByIds(List.of(projectChangeIds), true)); + } + + /** + * 下拉框查询项目变更申请列表 + */ + @GetMapping("/getErpProjectChangeList") + public R> getErpProjectChangeList(ErpProjectChangeBo bo) { + List list = erpProjectChangeService.queryList(bo); + return R.ok(list); + } + + /** + * 根据项目ID准备项目变更信息(带出项目信息和项目计划阶段) + * + * @param projectId 项目ID + */ + @SaCheckPermission("oa/erp:erpProjectChange:query") + @GetMapping("/prepareWithInfo/{projectId}") + public R prepareWithInfo(@NotNull(message = "项目ID不能为空") + @PathVariable("projectId") Long projectId) { + return R.ok(erpProjectChangeService.prepareByProjectWithInfo(projectId)); + } + + /** + * 提交项目变更并发起审批流 + */ + @SaCheckPermission("oa/erp:erpProjectChange:add") + @Log(title = "项目变更申请", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/submitAndFlowStart") + public R submitAndFlowStart(@Validated(AddGroup.class) @RequestBody ErpProjectChangeBo bo) { + return R.ok(erpProjectChangeService.projectChangeSubmitAndFlowStart(bo)); + } + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectChangeProgressController.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectChangeProgressController.java new file mode 100644 index 00000000..ca3fe7b9 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectChangeProgressController.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.ErpProjectChangeProgressVo; +import org.dromara.oa.erp.domain.bo.ErpProjectChangeProgressBo; +import org.dromara.oa.erp.service.IErpProjectChangeProgressService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 项目进度变更明细 + * 前端访问路由地址为:/oa/erp/erpProjectChangeProgress + * + * @author Yinq + * @date 2025-11-10 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/erpProjectChangeProgress") +public class ErpProjectChangeProgressController extends BaseController { + + private final IErpProjectChangeProgressService erpProjectChangeProgressService; + + /** + * 查询项目进度变更明细列表 + */ + @SaCheckPermission("oa/erp:erpProjectChangeProgress:list") + @GetMapping("/list") + public TableDataInfo list(ErpProjectChangeProgressBo bo, PageQuery pageQuery) { + return erpProjectChangeProgressService.queryPageList(bo, pageQuery); + } + + /** + * 导出项目进度变更明细列表 + */ + @SaCheckPermission("oa/erp:erpProjectChangeProgress:export") + @Log(title = "项目进度变更明细", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(ErpProjectChangeProgressBo bo, HttpServletResponse response) { + List list = erpProjectChangeProgressService.queryList(bo); + ExcelUtil.exportExcel(list, "项目进度变更明细", ErpProjectChangeProgressVo.class, response); + } + + /** + * 获取项目进度变更明细详细信息 + * + * @param changeProgressId 主键 + */ + @SaCheckPermission("oa/erp:erpProjectChangeProgress:query") + @GetMapping("/{changeProgressId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable("changeProgressId") Long changeProgressId) { + return R.ok(erpProjectChangeProgressService.queryById(changeProgressId)); + } + + /** + * 新增项目进度变更明细 + */ + @SaCheckPermission("oa/erp:erpProjectChangeProgress:add") + @Log(title = "项目进度变更明细", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ErpProjectChangeProgressBo bo) { + return toAjax(erpProjectChangeProgressService.insertByBo(bo)); + } + + /** + * 修改项目进度变更明细 + */ + @SaCheckPermission("oa/erp:erpProjectChangeProgress:edit") + @Log(title = "项目进度变更明细", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ErpProjectChangeProgressBo bo) { + return toAjax(erpProjectChangeProgressService.updateByBo(bo)); + } + + /** + * 删除项目进度变更明细 + * + * @param changeProgressIds 主键串 + */ + @SaCheckPermission("oa/erp:erpProjectChangeProgress:remove") + @Log(title = "项目进度变更明细", businessType = BusinessType.DELETE) + @DeleteMapping("/{changeProgressIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable("changeProgressIds") Long[] changeProgressIds) { + return toAjax(erpProjectChangeProgressService.deleteWithValidByIds(List.of(changeProgressIds), true)); + } + + /** + * 下拉框查询项目进度变更明细列表 + */ + @GetMapping("/getErpProjectChangeProgressList") + public R> getErpProjectChangeProgressList(ErpProjectChangeProgressBo bo) { + List list = erpProjectChangeProgressService.queryList(bo); + return R.ok(list); + } + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectChange.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectChange.java new file mode 100644 index 00000000..7f2d833f --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectChange.java @@ -0,0 +1,149 @@ +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_project_change + * + * @author Yinq + * @date 2025-11-10 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("erp_project_change") +public class ErpProjectChange extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 项目变更ID + */ + @TableId(value = "project_change_id", type = IdType.ASSIGN_ID) + private Long projectChangeId; + + /** + * 项目ID + */ + private Long projectId; + + /** + * 项目编号 + */ + private String projectCode; + + /** + * 项目名称 + */ + private String projectName; + + /** + * 项目类别(1销售(实施、物流) 2销售(备件) 3研发 4预投) + */ + private String projectCategory; + + /** + * 变更类型(多选)(1预算变更 2计划变更 3范围变更 4需求变更 5合同变更) + */ + private String changeType; + + /** + * 变更次数 + */ + private Integer changeNumber; + + /** + * 项目经理ID + */ + private Long projectManagerId; + + /** + * 项目经理姓名 + */ + private String projectManagerName; + + /** + * 部门负责人ID + */ + private Long deptHeadId; + + /** + * 部门负责人姓名 + */ + private String deptHeadName; + + /** + * 分管副总ID + */ + private Long responsibleVpId; + + /** + * 分管副总姓名 + */ + private String responsibleVpName; + + /** + * 申请变更时间 + */ + private Date applyChangeDate; + + /** + * 项目合同额 + */ + private BigDecimal contractAmount; + + /** + * 项目合同净额 + */ + private BigDecimal contractNetAmount; + + /** + * 项目当前情况 + */ + private String currentStatus; + + /** + * 变更原因 + */ + private String changeReason; + + /** + * 后续工作 + */ + private String followUpWork; + + /** + * 项目变更状态(1暂存 2审批中 3可用) + */ + private String projectChangeStatus; + + /** + * 流程状态 + */ + private String flowStatus; + + /** + * 备注 + */ + 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/ErpProjectChangeBudget.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectChangeBudget.java new file mode 100644 index 00000000..24b9c930 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectChangeBudget.java @@ -0,0 +1,85 @@ +package org.dromara.oa.erp.domain; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.tenant.core.TenantEntity; + +import java.math.BigDecimal; + +import java.io.Serial; + +/** + * 项目预算变更明细对象 erp_project_change_budget + * + * @author Yinq + * @date 2025-11-10 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("erp_project_change_budget") +public class ErpProjectChangeBudget extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 预算变更ID + */ + @TableId(value = "change_budget_id", type = IdType.AUTO) + private Long changeBudgetId; + + /** + * 变更申请ID + */ + private Long projectChangeId; + + /** + * 预算详情ID + */ + private Long budgetDetailId; + + /** + * 科目名称(材料费、人工费、安装费、差旅费、其他费用) + */ + private String subjectName; + + /** + * 变更前预算 + */ + private BigDecimal budgetBefore; + + /** + * 变更后预算 + */ + private BigDecimal budgetAfter; + + /** + * 已使用金额 + */ + private BigDecimal amountUsed; + + /** + * 费用调整原因 + */ + private String adjustmentReason; + + /** + * 排序顺序 + */ + private Long sortOrder; + + /** + * 备注 + */ + private String remark; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectChangeProgress.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectChangeProgress.java new file mode 100644 index 00000000..42e6472f --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectChangeProgress.java @@ -0,0 +1,97 @@ +package org.dromara.oa.erp.domain; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +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 org.dromara.common.tenant.core.TenantEntity; + +import java.io.Serial; + +/** + * 项目进度变更明细对象 erp_project_change_progress + * + * @author Yinq + * @date 2025-11-10 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("erp_project_change_progress") +public class ErpProjectChangeProgress extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 进度变更ID + */ + @TableId(value = "change_progress_id", type = IdType.AUTO) + private Long changeProgressId; + + /** + * 变更申请ID + */ + private Long projectChangeId; + + /** + * 计划阶段ID + */ + private Long planStageId; + + /** + * 项目阶段(字典project_phases) + */ + @TableField(exist = false) + private String projectPhases; + + /** + * 项目里程碑 + */ + private String milestoneName; + + /** + * 原计划时间起 + */ + private Date originalStart; + + /** + * 原计划时间止 + */ + private Date originalEnd; + + /** + * 变更后时间起 + */ + private Date changedStart; + + /** + * 变更后时间止 + */ + private Date changedEnd; + + /** + * 里程碑完成程度(百分比) + */ + private BigDecimal completionDegree; + + /** + * 排序顺序 + */ + private Long sortOrder; + + /** + * 备注 + */ + private String remark; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectChangeBo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectChangeBo.java new file mode 100644 index 00000000..209fb1d1 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectChangeBo.java @@ -0,0 +1,195 @@ +package org.dromara.oa.erp.domain.bo; + +import cn.hutool.core.util.ObjectUtil; +import org.dromara.oa.erp.domain.ErpProjectChange; +import org.dromara.oa.erp.domain.ErpProjectChangeBudget; +import org.dromara.oa.erp.domain.ErpProjectChangeProgress; +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.math.BigDecimal; +import java.util.*; + +import com.fasterxml.jackson.annotation.JsonFormat; +import org.dromara.workflow.api.domain.RemoteFlowInstanceBizExt; + +/** + * 项目变更申请业务对象 erp_project_change + * + * @author Yinq + * @date 2025-11-10 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ErpProjectChange.class, reverseConvertGenerate = false) +public class ErpProjectChangeBo extends BaseEntity { + + /** + * 项目变更ID + */ + @NotNull(message = "项目变更ID不能为空", groups = { EditGroup.class }) + private Long projectChangeId; + + /** + * 项目ID + */ + @NotNull(message = "项目ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long projectId; + + /** + * 项目编号 + */ + private String projectCode; + + /** + * 项目名称 + */ + private String projectName; + + /** + * 项目类别(1销售(实施、物流) 2销售(备件) 3研发 4预投) + */ + private String projectCategory; + + /** + * 变更类型(多选)(1预算变更 2计划变更 3范围变更 4需求变更 5合同变更) + */ + private String changeType; + + /** + * 变更次数 + */ + private Integer changeNumber; + + /** + * 项目经理ID + */ + private Long projectManagerId; + + /** + * 项目经理姓名 + */ + private String projectManagerName; + + /** + * 部门负责人ID + */ + private Long deptHeadId; + + /** + * 部门负责人姓名 + */ + private String deptHeadName; + + /** + * 分管副总ID + */ + private Long responsibleVpId; + + /** + * 分管副总姓名 + */ + private String responsibleVpName; + + /** + * 申请变更时间 + */ + @NotNull(message = "申请变更时间不能为空", groups = { AddGroup.class, EditGroup.class }) + private Date applyChangeDate; + + /** + * 项目合同额 + */ + private BigDecimal contractAmount; + + /** + * 项目合同净额 + */ + private BigDecimal contractNetAmount; + + /** + * 项目当前情况 + */ + private String currentStatus; + + /** + * 变更原因 + */ + private String changeReason; + + /** + * 后续工作 + */ + private String followUpWork; + + /** + * 项目变更状态(1暂存 2审批中 3可用) + */ + private String projectChangeStatus; + + /** + * 流程状态 + */ + private String flowStatus; + + /** + * 备注 + */ + private String remark; + + /** + * 激活标识(1是 0否) + */ + private String activeFlag; + + /** + * 预算变更明细列表 + */ + private List budgetList; + + /** + * 进度变更明细列表 + */ + private List progressList; + + /** + * 流程编码 + */ + 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/ErpProjectChangeBudgetBo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectChangeBudgetBo.java new file mode 100644 index 00000000..bbf6b8a6 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectChangeBudgetBo.java @@ -0,0 +1,78 @@ +package org.dromara.oa.erp.domain.bo; + +import org.dromara.oa.erp.domain.ErpProjectChangeBudget; +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.math.BigDecimal; + +/** + * 项目预算变更明细业务对象 erp_project_change_budget + * + * @author Yinq + * @date 2025-11-10 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ErpProjectChangeBudget.class, reverseConvertGenerate = false) +public class ErpProjectChangeBudgetBo extends BaseEntity { + + /** + * 预算变更ID + */ + @NotNull(message = "预算变更ID不能为空", groups = { EditGroup.class }) + private Long changeBudgetId; + + /** + * 变更申请ID + */ + @NotNull(message = "变更申请ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long projectChangeId; + + /** + * 预算详情ID + */ + private Long budgetDetailId; + + /** + * 科目名称(材料费、人工费、安装费、差旅费、其他费用) + */ + @NotBlank(message = "科目名称(材料费、人工费、安装费、差旅费、其他费用)不能为空", groups = { AddGroup.class, EditGroup.class }) + private String subjectName; + + /** + * 变更前预算 + */ + private BigDecimal budgetBefore; + + /** + * 变更后预算 + */ + private BigDecimal budgetAfter; + + /** + * 已使用金额 + */ + private BigDecimal amountUsed; + + /** + * 费用调整原因 + */ + private String adjustmentReason; + + /** + * 排序顺序 + */ + private Long sortOrder; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectChangeProgressBo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectChangeProgressBo.java new file mode 100644 index 00000000..64641fda --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectChangeProgressBo.java @@ -0,0 +1,86 @@ +package org.dromara.oa.erp.domain.bo; + +import org.dromara.oa.erp.domain.ErpProjectChangeProgress; +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.math.BigDecimal; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 项目进度变更明细业务对象 erp_project_change_progress + * + * @author Yinq + * @date 2025-11-10 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ErpProjectChangeProgress.class, reverseConvertGenerate = false) +public class ErpProjectChangeProgressBo extends BaseEntity { + + /** + * 进度变更ID + */ + @NotNull(message = "进度变更ID不能为空", groups = { EditGroup.class }) + private Long changeProgressId; + + /** + * 变更申请ID + */ + @NotNull(message = "变更申请ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long projectChangeId; + + /** + * 计划阶段ID + */ + @NotNull(message = "计划阶段ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long planStageId; + + /** + * 项目里程碑 + */ + @NotBlank(message = "项目里程碑不能为空", groups = { AddGroup.class, EditGroup.class }) + private String milestoneName; + + /** + * 原计划时间起 + */ + private Date originalStart; + + /** + * 原计划时间止 + */ + private Date originalEnd; + + /** + * 变更后时间起 + */ + private Date changedStart; + + /** + * 变更后时间止 + */ + private Date changedEnd; + + /** + * 里程碑完成程度(百分比) + */ + private BigDecimal completionDegree; + + /** + * 排序顺序 + */ + private Long sortOrder; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectChangeBudgetVo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectChangeBudgetVo.java new file mode 100644 index 00000000..c3a87632 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectChangeBudgetVo.java @@ -0,0 +1,94 @@ +package org.dromara.oa.erp.domain.vo; + +import java.math.BigDecimal; +import org.dromara.oa.erp.domain.ErpProjectChangeBudget; +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_change_budget + * + * @author Yinq + * @date 2025-11-10 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ErpProjectChangeBudget.class) +public class ErpProjectChangeBudgetVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 预算变更ID + */ + @ExcelProperty(value = "预算变更ID") + private Long changeBudgetId; + + /** + * 变更申请ID + */ + @ExcelProperty(value = "变更申请ID") + private Long projectChangeId; + + /** + * 预算详情ID + */ + @ExcelProperty(value = "预算详情ID") + private Long budgetDetailId; + + /** + * 科目名称(材料费、人工费、安装费、差旅费、其他费用) + */ + @ExcelProperty(value = "科目名称", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "材=料费、人工费、安装费、差旅费、其他费用") + private String subjectName; + + /** + * 变更前预算 + */ + @ExcelProperty(value = "变更前预算") + private BigDecimal budgetBefore; + + /** + * 变更后预算 + */ + @ExcelProperty(value = "变更后预算") + private BigDecimal budgetAfter; + + /** + * 已使用金额 + */ + @ExcelProperty(value = "已使用金额") + private BigDecimal amountUsed; + + /** + * 费用调整原因 + */ + @ExcelProperty(value = "费用调整原因") + private String adjustmentReason; + + /** + * 排序顺序 + */ + @ExcelProperty(value = "排序顺序") + private Long sortOrder; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectChangeProgressVo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectChangeProgressVo.java new file mode 100644 index 00000000..e65708c7 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectChangeProgressVo.java @@ -0,0 +1,109 @@ +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.ErpProjectChangeProgress; +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_change_progress + * + * @author Yinq + * @date 2025-11-10 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ErpProjectChangeProgress.class) +public class ErpProjectChangeProgressVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 进度变更ID + */ + @ExcelProperty(value = "进度变更ID") + private Long changeProgressId; + + /** + * 变更申请ID + */ + @ExcelProperty(value = "变更申请ID") + private Long projectChangeId; + + /** + * 计划阶段ID + */ + @ExcelProperty(value = "计划阶段ID") + private Long planStageId; + + /** + * 项目阶段(字典project_phases) + */ + @ExcelProperty(value = "项目阶段", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "project_phases") + private String projectPhases; + + /** + * 项目里程碑 + */ + @ExcelProperty(value = "项目里程碑") + private String milestoneName; + + /** + * 原计划时间起 + */ + @ExcelProperty(value = "原计划时间起") + private Date originalStart; + + /** + * 原计划时间止 + */ + @ExcelProperty(value = "原计划时间止") + private Date originalEnd; + + /** + * 变更后时间起 + */ + @ExcelProperty(value = "变更后时间起") + private Date changedStart; + + /** + * 变更后时间止 + */ + @ExcelProperty(value = "变更后时间止") + private Date changedEnd; + + /** + * 里程碑完成程度(百分比) + */ + @ExcelProperty(value = "里程碑完成程度", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "百=分比") + private BigDecimal completionDegree; + + /** + * 排序顺序 + */ + @ExcelProperty(value = "排序顺序") + private Long sortOrder; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectChangeVo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectChangeVo.java new file mode 100644 index 00000000..421eb6a3 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectChangeVo.java @@ -0,0 +1,204 @@ +package org.dromara.oa.erp.domain.vo; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.dromara.oa.erp.domain.ErpProjectChange; +import org.dromara.oa.erp.domain.ErpProjectChangeBudget; +import org.dromara.oa.erp.domain.ErpProjectChangeProgress; +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 com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 项目变更申请视图对象 erp_project_change + * + * @author Yinq + * @date 2025-11-10 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ErpProjectChange.class) +public class ErpProjectChangeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 项目变更ID + */ + @ExcelProperty(value = "项目变更ID") + private Long projectChangeId; + + /** + * 项目ID + */ + @ExcelProperty(value = "项目ID") + private Long projectId; + + /** + * 项目编号 + */ + @ExcelProperty(value = "项目编号") + private String projectCode; + + /** + * 项目名称 + */ + @ExcelProperty(value = "项目名称") + private String projectName; + + /** + * 项目类别(1销售(实施、物流) 2销售(备件) 3研发 4预投) + */ + @ExcelProperty(value = "项目类别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "project_category") + private String projectCategory; + + /** + * 变更类型(多选)(1预算变更 2计划变更 3范围变更 4需求变更 5合同变更) + */ + @ExcelProperty(value = "变更类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "change_type") + private String changeType; + + /** + * 变更次数 + */ + @ExcelProperty(value = "变更次数") + private Integer changeNumber; + + /** + * 项目经理ID + */ + @ExcelProperty(value = "项目经理ID") + private Long projectManagerId; + + /** + * 项目经理姓名 + */ + @ExcelProperty(value = "项目经理姓名") + private String projectManagerName; + + /** + * 部门负责人ID + */ + @ExcelProperty(value = "部门负责人ID") + private Long deptHeadId; + + /** + * 部门负责人姓名 + */ + @ExcelProperty(value = "部门负责人姓名") + private String deptHeadName; + + /** + * 分管副总ID + */ + @ExcelProperty(value = "分管副总ID") + private Long responsibleVpId; + + /** + * 分管副总姓名 + */ + @ExcelProperty(value = "分管副总姓名") + private String responsibleVpName; + + /** + * 申请变更时间 + */ + @ExcelProperty(value = "申请变更时间") + private Date applyChangeDate; + + /** + * 项目合同额 + */ + @ExcelProperty(value = "项目合同额") + private BigDecimal contractAmount; + + /** + * 项目合同净额 + */ + @ExcelProperty(value = "项目合同净额") + private BigDecimal contractNetAmount; + + /** + * 项目当前情况 + */ + @ExcelProperty(value = "项目当前情况") + private String currentStatus; + + /** + * 变更原因 + */ + @ExcelProperty(value = "变更原因") + private String changeReason; + + /** + * 后续工作 + */ + @ExcelProperty(value = "后续工作") + private String followUpWork; + + /** + * 项目变更状态(1暂存 2审批中 3可用) + */ + @ExcelProperty(value = "项目变更状态(1暂存 2审批中 3可用)", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "project_change_status") + private String projectChangeStatus; + + /** + * 流程状态 + */ + @ExcelProperty(value = "流程状态") + private String flowStatus; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 激活标识(1是 0否) + */ + @ExcelProperty(value = "激活标识", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "active_flag") + private String activeFlag; + + /** + * 创建人 + */ + @ExcelProperty(value = "创建人") + private Long createBy; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + /** + * 预算变更明细列表 + */ + @TableField(exist = false) + private List budgetList; + + /** + * 进度变更明细列表 + */ + @TableField(exist = false) + private List progressList; + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectChangeBudgetMapper.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectChangeBudgetMapper.java new file mode 100644 index 00000000..597162fb --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectChangeBudgetMapper.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.ErpProjectChangeBudget; +import org.dromara.oa.erp.domain.vo.ErpProjectChangeBudgetVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 项目预算变更明细Mapper接口 + * + * @author Yinq + * @date 2025-11-10 + */ +public interface ErpProjectChangeBudgetMapper extends BaseMapperPlus { + + /** + * 查询项目预算变更明细列表 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 项目预算变更明细集合 + */ + public Page selectCustomErpProjectChangeBudgetVoList(@Param("page") Page page, @Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 查询项目预算变更明细列表 + * + * @param queryWrapper 条件 + * @return 项目预算变更明细集合 + */ + public List selectCustomErpProjectChangeBudgetVoList(@Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 根据ID查询项目预算变更明细详情 + * + * @param changeBudgetId 主键ID + * @return 项目预算变更明细对象 + */ + ErpProjectChangeBudgetVo selectCustomErpProjectChangeBudgetVoById(@Param("changeBudgetId") Long changeBudgetId); + + /** + * 根据ID列表批量查询项目预算变更明细 + * + * @param ids ID集合 + * @return 项目预算变更明细集合 + */ + List selectCustomErpProjectChangeBudgetVoByIds(@Param("ids") Collection ids); + + /** + * 统计项目预算变更明细记录数 + * + * @param queryWrapper 查询条件 + * @return 记录总数 + */ + Long countCustomErpProjectChangeBudget(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 分页查询项目预算变更明细(自定义条件) + * + * @param page 分页对象 + * @param queryWrapper 查询条件 + * @return 分页结果 + */ + Page selectCustomErpProjectChangeBudgetVoPage(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 批量插入项目预算变更明细 + * + * @param list 项目预算变更明细对象集合 + * @return 影响行数 + */ + int batchInsertErpProjectChangeBudget(@Param("list") List list); + + /** + * 批量更新项目预算变更明细 + * + * @param list 项目预算变更明细对象集合 + * @return 影响行数 + */ + int batchUpdateErpProjectChangeBudget(@Param("list") List list); + + /** + * 根据自定义条件删除项目预算变更明细 + * + * @param queryWrapper 删除条件 + * @return 影响行数 + */ + int deleteCustomErpProjectChangeBudget(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据ID列表批量删除项目预算变更明细 + * + * @param ids ID集合 + * @return 影响行数 + */ + int deleteCustomErpProjectChangeBudgetByIds(@Param("ids") Collection ids); + + /** + * 检查项目预算变更明细是否存在 + * + * @param queryWrapper 查询条件 + * @return 是否存在 + */ + Boolean existsErpProjectChangeBudget(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectChangeMapper.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectChangeMapper.java new file mode 100644 index 00000000..099c5de0 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectChangeMapper.java @@ -0,0 +1,131 @@ +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.ErpProjectChange; +import org.dromara.oa.erp.domain.vo.ErpProjectChangeVo; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 项目变更申请Mapper接口 + * + * @author Yinq + * @date 2025-11-10 + */ +public interface ErpProjectChangeMapper extends BaseMapperPlus { + + /** + * 查询项目变更申请列表 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 项目变更申请集合 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "t.create_dept"), + @DataColumn(key = "userName", value = "t.create_by") + }) + public Page selectCustomErpProjectChangeVoList(@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 selectCustomErpProjectChangeVoList(@Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 根据ID查询项目变更申请详情 + * + * @param projectChangeId 主键ID + * @return 项目变更申请对象 + */ + ErpProjectChangeVo selectCustomErpProjectChangeVoById(@Param("projectChangeId") Long projectChangeId); + + /** + * 根据ID列表批量查询项目变更申请 + * + * @param ids ID集合 + * @return 项目变更申请集合 + */ + List selectCustomErpProjectChangeVoByIds(@Param("ids") Collection ids); + + /** + * 统计项目变更申请记录数 + * + * @param queryWrapper 查询条件 + * @return 记录总数 + */ + Long countCustomErpProjectChange(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 分页查询项目变更申请(自定义条件) + * + * @param page 分页对象 + * @param queryWrapper 查询条件 + * @return 分页结果 + */ + Page selectCustomErpProjectChangeVoPage(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 批量插入项目变更申请 + * + * @param list 项目变更申请对象集合 + * @return 影响行数 + */ + int batchInsertErpProjectChange(@Param("list") List list); + + /** + * 批量更新项目变更申请 + * + * @param list 项目变更申请对象集合 + * @return 影响行数 + */ + int batchUpdateErpProjectChange(@Param("list") List list); + + /** + * 根据自定义条件删除项目变更申请 + * + * @param queryWrapper 删除条件 + * @return 影响行数 + */ + int deleteCustomErpProjectChange(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据ID列表批量删除项目变更申请 + * + * @param ids ID集合 + * @return 影响行数 + */ + int deleteCustomErpProjectChangeByIds(@Param("ids") Collection ids); + + /** + * 检查项目变更申请是否存在 + * + * @param queryWrapper 查询条件 + * @return 是否存在 + */ + Boolean existsErpProjectChange(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据项目ID准备项目变更信息(带出项目信息和用户名称) + * + * @param projectId 项目ID + * @return 项目变更申请对象 + */ + ErpProjectChangeVo prepareByProjectId(@Param("projectId") Long projectId); + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectChangeProgressMapper.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectChangeProgressMapper.java new file mode 100644 index 00000000..4e7e2356 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/mapper/ErpProjectChangeProgressMapper.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.ErpProjectChangeProgress; +import org.dromara.oa.erp.domain.vo.ErpProjectChangeProgressVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 项目进度变更明细Mapper接口 + * + * @author Yinq + * @date 2025-11-10 + */ +public interface ErpProjectChangeProgressMapper extends BaseMapperPlus { + + /** + * 查询项目进度变更明细列表 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 项目进度变更明细集合 + */ + public Page selectCustomErpProjectChangeProgressVoList(@Param("page") Page page, @Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 查询项目进度变更明细列表 + * + * @param queryWrapper 条件 + * @return 项目进度变更明细集合 + */ + public List selectCustomErpProjectChangeProgressVoList(@Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 根据ID查询项目进度变更明细详情 + * + * @param changeProgressId 主键ID + * @return 项目进度变更明细对象 + */ + ErpProjectChangeProgressVo selectCustomErpProjectChangeProgressVoById(@Param("changeProgressId") Long changeProgressId); + + /** + * 根据ID列表批量查询项目进度变更明细 + * + * @param ids ID集合 + * @return 项目进度变更明细集合 + */ + List selectCustomErpProjectChangeProgressVoByIds(@Param("ids") Collection ids); + + /** + * 统计项目进度变更明细记录数 + * + * @param queryWrapper 查询条件 + * @return 记录总数 + */ + Long countCustomErpProjectChangeProgress(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 分页查询项目进度变更明细(自定义条件) + * + * @param page 分页对象 + * @param queryWrapper 查询条件 + * @return 分页结果 + */ + Page selectCustomErpProjectChangeProgressVoPage(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 批量插入项目进度变更明细 + * + * @param list 项目进度变更明细对象集合 + * @return 影响行数 + */ + int batchInsertErpProjectChangeProgress(@Param("list") List list); + + /** + * 批量更新项目进度变更明细 + * + * @param list 项目进度变更明细对象集合 + * @return 影响行数 + */ + int batchUpdateErpProjectChangeProgress(@Param("list") List list); + + /** + * 根据自定义条件删除项目进度变更明细 + * + * @param queryWrapper 删除条件 + * @return 影响行数 + */ + int deleteCustomErpProjectChangeProgress(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据ID列表批量删除项目进度变更明细 + * + * @param ids ID集合 + * @return 影响行数 + */ + int deleteCustomErpProjectChangeProgressByIds(@Param("ids") Collection ids); + + /** + * 检查项目进度变更明细是否存在 + * + * @param queryWrapper 查询条件 + * @return 是否存在 + */ + Boolean existsErpProjectChangeProgress(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectChangeBudgetService.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectChangeBudgetService.java new file mode 100644 index 00000000..5c882beb --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectChangeBudgetService.java @@ -0,0 +1,69 @@ +package org.dromara.oa.erp.service; + +import org.dromara.oa.erp.domain.ErpProjectChangeBudget; +import org.dromara.oa.erp.domain.vo.ErpProjectChangeBudgetVo; +import org.dromara.oa.erp.domain.bo.ErpProjectChangeBudgetBo; +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-11-10 + */ +public interface IErpProjectChangeBudgetService { + + /** + * 查询项目预算变更明细 + * + * @param changeBudgetId 主键 + * @return 项目预算变更明细 + */ + ErpProjectChangeBudgetVo queryById(Long changeBudgetId); + + /** + * 分页查询项目预算变更明细列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 项目预算变更明细分页列表 + */ + TableDataInfo queryPageList(ErpProjectChangeBudgetBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的项目预算变更明细列表 + * + * @param bo 查询条件 + * @return 项目预算变更明细列表 + */ + List queryList(ErpProjectChangeBudgetBo bo); + + /** + * 新增项目预算变更明细 + * + * @param bo 项目预算变更明细 + * @return 是否新增成功 + */ + Boolean insertByBo(ErpProjectChangeBudgetBo bo); + + /** + * 修改项目预算变更明细 + * + * @param bo 项目预算变更明细 + * @return 是否修改成功 + */ + Boolean updateByBo(ErpProjectChangeBudgetBo 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/IErpProjectChangeProgressService.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectChangeProgressService.java new file mode 100644 index 00000000..91a09826 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectChangeProgressService.java @@ -0,0 +1,69 @@ +package org.dromara.oa.erp.service; + +import org.dromara.oa.erp.domain.ErpProjectChangeProgress; +import org.dromara.oa.erp.domain.vo.ErpProjectChangeProgressVo; +import org.dromara.oa.erp.domain.bo.ErpProjectChangeProgressBo; +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-11-10 + */ +public interface IErpProjectChangeProgressService { + + /** + * 查询项目进度变更明细 + * + * @param changeProgressId 主键 + * @return 项目进度变更明细 + */ + ErpProjectChangeProgressVo queryById(Long changeProgressId); + + /** + * 分页查询项目进度变更明细列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 项目进度变更明细分页列表 + */ + TableDataInfo queryPageList(ErpProjectChangeProgressBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的项目进度变更明细列表 + * + * @param bo 查询条件 + * @return 项目进度变更明细列表 + */ + List queryList(ErpProjectChangeProgressBo bo); + + /** + * 新增项目进度变更明细 + * + * @param bo 项目进度变更明细 + * @return 是否新增成功 + */ + Boolean insertByBo(ErpProjectChangeProgressBo bo); + + /** + * 修改项目进度变更明细 + * + * @param bo 项目进度变更明细 + * @return 是否修改成功 + */ + Boolean updateByBo(ErpProjectChangeProgressBo 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/IErpProjectChangeService.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectChangeService.java new file mode 100644 index 00000000..d51736a7 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectChangeService.java @@ -0,0 +1,85 @@ +package org.dromara.oa.erp.service; + +import org.dromara.oa.erp.domain.ErpProjectChange; +import org.dromara.oa.erp.domain.vo.ErpProjectChangeVo; +import org.dromara.oa.erp.domain.bo.ErpProjectChangeBo; +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-11-10 + */ +public interface IErpProjectChangeService { + + /** + * 查询项目变更申请 + * + * @param projectChangeId 主键 + * @return 项目变更申请 + */ + ErpProjectChangeVo queryById(Long projectChangeId); + + /** + * 分页查询项目变更申请列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 项目变更申请分页列表 + */ + TableDataInfo queryPageList(ErpProjectChangeBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的项目变更申请列表 + * + * @param bo 查询条件 + * @return 项目变更申请列表 + */ + List queryList(ErpProjectChangeBo bo); + + /** + * 新增项目变更申请 + * + * @param bo 项目变更申请 + * @return 是否新增成功 + */ + Boolean insertByBo(ErpProjectChangeBo bo); + + /** + * 修改项目变更申请 + * + * @param bo 项目变更申请 + * @return 是否修改成功 + */ + Boolean updateByBo(ErpProjectChangeBo bo); + + /** + * 校验并批量删除项目变更申请信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 根据项目 ID 准备项目变更信息(带出项目信息和项目计划阶段) + * + * @param projectId 项目 ID + * @return 项目变更信息 + */ + ErpProjectChangeVo prepareByProjectWithInfo(Long projectId); + + /** + * 提交项目变更并发起审批流 + * + * @param bo 项目变更申请 + * @return 是否成功 + */ + ErpProjectChangeVo projectChangeSubmitAndFlowStart(ErpProjectChangeBo bo); +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectChangeBudgetServiceImpl.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectChangeBudgetServiceImpl.java new file mode 100644 index 00000000..e99d253c --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectChangeBudgetServiceImpl.java @@ -0,0 +1,139 @@ +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.ErpProjectChangeBudgetBo; +import org.dromara.oa.erp.domain.vo.ErpProjectChangeBudgetVo; +import org.dromara.oa.erp.domain.ErpProjectChangeBudget; +import org.dromara.oa.erp.mapper.ErpProjectChangeBudgetMapper; +import org.dromara.oa.erp.service.IErpProjectChangeBudgetService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 项目预算变更明细Service业务层处理 + * + * @author Yinq + * @date 2025-11-10 + */ +@RequiredArgsConstructor +@Service +public class ErpProjectChangeBudgetServiceImpl implements IErpProjectChangeBudgetService { + + private final ErpProjectChangeBudgetMapper baseMapper; + + /** + * 查询项目预算变更明细 + * + * @param changeBudgetId 主键 + * @return 项目预算变更明细 + */ + @Override + public ErpProjectChangeBudgetVo queryById(Long changeBudgetId){ + return baseMapper.selectVoById(changeBudgetId); + } + + /** + * 分页查询项目预算变更明细列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 项目预算变更明细分页列表 + */ + @Override + public TableDataInfo queryPageList(ErpProjectChangeBudgetBo 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(ErpProjectChangeBudgetBo bo) { + MPJLambdaWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private MPJLambdaWrapper buildQueryWrapper(ErpProjectChangeBudgetBo bo) { + Map params = bo.getParams(); + MPJLambdaWrapper lqw = JoinWrappers.lambda(ErpProjectChangeBudget.class) + .selectAll(ErpProjectChangeBudget.class) + .eq(ErpProjectChangeBudget::getDelFlag, "0") + .eq(bo.getProjectChangeId() != null, ErpProjectChangeBudget::getProjectChangeId, bo.getProjectChangeId()) + .eq(bo.getBudgetDetailId() != null, ErpProjectChangeBudget::getBudgetDetailId, bo.getBudgetDetailId()) + .like(StringUtils.isNotBlank(bo.getSubjectName()), ErpProjectChangeBudget::getSubjectName, bo.getSubjectName()) + .eq(bo.getBudgetBefore() != null, ErpProjectChangeBudget::getBudgetBefore, bo.getBudgetBefore()) + .eq(bo.getBudgetAfter() != null, ErpProjectChangeBudget::getBudgetAfter, bo.getBudgetAfter()) + .eq(bo.getAmountUsed() != null, ErpProjectChangeBudget::getAmountUsed, bo.getAmountUsed()) + .eq(StringUtils.isNotBlank(bo.getAdjustmentReason()), ErpProjectChangeBudget::getAdjustmentReason, bo.getAdjustmentReason()) + .eq(bo.getSortOrder() != null, ErpProjectChangeBudget::getSortOrder, bo.getSortOrder()); + return lqw; + } + + /** + * 新增项目预算变更明细 + * + * @param bo 项目预算变更明细 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(ErpProjectChangeBudgetBo bo) { + ErpProjectChangeBudget add = MapstructUtils.convert(bo, ErpProjectChangeBudget.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setChangeBudgetId(add.getChangeBudgetId()); + } + return flag; + } + + /** + * 修改项目预算变更明细 + * + * @param bo 项目预算变更明细 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(ErpProjectChangeBudgetBo bo) { + ErpProjectChangeBudget update = MapstructUtils.convert(bo, ErpProjectChangeBudget.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(ErpProjectChangeBudget 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/ErpProjectChangeProgressServiceImpl.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectChangeProgressServiceImpl.java new file mode 100644 index 00000000..101eac47 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectChangeProgressServiceImpl.java @@ -0,0 +1,140 @@ +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.ErpProjectChangeProgressBo; +import org.dromara.oa.erp.domain.vo.ErpProjectChangeProgressVo; +import org.dromara.oa.erp.domain.ErpProjectChangeProgress; +import org.dromara.oa.erp.mapper.ErpProjectChangeProgressMapper; +import org.dromara.oa.erp.service.IErpProjectChangeProgressService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 项目进度变更明细Service业务层处理 + * + * @author Yinq + * @date 2025-11-10 + */ +@RequiredArgsConstructor +@Service +public class ErpProjectChangeProgressServiceImpl implements IErpProjectChangeProgressService { + + private final ErpProjectChangeProgressMapper baseMapper; + + /** + * 查询项目进度变更明细 + * + * @param changeProgressId 主键 + * @return 项目进度变更明细 + */ + @Override + public ErpProjectChangeProgressVo queryById(Long changeProgressId){ + return baseMapper.selectVoById(changeProgressId); + } + + /** + * 分页查询项目进度变更明细列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 项目进度变更明细分页列表 + */ + @Override + public TableDataInfo queryPageList(ErpProjectChangeProgressBo 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(ErpProjectChangeProgressBo bo) { + MPJLambdaWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private MPJLambdaWrapper buildQueryWrapper(ErpProjectChangeProgressBo bo) { + Map params = bo.getParams(); + MPJLambdaWrapper lqw = JoinWrappers.lambda(ErpProjectChangeProgress.class) + .selectAll(ErpProjectChangeProgress.class) + .eq(ErpProjectChangeProgress::getDelFlag, "0") + .eq(bo.getProjectChangeId() != null, ErpProjectChangeProgress::getProjectChangeId, bo.getProjectChangeId()) + .eq(bo.getPlanStageId() != null, ErpProjectChangeProgress::getPlanStageId, bo.getPlanStageId()) + .like(StringUtils.isNotBlank(bo.getMilestoneName()), ErpProjectChangeProgress::getMilestoneName, bo.getMilestoneName()) + .eq(bo.getOriginalStart() != null, ErpProjectChangeProgress::getOriginalStart, bo.getOriginalStart()) + .eq(bo.getOriginalEnd() != null, ErpProjectChangeProgress::getOriginalEnd, bo.getOriginalEnd()) + .eq(bo.getChangedStart() != null, ErpProjectChangeProgress::getChangedStart, bo.getChangedStart()) + .eq(bo.getChangedEnd() != null, ErpProjectChangeProgress::getChangedEnd, bo.getChangedEnd()) + .eq(bo.getCompletionDegree() != null, ErpProjectChangeProgress::getCompletionDegree, bo.getCompletionDegree()) + .eq(bo.getSortOrder() != null, ErpProjectChangeProgress::getSortOrder, bo.getSortOrder()); + return lqw; + } + + /** + * 新增项目进度变更明细 + * + * @param bo 项目进度变更明细 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(ErpProjectChangeProgressBo bo) { + ErpProjectChangeProgress add = MapstructUtils.convert(bo, ErpProjectChangeProgress.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setChangeProgressId(add.getChangeProgressId()); + } + return flag; + } + + /** + * 修改项目进度变更明细 + * + * @param bo 项目进度变更明细 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(ErpProjectChangeProgressBo bo) { + ErpProjectChangeProgress update = MapstructUtils.convert(bo, ErpProjectChangeProgress.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(ErpProjectChangeProgress 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/ErpProjectChangeServiceImpl.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectChangeServiceImpl.java new file mode 100644 index 00000000..f1070935 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectChangeServiceImpl.java @@ -0,0 +1,445 @@ +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.ObjectUtils; +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.*; +import org.dromara.oa.erp.mapper.*; +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.ErpProjectChangeBo; +import org.dromara.oa.erp.domain.vo.ErpProjectChangeVo; +import org.dromara.oa.erp.service.IErpProjectChangeService; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 项目变更申请Service业务层处理 + * + * @author Yinq + * @date 2025-11-10 + */ +@RequiredArgsConstructor +@Service +@Slf4j +public class ErpProjectChangeServiceImpl implements IErpProjectChangeService { + + private final ErpProjectChangeMapper baseMapper; + private final ErpProjectChangeBudgetMapper changeBudgetMapper; + private final ErpProjectChangeProgressMapper changeProgressMapper; + private final ErpProjectInfoMapper projectInfoMapper; + private final ErpProjectPlanMapper projectPlanMapper; + private final ErpProjectPlanStageMapper planStageMapper; + + @DubboReference(timeout = 30000) + private RemoteWorkflowService remoteWorkflowService; + + /** + * 查询项目变更申请 + * + * @param projectChangeId 主键 + * @return 项目变更申请 + */ + @Override + public ErpProjectChangeVo queryById(Long projectChangeId){ + // 使用自定义查询方法,连表查询用户名称 + ErpProjectChangeVo projectChangeVo = baseMapper.selectCustomErpProjectChangeVoById(projectChangeId); + if (ObjectUtils.isEmpty(projectChangeVo)) { + return null; + } + // 查询预算变更明细列表 + MPJLambdaWrapper budgetLqw = JoinWrappers.lambda(ErpProjectChangeBudget.class) + .selectAll(ErpProjectChangeBudget.class) + .eq("t.del_flag", "0") + .eq(projectChangeId != null, ErpProjectChangeBudget::getProjectChangeId, projectChangeId); + List budgetList = changeBudgetMapper.selectList(budgetLqw); + projectChangeVo.setBudgetList(budgetList); + + // 查询进度变更明细列表,连表查询项目计划阶段获取projectPhases + MPJLambdaWrapper progressLqw = JoinWrappers.lambda(ErpProjectChangeProgress.class) + .selectAll(ErpProjectChangeProgress.class) + .selectAs(ErpProjectPlanStage::getProjectPhases, ErpProjectChangeProgress::getProjectPhases) + .leftJoin(ErpProjectPlanStage.class, ErpProjectPlanStage::getPlanStageId, ErpProjectChangeProgress::getPlanStageId) + .eq("t.del_flag", "0") + .eq(projectChangeId != null, ErpProjectChangeProgress::getProjectChangeId, projectChangeId) + .orderByAsc(ErpProjectChangeProgress::getSortOrder); + List progressList = changeProgressMapper.selectList(progressLqw); + projectChangeVo.setProgressList(progressList); + + return projectChangeVo; + } + + /** + * 分页查询项目变更申请列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 项目变更申请分页列表 + */ + @Override + public TableDataInfo queryPageList(ErpProjectChangeBo 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(ErpProjectChangeBo bo) { + MPJLambdaWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private MPJLambdaWrapper buildQueryWrapper(ErpProjectChangeBo bo) { + Map params = bo.getParams(); + MPJLambdaWrapper lqw = JoinWrappers.lambda(ErpProjectChange.class) + .selectAll(ErpProjectChange.class) + .eq(ErpProjectChange::getDelFlag, "0") + .eq(bo.getProjectId() != null, ErpProjectChange::getProjectId, bo.getProjectId()) + .eq(StringUtils.isNotBlank(bo.getProjectCode()), ErpProjectChange::getProjectCode, bo.getProjectCode()) + .like(StringUtils.isNotBlank(bo.getProjectName()), ErpProjectChange::getProjectName, bo.getProjectName()) + .eq(StringUtils.isNotBlank(bo.getProjectCategory()), ErpProjectChange::getProjectCategory, bo.getProjectCategory()) + .eq(StringUtils.isNotBlank(bo.getChangeType()), ErpProjectChange::getChangeType, bo.getChangeType()) + .eq(bo.getChangeNumber() != null, ErpProjectChange::getChangeNumber, bo.getChangeNumber()) + .eq(bo.getProjectManagerId() != null, ErpProjectChange::getProjectManagerId, bo.getProjectManagerId()) + .like(StringUtils.isNotBlank(bo.getProjectManagerName()), ErpProjectChange::getProjectManagerName, bo.getProjectManagerName()) + .eq(bo.getDeptHeadId() != null, ErpProjectChange::getDeptHeadId, bo.getDeptHeadId()) + .like(StringUtils.isNotBlank(bo.getDeptHeadName()), ErpProjectChange::getDeptHeadName, bo.getDeptHeadName()) + .eq(bo.getResponsibleVpId() != null, ErpProjectChange::getResponsibleVpId, bo.getResponsibleVpId()) + .like(StringUtils.isNotBlank(bo.getResponsibleVpName()), ErpProjectChange::getResponsibleVpName, bo.getResponsibleVpName()) + .eq(bo.getApplyChangeDate() != null, ErpProjectChange::getApplyChangeDate, bo.getApplyChangeDate()) + .eq(bo.getContractAmount() != null, ErpProjectChange::getContractAmount, bo.getContractAmount()) + .eq(bo.getContractNetAmount() != null, ErpProjectChange::getContractNetAmount, bo.getContractNetAmount()) + .eq(StringUtils.isNotBlank(bo.getCurrentStatus()), ErpProjectChange::getCurrentStatus, bo.getCurrentStatus()) + .eq(StringUtils.isNotBlank(bo.getChangeReason()), ErpProjectChange::getChangeReason, bo.getChangeReason()) + .eq(StringUtils.isNotBlank(bo.getFollowUpWork()), ErpProjectChange::getFollowUpWork, bo.getFollowUpWork()) + .eq(StringUtils.isNotBlank(bo.getProjectChangeStatus()), ErpProjectChange::getProjectChangeStatus, bo.getProjectChangeStatus()) + .eq(StringUtils.isNotBlank(bo.getFlowStatus()), ErpProjectChange::getFlowStatus, bo.getFlowStatus()) + .eq(StringUtils.isNotBlank(bo.getActiveFlag()), ErpProjectChange::getActiveFlag, bo.getActiveFlag()) +; + return lqw; + } + + /** + * 新增项目变更申请 + * + * @param bo 项目变更申请 + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByBo(ErpProjectChangeBo bo) { + ErpProjectChange add = MapstructUtils.convert(bo, ErpProjectChange.class); + validEntityBeforeSave(add); + + List budgetList = bo.getBudgetList(); + List progressList = bo.getProgressList(); + + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setProjectChangeId(add.getProjectChangeId()); + + // 保存预算变更明细 + if (ObjectUtils.isNotEmpty(budgetList)) { + for (ErpProjectChangeBudget budget : budgetList) { + budget.setProjectChangeId(add.getProjectChangeId()); + changeBudgetMapper.insert(budget); + } + } + + // 保存进度变更明细 + if (ObjectUtils.isNotEmpty(progressList)) { + for (ErpProjectChangeProgress progress : progressList) { + progress.setProjectChangeId(add.getProjectChangeId()); + changeProgressMapper.insert(progress); + } + } + } + return flag; + } + + /** + * 修改项目变更申请 + * + * @param bo 项目变更申请 + * @return 是否修改成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(ErpProjectChangeBo bo) { + ErpProjectChange update = MapstructUtils.convert(bo, ErpProjectChange.class); + validEntityBeforeSave(update); + + List budgetList = bo.getBudgetList(); + List progressList = bo.getProgressList(); + + // 处理预算变更明细 + if (budgetList != null && !budgetList.isEmpty()) { + for (ErpProjectChangeBudget budget : budgetList) { + budget.setProjectChangeId(bo.getProjectChangeId()); + changeBudgetMapper.insertOrUpdate(budget); + } + // 删除前端未提交的旧数据 + Set existingBudgetIds = budgetList.stream() + .map(ErpProjectChangeBudget::getChangeBudgetId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + MPJLambdaWrapper budgetLqw = JoinWrappers.lambda(ErpProjectChangeBudget.class); + budgetLqw.eq(ErpProjectChangeBudget::getProjectChangeId, bo.getProjectChangeId()); + List oldBudgetList = changeBudgetMapper.selectList(budgetLqw); + oldBudgetList.stream() + .filter(budget -> !existingBudgetIds.contains(budget.getChangeBudgetId())) + .forEach(budget -> changeBudgetMapper.deleteById(budget.getChangeBudgetId())); + } + + // 处理进度变更明细 + if (progressList != null && !progressList.isEmpty()) { + for (ErpProjectChangeProgress progress : progressList) { + progress.setProjectChangeId(bo.getProjectChangeId()); + changeProgressMapper.insertOrUpdate(progress); + } + // 删除前端未提交的旧数据 + Set existingProgressIds = progressList.stream() + .map(ErpProjectChangeProgress::getChangeProgressId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + MPJLambdaWrapper progressLqw = JoinWrappers.lambda(ErpProjectChangeProgress.class); + progressLqw.eq(ErpProjectChangeProgress::getProjectChangeId, bo.getProjectChangeId()); + List oldProgressList = changeProgressMapper.selectList(progressLqw); + oldProgressList.stream() + .filter(progress -> !existingProgressIds.contains(progress.getChangeProgressId())) + .forEach(progress -> changeProgressMapper.deleteById(progress.getChangeProgressId())); + } + + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(ErpProjectChange entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除项目变更申请信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @GlobalTransactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + // 先删除子表 + changeBudgetMapper.delete(Wrappers.lambdaQuery().in(ErpProjectChangeBudget::getProjectChangeId, ids)); + changeProgressMapper.delete(Wrappers.lambdaQuery().in(ErpProjectChangeProgress::getProjectChangeId, ids)); + // 删除主表 + baseMapper.deleteByIds(ids); + //删除工作流 + List businessIds = ids.stream().toList(); + return remoteWorkflowService.deleteInstance(businessIds); + } + + /** + * 根据项目 ID 准备项目变更信息(带出项目信息和项目计划阶段) + * + * @param projectId 项目 ID + * @return 项目变更信息 + */ + @Override + public ErpProjectChangeVo prepareByProjectWithInfo(Long projectId) { + if (projectId == null) { + throw new ServiceException("项目ID不能为空"); + } + + // 若存在审批中的项目变更则禁止再次发起 + long approvingCount = baseMapper.selectCount(Wrappers.lambdaQuery() + .eq(ErpProjectChange::getProjectId, projectId) + .eq(ErpProjectChange::getDelFlag, "0") + .eq(ErpProjectChange::getProjectChangeStatus, OAStatusEnum.APPROVING.getStatus()));// "2"审批中,"3"可用 + if (approvingCount > 0) { + throw new ServiceException("该项目存在未完成的变更申请,请等待审批完成后再发起新的变更"); + } + + // 如果已有暂存记录,返回该记录供继续编辑 + ErpProjectChange draftChange = baseMapper.selectOne(Wrappers.lambdaQuery() + .eq(ErpProjectChange::getProjectId, projectId) + .eq(ErpProjectChange::getDelFlag, "0") + .eq(ErpProjectChange::getProjectChangeStatus, "1") + .orderByDesc(ErpProjectChange::getCreateTime) + .last("limit 1")); + if (draftChange != null) { + return queryById(draftChange.getProjectChangeId()); + } + + // 通过自定义Mapper方法查询项目信息和用户名称(连表查询sys_user) + ErpProjectChangeVo vo = baseMapper.prepareByProjectId(projectId); + if (vo == null) { + throw new ServiceException("项目不存在"); + } + + // 查询项目计划信息 + MPJLambdaWrapper planLqw = JoinWrappers.lambda(ErpProjectPlan.class) + .eq(ErpProjectPlan::getProjectId, projectId) + .eq(ErpProjectPlan::getDelFlag, "0"); + ErpProjectPlan projectPlan = projectPlanMapper.selectOne(planLqw); + + if (projectPlan != null) { + // 查询项目计划阶段 + MPJLambdaWrapper stageLqw = JoinWrappers.lambda(ErpProjectPlanStage.class) + .eq(ErpProjectPlanStage::getProjectPlanId, projectPlan.getProjectPlanId()) + .eq(ErpProjectPlanStage::getDelFlag, "0") + .orderByAsc(ErpProjectPlanStage::getSortOrder); + List planStageList = planStageMapper.selectList(stageLqw); + + // 将项目阶段转换为进度变更明细 + if (ObjectUtils.isNotEmpty(planStageList)) { + List progressList = planStageList.stream().map(stage -> { + ErpProjectChangeProgress progress = new ErpProjectChangeProgress(); + progress.setPlanStageId(stage.getPlanStageId()); // 绑定项目计划阶段ID + progress.setProjectPhases(stage.getProjectPhases()); // 项目阶段字典值(禁用显示) + progress.setMilestoneName(""); // 里程碑名称由用户手动输入 + progress.setOriginalStart(stage.getPlanStartTime()); // 原计划开始时间 + progress.setOriginalEnd(stage.getPlanEndTime()); // 原计划结束时间 + progress.setChangedStart(stage.getPlanStartTime()); // 初始值设为原计划时间 + progress.setChangedEnd(stage.getPlanEndTime()); // 初始值设为原计划时间 + progress.setSortOrder(stage.getSortOrder()); // 排序顺序 + return progress; + }).collect(Collectors.toList()); + vo.setProgressList(progressList); + } + } + + // 初始化空的预算变更列表(由用户手动添加) + vo.setBudgetList(new ArrayList<>()); + + // 计算变更次数:查询该项目已完成的变更次数 + MPJLambdaWrapper changeCountLqw = JoinWrappers.lambda(ErpProjectChange.class) + .eq(ErpProjectChange::getProjectId, projectId) + .eq(ErpProjectChange::getDelFlag, "0") + .eq(ErpProjectChange::getProjectChangeStatus, OAStatusEnum.COMPLETED.getStatus()); + int changeCount = Math.toIntExact(baseMapper.selectCount(changeCountLqw)); + + vo.setChangeNumber(changeCount + 1); // 当前变更次数 = 已有次数 + 1 + + // 设置默认值 + vo.setActiveFlag("1"); + vo.setProjectChangeStatus("1"); // 1-暂存 + + return vo; + } + + /** + * 提交项目变更并发起审批流 + * + * @param bo 项目变更申请 + * @return 是否成功 + */ + @Override + @GlobalTransactional(rollbackFor = Exception.class) + public ErpProjectChangeVo projectChangeSubmitAndFlowStart(ErpProjectChangeBo bo) { + + ErpProjectChange add = MapstructUtils.convert(bo, ErpProjectChange.class); + validEntityBeforeSave(add) ; + // 权限校验:只有项目经理才能提交 + validateProjectManager(bo.getProjectManagerId()); + + // 保存或更新项目变更数据 + boolean saveFlag; + if (bo.getProjectChangeId() == null) { + saveFlag = insertByBo(bo); + } else { + saveFlag = updateByBo(bo); + } + + if (!saveFlag) { + throw new ServiceException("保存项目变更失败"); + } + + // 后端发起需要忽略权限 + bo.getVariables().put("ignore", true); + RemoteStartProcess startProcess = new RemoteStartProcess(); + startProcess.setBusinessId(bo.getProjectChangeId().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, ErpProjectChangeVo.class); + } + + /** + * 项目变更流程监听器 + * + * @param processEvent 流程事件 + */ + @EventListener(condition = "#processEvent.flowCode == 'OAEP'") + public void processHandler(ProcessEvent processEvent) { + TenantHelper.dynamic(processEvent.getTenantId(), () -> { + ErpProjectChange projectChange = baseMapper.selectById(Convert.toLong(processEvent.getBusinessId())); + projectChange.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())){ + projectChange.setProjectChangeStatus(OAStatusEnum.COMPLETED.getStatus()); + } + baseMapper.updateById(projectChange); + }); + } + + /** + * 校验项目经理权限 + * + * @param projectManagerId 项目经理ID + */ + private void validateProjectManager(Long projectManagerId) { + // 超级管理员跳过校验 + if (LoginHelper.isSuperAdmin()) { + return; + } + + Long currentUserId = LoginHelper.getUserId(); + if (!currentUserId.equals(projectManagerId)) { + throw new ServiceException("只有项目经理才能提交项目变更申请"); + } + } +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectChangeBudgetMapper.xml b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectChangeBudgetMapper.xml new file mode 100644 index 00000000..3ab6fbb0 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectChangeBudgetMapper.xml @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + insert into erp_project_change_budget( + project_change_id, + + budget_detail_id, + + subject_name, + + budget_before, + + budget_after, + + amount_used, + + adjustment_reason, + + sort_order, + + remark, + + del_flag, + + create_dept, + + create_by, + + create_time, + + update_by, + + update_time + + ) + values + + ( + #{item.projectChangeId}, + + #{item.budgetDetailId}, + + #{item.subjectName}, + + #{item.budgetBefore}, + + #{item.budgetAfter}, + + #{item.amountUsed}, + + #{item.adjustmentReason}, + + #{item.sortOrder}, + + #{item.remark}, + + #{item.delFlag}, + + #{item.createDept}, + + #{item.createBy}, + + #{item.createTime}, + + #{item.updateBy}, + + #{item.updateTime} + + ) + + + + + + + update erp_project_change_budget + + + project_change_id = #{item.projectChangeId}, + + + budget_detail_id = #{item.budgetDetailId}, + + + subject_name = #{item.subjectName}, + + + budget_before = #{item.budgetBefore}, + + + budget_after = #{item.budgetAfter}, + + + amount_used = #{item.amountUsed}, + + + adjustment_reason = #{item.adjustmentReason}, + + + sort_order = #{item.sortOrder}, + + + remark = #{item.remark}, + + + 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 change_budget_id = #{item.changeBudgetId} + + + + + + delete from erp_project_change_budget + ${ew.getCustomSqlSegment} + + + + + delete from erp_project_change_budget + where change_budget_id in + + #{id} + + + + + + + + diff --git a/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectChangeMapper.xml b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectChangeMapper.xml new file mode 100644 index 00000000..d9e7e207 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectChangeMapper.xml @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + insert into erp_project_change( + tenant_id, + + project_id, + + project_code, + + project_name, + + project_category, + + change_type, + + change_number, + + project_manager_id, + + project_manager_name, + + dept_head_id, + + dept_head_name, + + responsible_vp_id, + + responsible_vp_name, + + apply_change_date, + + contract_amount, + + contract_net_amount, + + current_status, + + change_reason, + + follow_up_work, + + project_change_status, + + flow_status, + + remark, + + active_flag, + + del_flag, + + create_dept, + + create_by, + + create_time, + + update_by, + + update_time + + ) + values + + ( + #{item.tenantId}, + + #{item.projectId}, + + #{item.projectCode}, + + #{item.projectName}, + + #{item.projectCategory}, + + #{item.changeType}, + + #{item.changeNumber}, + + #{item.projectManagerId}, + + #{item.projectManagerName}, + + #{item.deptHeadId}, + + #{item.deptHeadName}, + + #{item.responsibleVpId}, + + #{item.responsibleVpName}, + + #{item.applyChangeDate}, + + #{item.contractAmount}, + + #{item.contractNetAmount}, + + #{item.currentStatus}, + + #{item.changeReason}, + + #{item.followUpWork}, + + #{item.projectChangeStatus}, + + #{item.flowStatus}, + + #{item.remark}, + + #{item.activeFlag}, + + #{item.delFlag}, + + #{item.createDept}, + + #{item.createBy}, + + #{item.createTime}, + + #{item.updateBy}, + + #{item.updateTime} + + ) + + + + + + + update erp_project_change + + + tenant_id = #{item.tenantId}, + + + project_id = #{item.projectId}, + + + project_code = #{item.projectCode}, + + + project_name = #{item.projectName}, + + + project_category = #{item.projectCategory}, + + + change_type = #{item.changeType}, + + + change_number = #{item.changeNumber}, + + + project_manager_id = #{item.projectManagerId}, + + + project_manager_name = #{item.projectManagerName}, + + + dept_head_id = #{item.deptHeadId}, + + + dept_head_name = #{item.deptHeadName}, + + + responsible_vp_id = #{item.responsibleVpId}, + + + responsible_vp_name = #{item.responsibleVpName}, + + + apply_change_date = #{item.applyChangeDate}, + + + contract_amount = #{item.contractAmount}, + + + contract_net_amount = #{item.contractNetAmount}, + + + current_status = #{item.currentStatus}, + + + change_reason = #{item.changeReason}, + + + follow_up_work = #{item.followUpWork}, + + + project_change_status = #{item.projectChangeStatus}, + + + flow_status = #{item.flowStatus}, + + + 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_change_id = #{item.projectChangeId} + + + + + + delete from erp_project_change + ${ew.getCustomSqlSegment} + + + + + delete from erp_project_change + where project_change_id in + + #{id} + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectChangeProgressMapper.xml b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectChangeProgressMapper.xml new file mode 100644 index 00000000..bd47a671 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectChangeProgressMapper.xml @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + insert into erp_project_change_progress( + project_change_id, + + plan_stage_id, + + milestone_name, + + original_start, + + original_end, + + changed_start, + + changed_end, + + completion_degree, + + sort_order, + + remark, + + del_flag, + + create_dept, + + create_by, + + create_time, + + update_by, + + update_time + + ) + values + + ( + #{item.projectChangeId}, + + #{item.planStageId}, + + #{item.milestoneName}, + + #{item.originalStart}, + + #{item.originalEnd}, + + #{item.changedStart}, + + #{item.changedEnd}, + + #{item.completionDegree}, + + #{item.sortOrder}, + + #{item.remark}, + + #{item.delFlag}, + + #{item.createDept}, + + #{item.createBy}, + + #{item.createTime}, + + #{item.updateBy}, + + #{item.updateTime} + + ) + + + + + + + update erp_project_change_progress + + + project_change_id = #{item.projectChangeId}, + + + plan_stage_id = #{item.planStageId}, + + + milestone_name = #{item.milestoneName}, + + + original_start = #{item.originalStart}, + + + original_end = #{item.originalEnd}, + + + changed_start = #{item.changedStart}, + + + changed_end = #{item.changedEnd}, + + + completion_degree = #{item.completionDegree}, + + + sort_order = #{item.sortOrder}, + + + remark = #{item.remark}, + + + 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 change_progress_id = #{item.changeProgressId} + + + + + + delete from erp_project_change_progress + ${ew.getCustomSqlSegment} + + + + + delete from erp_project_change_progress + where change_progress_id in + + #{id} + + + + + + + + diff --git a/ruoyi-modules/ruoyi-oa/src/main/resources/报价单模板.md b/ruoyi-modules/ruoyi-oa/src/main/resources/报价单模板.md new file mode 100644 index 00000000..a89b2473 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/resources/报价单模板.md @@ -0,0 +1,22 @@ +致: +{customerContactName} +{title} +报价日期 {quoteDate} +含税信息 {taxIncludedInfo} +付款方式 {paymentMethod} +交货期 {deliveryPeriod} +交货方式 {deliveryMethod} +报价有效期 {quoteValidity} + 币种:{currencyType} 价格单位:元 +序号 产品名称 型号/说明 数量 单位 单价 小计 备注 +{data.seq} {data.productName} {data.modelDesc} {data.quantity} {data.unit} {data.price} {data.subtotal} {data.remark} + +合计 {total} + 小写: {totalLower} 大写: {totalUpper} +注: +"供货方信息: +公司名称:青岛海威物联科技有限公司 +公司地址:青岛市市北区郑州路43号 +公司网址:www.highwayiot.com " " 联 系 人: +联系电话: +电子邮件:" diff --git a/ruoyi-modules/ruoyi-oa/src/main/resources/报价单模板.xlsx b/ruoyi-modules/ruoyi-oa/src/main/resources/报价单模板.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c448f1f5c7debdbb810b5430cb15fd9c91fe75e9 GIT binary patch literal 79471 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ŗG9?1=pWxvn$L4 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

B*F#M0J-IpskR*-~wKM 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 Oygq>|S2S3UVgCZNN|v4g literal 0 HcmV?d00001