[feat] 新增项目信息管理模块业务流程表单

This commit is contained in:
hhyykk 2024-07-07 16:00:38 +08:00
parent 8bfc2a8ef8
commit 55e5265152
11 changed files with 116 additions and 30 deletions

View File

@ -6,9 +6,16 @@ package cn.iocoder.yudao.module.pms.enums;
* @date 2024/7/3 * @date 2024/7/3
*/ */
public interface DictTypeConstants { public interface DictTypeConstants {
// ***** 字典名称 ******
String PROJECT_TYPE = "project_type"; // 项目类型 String PROJECT_TYPE = "project_type"; // 项目类型
String ENTRUST_METHOD = "entrust_method"; // 委托方式 String ENTRUST_METHOD = "entrust_method"; // 委托方式
String INFRA_BOOLEAN_STRING = "infra_boolean_string"; // 布尔 String INFRA_BOOLEAN_STRING = "infra_boolean_string"; // 布尔
String PROCESS_STATUS = "process_status"; // 流程状态 String PROCESS_STATUS = "process_status"; // 流程状态
String POSSIBILITY_OF_LANDING = "possibility_of_landing"; // 可能性 String POSSIBILITY_OF_LANDING = "possibility_of_landing"; // 可能性
String BPM_PROCESS_INSTANCE_STATUS = "bpm_process_instance_status"; // 流程实例状态
} }

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.module.pms.enums;
/**
* @author hhyykk
* @description 委托方式枚举
* @date 2024/7/6
*/
public interface EntrustMethodConstants {
// **** 字典值 ******
String ENTRUST_PUBLIC_BIDDING = "public_bidding"; // 公开招标
String ENTRUST_DIRECT_DELEGATION = "public_direct_delegation"; // 直接委托
String ENTRUST_INVITED_BIDDING = "invited_bidding"; // 邀请招标
}

View File

