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("type") String type,
|
||||||
@RequestParam("hierarchy") String hierarchy,
|
@RequestParam("hierarchy") String hierarchy,
|
||||||
@RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
@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) {
|
public R<String> packagedFile(HashMap<String, String> packagedStructure, String zipFileName, String type, String hierarchy, String source) {
|
||||||
return R.fail("打包文件失败:" + throwable.getMessage());
|
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("");
|
sysFileInfo.setFilePath("");
|
||||||
return R.ok(sysFileInfo);
|
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 压缩包文件标识
|
* @return 压缩包文件标识
|
||||||
*/
|
*/
|
||||||
String packagedFile(HashMap<String, String> packagedStructure, String zipFileName, String type, String hierarchy);
|
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;
|
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) {
|
private void fileDownload(SysFileInfo sysFileInfo, HttpServletResponse response) {
|
||||||
try {
|
try {
|
||||||
String fileName = sysFileInfo.getFileOriginName();
|
String fileName = sysFileInfo.getFileOriginName();
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ public class ProductReqSpecsController extends BaseController {
|
||||||
*/
|
*/
|
||||||
@RequiresPermissions("pms:pmsProductRequirement:edit")
|
@RequiresPermissions("pms:pmsProductRequirement:edit")
|
||||||
@Log(title = "需求规格", businessType = BusinessType.UPDATE)
|
@Log(title = "需求规格", businessType = BusinessType.UPDATE)
|
||||||
@PutMapping
|
@PutMapping("/change")
|
||||||
@ApiOperation(value = "变更需求规格")
|
@ApiOperation(value = "变更需求规格")
|
||||||
public AjaxResult change(@RequestBody @Validated ProductReqSpecsChangeVo productReqSpecsChangeVo) {
|
public AjaxResult change(@RequestBody @Validated ProductReqSpecsChangeVo productReqSpecsChangeVo) {
|
||||||
return toAjax(pmsProductRequirementService.changeReqSpecs(productReqSpecsChangeVo));
|
return toAjax(pmsProductRequirementService.changeReqSpecs(productReqSpecsChangeVo));
|
||||||
|
|
@ -109,4 +109,15 @@ public class ProductReqSpecsController extends BaseController {
|
||||||
public AjaxResult review(@RequestBody @Validated ProductReqReviewVo productReqReviewVo) {
|
public AjaxResult review(@RequestBody @Validated ProductReqReviewVo productReqReviewVo) {
|
||||||
return toAjax(pmsProductRequirementService.reviewReqSpecs(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 {
|
public enum ProductReqOperationType {
|
||||||
CONTENT_MODIFY("contentModify", "内容修改"),
|
CONTENT_MODIFY("contentModify", "内容修改"),
|
||||||
REVIEW_USER_REQ("reviewUserReq", "用户需求评审"),
|
REVIEW_USER_REQ("reviewUserReq", "用户需求评审"),
|
||||||
|
ACTIVE_PLAN("activePlan", "纳入计划"),
|
||||||
REVIEW_REQ_SPECS("reviewUserReq", "需求规格评审");
|
REVIEW_REQ_SPECS("reviewUserReq", "需求规格评审");
|
||||||
private final String key;
|
private final String key;
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import java.util.Date;
|
||||||
* @date 2023-10-10
|
* @date 2023-10-10
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@ApiModel("用户需求评审对象")
|
@ApiModel("需求评审对象")
|
||||||
public class ProductReqReviewVo {
|
public class ProductReqReviewVo {
|
||||||
|
|
||||||
@ApiModelProperty(value = "需求Id", required = true)
|
@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) {
|
public boolean isReqChange(PmsProductRequirement oldPmsProductRequirement) {
|
||||||
if (StringUtils.isNotEmpty(this.getContent()) || StringUtils.isNotEmpty(this.getFileIdentifiers()) || StringUtils.isNotEmpty(this.getTitle())) {
|
|
||||||
return !oldPmsProductRequirement.getTitle().equals(this.title)
|
if (StringUtils.isNotEmpty(this.getContent()) && !this.content.equals(oldPmsProductRequirement.getContent())) {
|
||||||
|| !oldPmsProductRequirement.getContent().equals(this.content)
|
return true;
|
||||||
|| !oldPmsProductRequirement.getFileIdentifiers().equals(this.fileIdentifiers);
|
|
||||||
}
|
}
|
||||||
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 reviewReqSpecs(ProductReqReviewVo productReqReviewVo);
|
||||||
|
|
||||||
int changeReqSpecs(ProductReqSpecsChangeVo productReqSpecsChangeVo);
|
int changeReqSpecs(ProductReqSpecsChangeVo productReqSpecsChangeVo);
|
||||||
|
|
||||||
|
int activePlan(ProductReqSpecsActivePlanVo productReqSpecsActivePlanVo);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.microservices.pms.product.service.impl;
|
package com.microservices.pms.product.service.impl;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
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.NotFoundException;
|
||||||
import com.microservices.common.core.exception.ServiceException;
|
import com.microservices.common.core.exception.ServiceException;
|
||||||
import com.microservices.common.core.utils.*;
|
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.mapper.PmsProductRequirementMapper;
|
||||||
import com.microservices.pms.product.service.*;
|
import com.microservices.pms.product.service.*;
|
||||||
import com.microservices.pms.project.domain.PmsProject;
|
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.IPmsProjectService;
|
||||||
import com.microservices.pms.project.service.PmsProjectIssuesService;
|
import com.microservices.pms.project.service.PmsProjectIssuesService;
|
||||||
import com.microservices.pms.utils.PmsConstants;
|
import com.microservices.pms.utils.PmsConstants;
|
||||||
import com.microservices.pms.utils.PmsUtils;
|
import com.microservices.pms.utils.PmsUtils;
|
||||||
|
import com.microservices.system.api.RemoteFileService;
|
||||||
import com.microservices.system.api.domain.SysUser;
|
import com.microservices.system.api.domain.SysUser;
|
||||||
|
import com.microservices.system.api.utils.FeignUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
@ -65,6 +69,8 @@ public class PmsProductRequirementServiceImpl implements IPmsProductRequirementS
|
||||||
@Autowired
|
@Autowired
|
||||||
@Lazy
|
@Lazy
|
||||||
private IPmsJournalsService pmsJournalsService;
|
private IPmsJournalsService pmsJournalsService;
|
||||||
|
@Autowired
|
||||||
|
private RemoteFileService remoteFileService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询产品需求
|
* 查询产品需求
|
||||||
|
|
@ -560,6 +566,34 @@ public class PmsProductRequirementServiceImpl implements IPmsProductRequirementS
|
||||||
return success;
|
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) {
|
private ProductReqSpecsDetailVo toProductReqSpecsDetailVo(PmsProductRequirement pmsProductRequirement) {
|
||||||
ProductReqSpecsDataVo productReqSpecsDataVo = toProductReqSpecsDataVo(pmsProductRequirement, null);
|
ProductReqSpecsDataVo productReqSpecsDataVo = toProductReqSpecsDataVo(pmsProductRequirement, null);
|
||||||
ProductReqSpecsDetailVo productReqSpecsDetailVo = productReqSpecsDataVo.toProductReqSpecsDetailVo();
|
ProductReqSpecsDetailVo productReqSpecsDetailVo = productReqSpecsDataVo.toProductReqSpecsDetailVo();
|
||||||
|
|
|
||||||
|
|
@ -271,7 +271,7 @@
|
||||||
requirement_assignee_gitlink_ids = #{requirementAssigneeGitlinkIds},
|
requirement_assignee_gitlink_ids = #{requirementAssigneeGitlinkIds},
|
||||||
pms_project_id = #{pmsProjectId},
|
pms_project_id = #{pmsProjectId},
|
||||||
<if test="fromId != null and fromId != ''">from_id = #{fromId},</if>
|
<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="type != null and type != ''">type = #{type},</if>
|
||||||
<if test="identifier != null and identifier != ''">identifier = #{identifier},</if>
|
<if test="identifier != null and identifier != ''">identifier = #{identifier},</if>
|
||||||
<if test="sourceUser != null and sourceUser != ''">source_user = #{sourceUser},</if>
|
<if test="sourceUser != null and sourceUser != ''">source_user = #{sourceUser},</if>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue