forked from Gitlink/microservices
feat(项目管理产品需求重构): 完善产品中的需求规格功能开发
需求规格纳入计划接口开发: 1. 限制仅已评审状态的需求规格才能纳入计划 2. 将需求规格文件上传至forge 3. 在对应项目中创建计划 4. 更新需规状态,记录计划id 5. 记录需规纳入计划操作 Signed-off-by: OTTO <731554297@qq.com>
This commit is contained in:
parent
f50d4ef1a8
commit
f12fac99e7
|
|
@ -107,4 +107,14 @@ public interface RemoteFileService {
|
|||
@RequestParam("type") String type,
|
||||
@RequestParam("hierarchy") String hierarchy,
|
||||
@RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
/**
|
||||
* 上传本地文件到Forge
|
||||
*
|
||||
* @param fileIdentifiers 文件标识列表,逗号分隔
|
||||
* @return Forge文件标识列表
|
||||
*/
|
||||
@PostMapping(value = "/common/uploadFileToForge/{fileIdentifiers}")
|
||||
R<List<String>> uploadFileToForge(@PathVariable("fileIdentifiers") String fileIdentifiers,
|
||||
@RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,11 @@ public class RemoteFileFallbackFactory implements FallbackFactory<RemoteFileServ
|
|||
public R<String> packagedFile(HashMap<String, String> packagedStructure, String zipFileName, String type, String hierarchy, String source) {
|
||||
return R.fail("打包文件失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<List<String>> uploadFileToForge(String fileIdentifiers, String source) {
|
||||
return R.fail("上传本地文件到Forge失败:" + throwable.getMessage());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -210,4 +210,17 @@ public class CommonController extends BaseController {
|
|||
sysFileInfo.setFilePath("");
|
||||
return R.ok(sysFileInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传本地文件到Forge
|
||||
*
|
||||
* @param fileIdentifiers 文件标识列表,逗号分隔
|
||||
* @return Forge文件标识列表
|
||||
*/
|
||||
@InnerAuth
|
||||
@PostMapping(value = "/uploadFileToForge/{fileIdentifiers}")
|
||||
@ApiOperation(value = "上传本地文件到Forge", hidden = true)
|
||||
R<List<String>> uploadFileToForge(@PathVariable("fileIdentifiers") String fileIdentifiers) {
|
||||
return R.ok(sysFileInfoService.uploadFileToForge(fileIdentifiers));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,4 +171,6 @@ public interface ISysFileInfoService {
|
|||
* @return 压缩包文件标识
|
||||
*/
|
||||
String packagedFile(HashMap<String, String> packagedStructure, String zipFileName, String type, String hierarchy);
|
||||
|
||||
List<String> uploadFileToForge(String fileIdentifiers);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -496,6 +496,30 @@ public class SysFileInfoServiceImpl implements ISysFileInfoService {
|
|||
return fileIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> uploadFileToForge(String fileIdentifiers) {
|
||||
List<SysFileInfo> fileInfoList = getFileListByIdentifier(fileIdentifiers);
|
||||
try {
|
||||
List<String> forgeFileIdentifierList = new ArrayList<>();
|
||||
for (SysFileInfo fileInfo : fileInfoList) {
|
||||
String filePath = localFilePath + fileInfo.getFilePath();
|
||||
File file = new File(filePath);
|
||||
if (!file.exists()) {
|
||||
throw new ServiceException("该文件不存在");
|
||||
}
|
||||
// 拷贝文件到打包目录
|
||||
FileInputStream fileInputStream = new FileInputStream(file);
|
||||
MultipartFile multipartFile = FileUtils.createMultipartFile(fileInputStream, fileInfo.getFileOriginName());
|
||||
SysFileInfo sysFileInfo = upload(multipartFile, "pms-gitlink", null);
|
||||
forgeFileIdentifierList.add(sysFileInfo.getFileIdentifier());
|
||||
}
|
||||
return forgeFileIdentifierList;
|
||||
} catch (IOException e) {
|
||||
logger.error("上传本地文件到Forge失败{}", e.getMessage());
|
||||
throw new ServiceException("上传本地文件到Forge失败");
|
||||
}
|
||||
}
|
||||
|
||||
private void fileDownload(SysFileInfo sysFileInfo, HttpServletResponse response) {
|
||||
try {
|
||||
String fileName = sysFileInfo.getFileOriginName();
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ public class ProductReqSpecsController extends BaseController {
|
|||
*/
|
||||
@RequiresPermissions("pms:pmsProductRequirement:edit")
|
||||
@Log(title = "需求规格", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
@PutMapping("/change")
|
||||
@ApiOperation(value = "变更需求规格")
|
||||
public AjaxResult change(@RequestBody @Validated ProductReqSpecsChangeVo productReqSpecsChangeVo) {
|
||||
return toAjax(pmsProductRequirementService.changeReqSpecs(productReqSpecsChangeVo));
|
||||
|
|
@ -109,4 +109,15 @@ public class ProductReqSpecsController extends BaseController {
|
|||
public AjaxResult review(@RequestBody @Validated ProductReqReviewVo productReqReviewVo) {
|
||||
return toAjax(pmsProductRequirementService.reviewReqSpecs(productReqReviewVo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 需求规格纳入计划
|
||||
*/
|
||||
@RequiresPermissions("pms:pmsProductRequirement:edit")
|
||||
@Log(title = "需求规格", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/activePlan")
|
||||
@ApiOperation(value = "需求规格纳入计划")
|
||||
public AjaxResult activePlan(@RequestBody @Validated ProductReqSpecsActivePlanVo productReqSpecsActivePlanVo) {
|
||||
return toAjax(pmsProductRequirementService.activePlan(productReqSpecsActivePlanVo));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import lombok.Getter;
|
|||
public enum ProductReqOperationType {
|
||||
CONTENT_MODIFY("contentModify", "内容修改"),
|
||||
REVIEW_USER_REQ("reviewUserReq", "用户需求评审"),
|
||||
ACTIVE_PLAN("activePlan", "纳入计划"),
|
||||
REVIEW_REQ_SPECS("reviewUserReq", "需求规格评审");
|
||||
private final String key;
|
||||
private final String name;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import java.util.Date;
|
|||
* @date 2023-10-10
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("用户需求评审对象")
|
||||
@ApiModel("需求评审对象")
|
||||
public class ProductReqReviewVo {
|
||||
|
||||
@ApiModelProperty(value = "需求Id", required = true)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
package com.microservices.pms.product.domain.vo;
|
||||
|
||||
import com.microservices.pms.product.domain.PmsProductReqOperationRecord;
|
||||
import com.microservices.pms.product.domain.PmsProductRequirement;
|
||||
import com.microservices.pms.product.domain.enums.ProductReqOperationType;
|
||||
import com.microservices.pms.project.domain.vo.PmsProjectIssuesInputVo;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 产品需求对象 pms_product_requirement
|
||||
*
|
||||
* @author otto
|
||||
* @date 2023-10-10
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("需求规格纳入计划对象")
|
||||
public class ProductReqSpecsActivePlanVo {
|
||||
@ApiModelProperty(value = "需求Id", required = true)
|
||||
@NotNull
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "项目Id", required = true)
|
||||
@NotNull
|
||||
private Long projectId;
|
||||
|
||||
public PmsProjectIssuesInputVo toPmsProjectIssuesInputVo(PmsProductRequirement reqSpecs, List<String> forgeFileIdentifierList) {
|
||||
PmsProjectIssuesInputVo issue = new PmsProjectIssuesInputVo();
|
||||
issue.setSubject(reqSpecs.getTitle());
|
||||
issue.setPmProjectId(projectId);
|
||||
issue.setStatusId(1);
|
||||
issue.setPmIssueType(1);
|
||||
issue.setPriorityId(2);
|
||||
issue.setDescription(reqSpecs.getContent());
|
||||
issue.setAttachmentIds(forgeFileIdentifierList);
|
||||
return issue;
|
||||
}
|
||||
|
||||
public PmsProductReqOperationRecord toPmsProductReqOperationRecord(PmsProductRequirement pmsProductRequirement) {
|
||||
PmsProductReqOperationRecord record = new PmsProductReqOperationRecord();
|
||||
record.setProductRequirementId(pmsProductRequirement.getId());
|
||||
record.setType(ProductReqOperationType.ACTIVE_PLAN.getKey());
|
||||
record.setOperation("激活");
|
||||
record.setOperator(pmsProductRequirement.getCreateBy());
|
||||
record.setOperatingTime(pmsProductRequirement.getCreateTime());
|
||||
return record;
|
||||
}
|
||||
}
|
||||
|
|
@ -47,11 +47,13 @@ public class ProductReqSpecsChangeVo {
|
|||
}
|
||||
|
||||
public boolean isReqChange(PmsProductRequirement oldPmsProductRequirement) {
|
||||
if (StringUtils.isNotEmpty(this.getContent()) || StringUtils.isNotEmpty(this.getFileIdentifiers()) || StringUtils.isNotEmpty(this.getTitle())) {
|
||||
return !oldPmsProductRequirement.getTitle().equals(this.title)
|
||||
|| !oldPmsProductRequirement.getContent().equals(this.content)
|
||||
|| !oldPmsProductRequirement.getFileIdentifiers().equals(this.fileIdentifiers);
|
||||
|
||||
if (StringUtils.isNotEmpty(this.getContent()) && !this.content.equals(oldPmsProductRequirement.getContent())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (StringUtils.isNotEmpty(this.getTitle()) && !this.title.equals(oldPmsProductRequirement.getTitle())) {
|
||||
return true;
|
||||
}
|
||||
return StringUtils.isNotEmpty(this.getFileIdentifiers()) && !this.getFileIdentifiers().equals(oldPmsProductRequirement.getFileIdentifiers());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,4 +162,6 @@ public interface IPmsProductRequirementService
|
|||
int reviewReqSpecs(ProductReqReviewVo productReqReviewVo);
|
||||
|
||||
int changeReqSpecs(ProductReqSpecsChangeVo productReqSpecsChangeVo);
|
||||
|
||||
int activePlan(ProductReqSpecsActivePlanVo productReqSpecsActivePlanVo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.microservices.pms.product.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.constant.SecurityConstants;
|
||||
import com.microservices.common.core.exception.NotFoundException;
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.common.core.utils.*;
|
||||
|
|
@ -16,11 +17,14 @@ import com.microservices.pms.product.domain.vo.*;
|
|||
import com.microservices.pms.product.mapper.PmsProductRequirementMapper;
|
||||
import com.microservices.pms.product.service.*;
|
||||
import com.microservices.pms.project.domain.PmsProject;
|
||||
import com.microservices.pms.project.domain.vo.PmsProjectIssuesInputVo;
|
||||
import com.microservices.pms.project.service.IPmsProjectService;
|
||||
import com.microservices.pms.project.service.PmsProjectIssuesService;
|
||||
import com.microservices.pms.utils.PmsConstants;
|
||||
import com.microservices.pms.utils.PmsUtils;
|
||||
import com.microservices.system.api.RemoteFileService;
|
||||
import com.microservices.system.api.domain.SysUser;
|
||||
import com.microservices.system.api.utils.FeignUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
|
@ -65,6 +69,8 @@ public class PmsProductRequirementServiceImpl implements IPmsProductRequirementS
|
|||
@Autowired
|
||||
@Lazy
|
||||
private IPmsJournalsService pmsJournalsService;
|
||||
@Autowired
|
||||
private RemoteFileService remoteFileService;
|
||||
|
||||
/**
|
||||
* 查询产品需求
|
||||
|
|
@ -560,6 +566,34 @@ public class PmsProductRequirementServiceImpl implements IPmsProductRequirementS
|
|||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int activePlan(ProductReqSpecsActivePlanVo productReqSpecsActivePlanVo) {
|
||||
// 通过id检查需修改的产品需求是否存在
|
||||
PmsProductRequirement reqSpecs = selectPmsProductRequirementById(productReqSpecsActivePlanVo.getId(), true);
|
||||
if (!ProductReqStatus.REVIEWED_REQ_SPECS.getKey().equals(reqSpecs.getStatus())) {
|
||||
throw new ServiceException("仅已评审状态的需求规格才能纳入计划");
|
||||
}
|
||||
PmsProject project = pmsProjectService.selectAndCheckPmsProjectById(productReqSpecsActivePlanVo.getProjectId());
|
||||
List<String> forgeFileIdentifierList = null;
|
||||
if (StringUtils.isNotEmpty(reqSpecs.getFileIdentifiers())) {
|
||||
// 需求规格文件上传至forge
|
||||
forgeFileIdentifierList = FeignUtils.getReturnData(
|
||||
remoteFileService.uploadFileToForge(reqSpecs.getFileIdentifiers(), SecurityConstants.INNER)
|
||||
);
|
||||
}
|
||||
PmsProjectIssuesInputVo pmsProjectIssuesInputVo = productReqSpecsActivePlanVo.toPmsProjectIssuesInputVo(reqSpecs, forgeFileIdentifierList);
|
||||
|
||||
JSONObject projectIssue = pmsProjectIssuesService.insertPmsProjectIssues(pmsProjectIssuesInputVo);
|
||||
reqSpecs.setPmsProjectId(project.getId());
|
||||
reqSpecs.setProjectReqId(projectIssue.getLong("id"));
|
||||
reqSpecs.setStatus(ProductReqStatus.PLANNED_REQ_SPECS_CHANGING.getKey());
|
||||
int success = updateRequirement(reqSpecs, reqSpecs.getPmsProductIdentifier());
|
||||
pmsProductReqOperationRecordService.insertPmsProductReqOperationRecord(
|
||||
productReqSpecsActivePlanVo.toPmsProductReqOperationRecord(reqSpecs)
|
||||
);
|
||||
return success;
|
||||
}
|
||||
|
||||
private ProductReqSpecsDetailVo toProductReqSpecsDetailVo(PmsProductRequirement pmsProductRequirement) {
|
||||
ProductReqSpecsDataVo productReqSpecsDataVo = toProductReqSpecsDataVo(pmsProductRequirement, null);
|
||||
ProductReqSpecsDetailVo productReqSpecsDetailVo = productReqSpecsDataVo.toProductReqSpecsDetailVo();
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@
|
|||
requirement_assignee_gitlink_ids = #{requirementAssigneeGitlinkIds},
|
||||
pms_project_id = #{pmsProjectId},
|
||||
<if test="fromId != null and fromId != ''">from_id = #{fromId},</if>
|
||||
<if test="projectReqId != null and projectReqId != ''">project_req_id = #{project_req_id},</if>
|
||||
<if test="projectReqId != null and projectReqId != ''">project_req_id = #{projectReqId},</if>
|
||||
<if test="type != null and type != ''">type = #{type},</if>
|
||||
<if test="identifier != null and identifier != ''">identifier = #{identifier},</if>
|
||||
<if test="sourceUser != null and sourceUser != ''">source_user = #{sourceUser},</if>
|
||||
|
|
|
|||
Loading…
Reference in New Issue