@ -25,6 +25,7 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*; import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import cn.iocoder.yudao.module.pms.controller.admin.project.vo.*; import cn.iocoder.yudao.module.pms.controller.admin.project.vo.*;
import cn.iocoder.yudao.module.pms.dal.dataobject.project.ProjectDO; import cn.iocoder.yudao.module.pms.dal.dataobject.project.ProjectDO;
@ -43,7 +44,7 @@ public class ProjectController {
@Operation(summary = "创建项目基本信息") @Operation(summary = "创建项目基本信息")
@PreAuthorize("@ss.hasPermission('pms:project:create')") @PreAuthorize("@ss.hasPermission('pms:project:create')")
public CommonResult<Long> createProject(@Valid @RequestBody ProjectSaveReqVO createReqVO) { public CommonResult<Long> createProject(@Valid @RequestBody ProjectSaveReqVO createReqVO) {
return success(projectService.createProject(createReqVO)); return success(projectService.createProject(getLoginUserId(),createReqVO));
} }
@PutMapping("/update") @PutMapping("/update")

View File

@ -73,8 +73,8 @@ public class ProjectRespDetailVO {
private String reason; private String reason;
@Schema(description = "审批状态", example = "doing") @Schema(description = "审批状态", example = "doing")
@DictFormat(DictTypeConstants.PROCESS_STATUS) @DictFormat(DictTypeConstants.BPM_PROCESS_INSTANCE_STATUS)
private String processStatus; private Integer processStatus;
@Schema(description = "状态", example = "doing") @Schema(description = "状态", example = "doing")
private String status; private String status;

View File

@ -52,4 +52,10 @@ public class ProjectRespVO {
@Schema(description = "客户公司", example = "26238") @Schema(description = "客户公司", example = "26238")
@ExcelProperty("客户公司") @ExcelProperty("客户公司")
private String customerCompanyName; private String customerCompanyName;
@Schema(description = "流程实体id", example = "26238")
private String processInstanceId;
@Schema(description = "委托方式", example = "public_bidding")
private String entrustMethod;
} }

View File

@ -21,7 +21,7 @@ public class ProjectSaveReqVO {
@Schema(description = "项目编号") @Schema(description = "项目编号")
private String code; private String code;
@Schema(description = "客户联系人") @Schema(description = "客户联系人", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
private String customerUser; private String customerUser;
@Schema(description = "出图公司", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "出图公司", requiredMode = Schema.RequiredMode.REQUIRED)
@ -51,19 +51,19 @@ public class ProjectSaveReqVO {
private String reason; private String reason;
@Schema(description = "审批状态", example = "2") @Schema(description = "审批状态", example = "2")
private String processStatus; private Integer processStatus;
@Schema(description = "跟踪编号") @Schema(description = "跟踪编号", requiredMode = Schema.RequiredMode.REQUIRED)
private String trackingCode; private String trackingCode;
@Schema(description = "类型", example = "1") @Schema(description = "类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private String type; private String type;
@Schema(description = "客户公司id", requiredMode = Schema.RequiredMode.REQUIRED, example = "12216") @Schema(description = "客户公司id", requiredMode = Schema.RequiredMode.REQUIRED, example = "12216")
@NotNull(message = "客户公司id不能为空") @NotNull(message = "客户公司id不能为空")
private Long customerCompanyId; private Long customerCompanyId;
@Schema(description = "项目经理id", example = "26238") @Schema(description = "项目经理id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26238")
private Long projectManagerId; private Long projectManagerId;
@Schema(description = "开始时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ -82,17 +82,17 @@ public class ProjectSaveReqVO {
@Schema(description = "中标附件", example = "https://www.iocoder.cn") @Schema(description = "中标附件", example = "https://www.iocoder.cn")
private List<String> winFileUrl; private List<String> winFileUrl;
@Schema(description = "预计合同金额") @Schema(description = "预计合同金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
private String contractAmount; private String contractAmount;
@Schema(description = "客户电话", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "客户电话", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "客户电话不能为空") @NotEmpty(message = "客户电话不能为空")
private String customerPhone; private String customerPhone;
@Schema(description = "省份id", example = "25195") @Schema(description = "省份id", requiredMode = Schema.RequiredMode.REQUIRED, example = "25195")
private Long provinceId; private Long provinceId;
@Schema(description = "城市id", example = "23899") @Schema(description = "城市id", requiredMode = Schema.RequiredMode.REQUIRED, example = "23899")
private Long cityId; private Long cityId;
} }

View File

@ -97,7 +97,7 @@ public class ProjectDO extends BaseDO {
* *
* 枚举 {@link DictTypeConstants} * 枚举 {@link DictTypeConstants}
*/ */
private String processStatus; private Integer processStatus;
/** /**
* 状态 * 状态
*/ */

View File

@ -1,13 +1,10 @@
package cn.iocoder.yudao.module.pms.service.project; package cn.iocoder.yudao.module.pms.service.project;
import java.util.*;
import cn.iocoder.yudao.module.pms.dal.dataobject.project.ProjectDetailDO; import cn.iocoder.yudao.module.pms.dal.dataobject.project.ProjectDetailDO;
import jakarta.validation.*; import jakarta.validation.*;
import cn.iocoder.yudao.module.pms.controller.admin.project.vo.*; import cn.iocoder.yudao.module.pms.controller.admin.project.vo.*;
import cn.iocoder.yudao.module.pms.dal.dataobject.project.ProjectDO; import cn.iocoder.yudao.module.pms.dal.dataobject.project.ProjectDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
/** /**
* 项目基本信息 Service 接口 * 项目基本信息 Service 接口
@ -19,10 +16,11 @@ public interface ProjectService {
/** /**
* 创建项目基本信息 * 创建项目基本信息
* *
* @param loginUserId 登录用户id
* @param createReqVO 创建信息 * @param createReqVO 创建信息
* @return 编号 * @return 编号
*/ */
Long createProject(@Valid ProjectSaveReqVO createReqVO); Long createProject(Long loginUserId, @Valid ProjectSaveReqVO createReqVO);
/** /**
* 更新项目基本信息 * 更新项目基本信息
@ -68,4 +66,11 @@ public interface ProjectService {
* @return 基本信息 * @return 基本信息
*/ */
ProjectDetailDO getProjectDetail(Long id); ProjectDetailDO getProjectDetail(Long id);
/**
* 更新项目立项状态
* @param id 编号
* @param status 结果
*/
void updateProjectStatus(Long id, Integer status);
} }

View File

@ -1,17 +1,17 @@
package cn.iocoder.yudao.module.pms.service.project; package cn.iocoder.yudao.module.pms.service.project;
import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.pms.dal.dataobject.project.ProjectDetailDO; import cn.iocoder.yudao.module.pms.dal.dataobject.project.ProjectDetailDO;
import cn.iocoder.yudao.module.pms.enums.EntrustMethodConstants;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import cn.iocoder.yudao.module.pms.controller.admin.project.vo.*; import cn.iocoder.yudao.module.pms.controller.admin.project.vo.*;
import cn.iocoder.yudao.module.pms.dal.dataobject.project.ProjectDO; import cn.iocoder.yudao.module.pms.dal.dataobject.project.ProjectDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.pms.dal.mysql.project.ProjectMapper; import cn.iocoder.yudao.module.pms.dal.mysql.project.ProjectMapper;
@ -28,15 +28,38 @@ import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstants.*;
@Validated @Validated
public class ProjectServiceImpl implements ProjectService { public class ProjectServiceImpl implements ProjectService {
/**
* 项目立项审批流程定义
*/
public static final String PROCESS_KEY = "pms_project_init";
@Resource @Resource
private ProjectMapper projectMapper; private ProjectMapper projectMapper;
@Resource
private BpmProcessInstanceApi processInstanceApi;
@Override @Override
public Long createProject(ProjectSaveReqVO createReqVO) { public Long createProject(Long loginUserId, ProjectSaveReqVO createReqVO) {
// 非公开招标或者邀请招标的无需审批
if (!EntrustMethodConstants.ENTRUST_PUBLIC_BIDDING.equals(createReqVO.getEntrustMethod()) &&
!EntrustMethodConstants.ENTRUST_INVITED_BIDDING.equals(createReqVO.getEntrustMethod())) {
createReqVO.setProcessStatus(2); //审批通过
}
// 插入 // 插入
ProjectDO project = BeanUtils.toBean(createReqVO, ProjectDO.class); ProjectDO project = BeanUtils.toBean(createReqVO, ProjectDO.class);
projectMapper.insert(project); projectMapper.insert(project);
// todo 启动流程 // 启动流程
if (createReqVO.getId() == null) {
if (EntrustMethodConstants.ENTRUST_PUBLIC_BIDDING.equals(project.getEntrustMethod()) ||
EntrustMethodConstants.ENTRUST_INVITED_BIDDING.equals(project.getEntrustMethod())) {
// 公开中标或邀请招标需要走流程
String processInstanceId = processInstanceApi.createProcessInstance(loginUserId,
new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY)
.setBusinessKey(String.valueOf(project.getId())));
// 写入工作流编号
projectMapper.updateById(new ProjectDO().setId(project.getId()).setProcessInstanceId(processInstanceId));
}
}
// 返回 // 返回
return project.getId(); return project.getId();
} }
@ -95,4 +118,11 @@ public class ProjectServiceImpl implements ProjectService {
return dto; return dto;
} }
@Override
public void updateProjectStatus(Long id, Integer status) {
// 校验存在
validateProjectExists(id);
projectMapper.updateById(new ProjectDO().setId(id).setProcessStatus(status));
}
} }

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.pms.service.project.listener;
import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEvent;
import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEventListener;
import cn.iocoder.yudao.module.pms.service.project.ProjectService;
import cn.iocoder.yudao.module.pms.service.project.ProjectServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
/**
* @author hhyykk
* @description 项目立项状态监听器
* @date 2024/7/6
*/
@Component
public class ProjectInitStatusListener extends BpmProcessInstanceStatusEventListener {
@Resource
private ProjectService projectService;
@Override
protected String getProcessDefinitionKey() {
return ProjectServiceImpl.PROCESS_KEY;
}
@Override
protected void onEvent(BpmProcessInstanceStatusEvent event) {
projectService.updateProjectStatus(Long.parseLong(event.getBusinessKey()), event.getStatus());
}
}

View File

@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.pms.service.project;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@ -13,20 +12,14 @@ import cn.iocoder.yudao.module.pms.dal.dataobject.project.ProjectDO;
import cn.iocoder.yudao.module.pms.dal.mysql.project.ProjectMapper; import cn.iocoder.yudao.module.pms.dal.mysql.project.ProjectMapper;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import java.util.*;
import java.time.LocalDateTime;
import static cn.hutool.core.util.RandomUtil.*; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
/** /**
* {@link ProjectServiceImpl} 的单元测试类 * {@link ProjectServiceImpl} 的单元测试类
@ -48,7 +41,7 @@ public class ProjectServiceImplTest extends BaseDbUnitTest {
ProjectSaveReqVO createReqVO = randomPojo(ProjectSaveReqVO.class).setId(null); ProjectSaveReqVO createReqVO = randomPojo(ProjectSaveReqVO.class).setId(null);
// 调用 // 调用
Long projectId = projectService.createProject(createReqVO); Long projectId = projectService.createProject(1L, createReqVO);
// 断言 // 断言
assertNotNull(projectId); assertNotNull(projectId);
// 校验记录的属性是否正确 // 校验记录的属性是否正确