diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteDeptService.java b/ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteDeptService.java index 7a852341..950cfbf3 100644 --- a/ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteDeptService.java +++ b/ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteDeptService.java @@ -51,4 +51,5 @@ public interface RemoteDeptService { */ Map selectDeptNamesByIds(List deptIds); + Long selectDeptGeneralManagerById(Long deptId); } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/controller/CrmFlightBookingController.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/controller/CrmFlightBookingController.java index c741c095..5af57dd4 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/controller/CrmFlightBookingController.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/controller/CrmFlightBookingController.java @@ -6,6 +6,8 @@ import lombok.RequiredArgsConstructor; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.constraints.*; import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.oa.erp.domain.bo.ErpTimesheetInfoBo; +import org.dromara.oa.erp.domain.vo.ErpTimesheetInfoVo; import org.springframework.web.bind.annotation.*; import org.springframework.validation.annotation.Validated; import org.dromara.common.idempotent.annotation.RepeatSubmit; @@ -107,10 +109,19 @@ public class CrmFlightBookingController extends BaseController { /** * 下拉框查询机票预订列表 */ - @GetMapping("/getCrmFlightBookingList") - public R> getCrmFlightBookingList(CrmFlightBookingBo bo) { + @GetMapping("/getCrmFlightBookingList") public R> getCrmFlightBookingList(CrmFlightBookingBo bo) { List list = crmFlightBookingService.queryList(bo); return R.ok(list); } + /** + * 提交机票预订填报并提交流程 + */ + @SaCheckPermission("oa/crm:flightBooking:add") + @Log(title = "机票预订", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/submitAndFlowStart") + public R submitAndFlowStart(@Validated(AddGroup.class) @RequestBody CrmFlightBookingBo bo) { + return R.ok(crmFlightBookingService.submitAndFlowStart(bo)); + } } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/CrmFlightBooking.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/CrmFlightBooking.java index e7407c48..e00a1f3a 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/CrmFlightBooking.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/CrmFlightBooking.java @@ -26,7 +26,7 @@ public class CrmFlightBooking extends TenantEntity { /** * 机票预订ID */ - @TableId(value = "booking_id", type = IdType.AUTO) + @TableId(value = "booking_id", type = IdType.ASSIGN_ID) private Long bookingId; /** diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/bo/CrmFlightBookingBo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/bo/CrmFlightBookingBo.java index 24c00341..b07373d8 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/bo/CrmFlightBookingBo.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/bo/CrmFlightBookingBo.java @@ -104,6 +104,10 @@ public class CrmFlightBookingBo extends BaseEntity { * 办理人(可不填 用于覆盖当前节点办理人) */ private String handler; + /** + * 流程定义编码 + */ + private String flowCode; /** * 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/ICrmFlightBookingService.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/ICrmFlightBookingService.java index d42600b1..da6d2cf2 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/ICrmFlightBookingService.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/ICrmFlightBookingService.java @@ -5,6 +5,7 @@ import org.dromara.oa.crm.domain.vo.CrmFlightBookingVo; import org.dromara.oa.crm.domain.bo.CrmFlightBookingBo; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.oa.erp.domain.vo.ErpTimesheetInfoVo; import java.util.Collection; import java.util.List; @@ -66,4 +67,6 @@ public interface ICrmFlightBookingService { * @return 是否删除成功 */ Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + CrmFlightBookingVo submitAndFlowStart(CrmFlightBookingBo bo); } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/impl/CrmFlightBookingServiceImpl.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/impl/CrmFlightBookingServiceImpl.java index ee3fc8a9..4fb02b49 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/impl/CrmFlightBookingServiceImpl.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/impl/CrmFlightBookingServiceImpl.java @@ -1,5 +1,13 @@ package org.dromara.oa.crm.service.impl; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.map.MapUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.dubbo.config.annotation.DubboReference; +import org.apache.seata.spring.annotation.GlobalTransactional; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.enums.OAStatusEnum; +import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.core.page.TableDataInfo; @@ -9,6 +17,13 @@ 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.ErpProjectPlan; +import org.dromara.oa.erp.domain.vo.ErpProjectPlanVo; +import org.dromara.workflow.api.RemoteWorkflowService; +import org.dromara.workflow.api.domain.RemoteStartProcess; +import org.dromara.workflow.api.event.ProcessEvent; +import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import org.dromara.oa.crm.domain.bo.CrmFlightBookingBo; import org.dromara.oa.crm.domain.vo.CrmFlightBookingVo; @@ -16,9 +31,7 @@ import org.dromara.oa.crm.domain.CrmFlightBooking; import org.dromara.oa.crm.mapper.CrmFlightBookingMapper; import org.dromara.oa.crm.service.ICrmFlightBookingService; -import java.util.List; -import java.util.Map; -import java.util.Collection; +import java.util.*; /** * 机票预订Service业务层处理 @@ -28,10 +41,14 @@ import java.util.Collection; */ @RequiredArgsConstructor @Service +@Slf4j public class CrmFlightBookingServiceImpl implements ICrmFlightBookingService { private final CrmFlightBookingMapper baseMapper; + @DubboReference(timeout = 30000) + private RemoteWorkflowService remoteWorkflowService; + /** * 查询机票预订 * @@ -140,4 +157,66 @@ public class CrmFlightBookingServiceImpl implements ICrmFlightBookingService { } return baseMapper.deleteByIds(ids) > 0; } + /** + * 机票预订并提交 + * + * + * + */ + @Override + @GlobalTransactional(rollbackFor = Exception.class) + public CrmFlightBookingVo submitAndFlowStart(CrmFlightBookingBo bo) { + CrmFlightBooking add = MapstructUtils.convert(bo, CrmFlightBooking.class); + validEntityBeforeSave(add); + + if (StringUtils.isNull(bo.getBookingId())) { + this.insertByBo(bo); + } else { + this.updateByBo(bo); + } + // 后端发起需要忽略权限 + bo.getVariables().put("ignore", true); + RemoteStartProcess startProcess = new RemoteStartProcess(); + startProcess.setBusinessId(bo.getBookingId().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, CrmFlightBookingVo.class); + } + /** + * 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成等) + * + * @param processEvent 参数 + */ + @EventListener(condition = "#processEvent.flowCode =='JPYD'") + public void processHandler(ProcessEvent processEvent) { + TenantHelper.dynamic(processEvent.getTenantId(), () -> { + log.info("当前任务执行了{}", processEvent.toString()); + CrmFlightBooking crmFlightBooking = baseMapper.selectById(Convert.toLong(processEvent.getBusinessId())); + crmFlightBooking.setFlowStatus(processEvent.getStatus()); + Map params = processEvent.getParams(); + if (MapUtil.isNotEmpty(params)) { + // 办理人 + String handler = Convert.toStr(params.get("handler")); + } + if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.WAITING.getStatus())) { + crmFlightBooking.setBookingStatus(OAStatusEnum.APPROVING.getStatus()); + } else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.FINISH.getStatus())) { + crmFlightBooking.setBookingStatus(OAStatusEnum.COMPLETED.getStatus()); + } else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.INVALID.getStatus()) + || Objects.equals(processEvent.getStatus(), BusinessStatusEnum.TERMINATION.getStatus())) { + crmFlightBooking.setBookingStatus(OAStatusEnum.INVALID.getStatus()); + } else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.BACK.getStatus()) + || Objects.equals(processEvent.getStatus(), BusinessStatusEnum.CANCEL.getStatus())) { + // 流程驳回:业务状态还原为草稿,允许重新编辑和提交 + crmFlightBooking.setBookingStatus(OAStatusEnum.DRAFT.getStatus()); + } + baseMapper.updateById(crmFlightBooking); + }); + } } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectReportDetail.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectReportDetail.java index a8740358..61343a08 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectReportDetail.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectReportDetail.java @@ -137,5 +137,13 @@ public class ErpProjectReportDetail extends TenantEntity { @TableLogic private String delFlag; + /** + * 开始日期 + */ + private Date beginDate; + /** + * 结束日期 + */ + private Date endDate; } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectReportDetailBo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectReportDetailBo.java index e775aa1d..9fdaec73 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectReportDetailBo.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectReportDetailBo.java @@ -180,5 +180,13 @@ public class ErpProjectReportDetailBo extends BaseEntity { return bizExt; } + /** + * 开始日期 + */ + private Date beginDate; + /** + * 结束日期 + */ + private Date endDate; } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectReportDetailVo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectReportDetailVo.java index 8ca525b9..9725d6a0 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectReportDetailVo.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectReportDetailVo.java @@ -181,6 +181,18 @@ public class ErpProjectReportDetailVo extends BaseEntity implements Serializable @ExcelDictFormat(readConverterExp = "1=是,0=否") private String activeFlag; + /** + * 开始日期 + */ + @ExcelProperty(value = "开始日期") + @ColumnWidth(20) // 设置列宽为20个字符 + private Date beginDate; + /** + * 结束日期 + */ + @ExcelProperty(value = "结束日期") + @ColumnWidth(20) // 设置列宽为20个字符 + private Date endDate; } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectReportDetailServiceImpl.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectReportDetailServiceImpl.java index 91f2a820..15873b72 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectReportDetailServiceImpl.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectReportDetailServiceImpl.java @@ -16,6 +16,7 @@ import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.oa.erp.domain.ErpProjectReport; import org.dromara.oa.erp.domain.ErpProjectReportDetail; import org.dromara.oa.erp.domain.bo.ErpProjectReportBo; import org.dromara.oa.erp.domain.bo.ErpProjectReportDetailBo; @@ -230,6 +231,8 @@ public class ErpProjectReportDetailServiceImpl implements IErpProjectReportDetai log.info("当前任务执行了{}", processEvent.toString()); ErpProjectReportDetail projectReportDetail = baseMapper.selectById(Convert.toLong(processEvent.getBusinessId())); projectReportDetail.setFlowStatus(processEvent.getStatus()); + ErpProjectReportBo projectReportBo = new ErpProjectReportBo(); + projectReportBo.setReportId(projectReportDetail.getReportId()); Map params = processEvent.getParams(); if (MapUtil.isNotEmpty(params)) { // 办理人 @@ -237,16 +240,21 @@ public class ErpProjectReportDetailServiceImpl implements IErpProjectReportDetai } if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.WAITING.getStatus())) { projectReportDetail.setProjectReportStatus(OAStatusEnum.APPROVING.getStatus()); + projectReportBo.setStatus(OAStatusEnum.APPROVING.getStatus()); } else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.FINISH.getStatus())) { projectReportDetail.setProjectReportStatus(OAStatusEnum.COMPLETED.getStatus()); + projectReportBo.setStatus((OAStatusEnum.COMPLETED.getStatus())); } else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.INVALID.getStatus()) || Objects.equals(processEvent.getStatus(), BusinessStatusEnum.TERMINATION.getStatus())) { projectReportDetail.setProjectReportStatus(OAStatusEnum.INVALID.getStatus()); + projectReportBo.setStatus(OAStatusEnum.INVALID.getStatus()); } else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.BACK.getStatus()) || Objects.equals(processEvent.getStatus(), BusinessStatusEnum.CANCEL.getStatus())) { projectReportDetail.setProjectReportStatus(OAStatusEnum.DRAFT.getStatus()); + projectReportBo.setStatus(OAStatusEnum.DRAFT.getStatus()); } baseMapper.updateById(projectReportDetail); + erpProjectReportService.updateByBo(projectReportBo); }); } /** diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java index 2b0bdbe7..3de4276a 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java @@ -98,5 +98,16 @@ public class RemoteDeptServiceImpl implements RemoteDeptService { ); return StreamUtils.toMap(list, SysDept::getDeptId, SysDept::getDeptName); } + /** + * 根据部门ID查询总经理 + * + * @param deptId 部门ID,用于指定需要查询的部门 + * @return 返回该部门的分管副总ID + */ + @Override + public Long selectDeptGeneralManagerById(Long deptId) { + SysDeptVo vo = deptService.getTopDeptFirstChild(deptId); + return vo.getLeader(); + } } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java index 0a7cda22..1b585aaf 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java @@ -146,4 +146,6 @@ public interface ISysDeptService { List selectAllListDept(SysDeptBo dept); + + SysDeptVo getTopDeptFirstChild(Long deptId); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java index 01b37f29..75128962 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java @@ -387,4 +387,54 @@ public class SysDeptServiceImpl implements ISysDeptService { return baseMapper.selectVoList(lqw); } + /** + * 根据部门ID,获取其所属分支的“一级子部门”的完整信息。 + * + * @param deptId 当前部门ID + * @return 目标部门的Vo对象 + */ + @Override + public SysDeptVo getTopDeptFirstChild(Long deptId) { + SysDeptVo dept = baseMapper.selectVoById(deptId); + if (ObjectUtil.isNull(dept)) { + return null; + } + // 2. 解析 ancestors 字段 + String ancestors = dept.getAncestors(); + if (StringUtils.isEmpty(ancestors)) { + // 无祖级列表,自身可视为顶级,返回自身 + return dept; + } + // 3. 分割祖先路径为ID数组 + // 注意:确认分隔符是逗号(根据您的代码 StringUtils.SEPARATOR 推断) + String[] ancestorIdArray = ancestors.split(StringUtils.SEPARATOR); + // 4. 核心逻辑判断 + if (ancestorIdArray.length == 0) { + return dept; + } else if (ancestorIdArray.length == 1) { + // 情况A:ancestors只有一个ID(即自身ID) + // 检查这个ID是否等于parentId。如果相等,说明它就是顶级部门(root)。 + Long ancestorId = Convert.toLong(ancestorIdArray[0]); + if (ObjectUtil.notEqual(ancestorId, dept.getParentId())) { + // 实际上,对于根部门,parentId通常为0或null,ancestors应为空或仅自身。 + // 此分支为逻辑兜底。 + } + // 根据需求:本身就是顶级部门,返回自身 + return dept; + } else { + // 情况B:ancestors有多个ID(例如:100,101,102) + // 第一个ID (ancestorIdArray[0]) 是顶级部门(root)。 + // 我们需要的是第二个ID,它是顶级部门的直接下属,也是当前部门所在分支的“一级子部门”。 + String firstChildIdStr = ancestorIdArray[1]; // 索引 1 是第二个元素 + if (StringUtils.isNotBlank(firstChildIdStr)) { + Long id = Convert.toLong(firstChildIdStr); + SysDeptVo firstChildDept = baseMapper.selectVoById(id); + return firstChildDept; + } else { + + return dept; + } + } + } + } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/rule/SpelRuleComponent.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/rule/SpelRuleComponent.java index b84a5850..5d49939c 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/rule/SpelRuleComponent.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/rule/SpelRuleComponent.java @@ -87,5 +87,15 @@ public class SpelRuleComponent { return BUSINESS_DIRECTION_TO_USERNAME.get(businessDirection); } + /** + * 通过发起人部门id获取总经理 + */ + public Long selectDeptGeneralManagerById(Long initiatorDeptId) { + Long generalManagerId = deptService.selectDeptGeneralManagerById(initiatorDeptId); + if (ObjectUtil.isNull(generalManagerId)) { + throw new ServiceException("当前部门未设置总经理,请联系管理员操作。"); + } + return generalManagerId; + } }