diff --git a/backend/src/main/java/io/metersphere/base/domain/Issues.java b/backend/src/main/java/io/metersphere/base/domain/Issues.java index bc9814bfcd..d5ac807e35 100644 --- a/backend/src/main/java/io/metersphere/base/domain/Issues.java +++ b/backend/src/main/java/io/metersphere/base/domain/Issues.java @@ -1,7 +1,6 @@ package io.metersphere.base.domain; import java.io.Serializable; - import lombok.Data; @Data @@ -22,13 +21,7 @@ public class Issues implements Serializable { private String platform; - private String description; - - private String model; - - private String projectName; - - private String currentOwner; + private String projectId; private static final long serialVersionUID = 1L; -} +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/domain/IssuesDao.java b/backend/src/main/java/io/metersphere/base/domain/IssuesDao.java new file mode 100644 index 0000000000..868ac6cba0 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/domain/IssuesDao.java @@ -0,0 +1,11 @@ +package io.metersphere.base.domain; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class IssuesDao extends IssuesWithBLOBs { + private String model; + private String projectName; +} diff --git a/backend/src/main/java/io/metersphere/base/domain/IssuesExample.java b/backend/src/main/java/io/metersphere/base/domain/IssuesExample.java index c2f363f61d..0beea9d72d 100644 --- a/backend/src/main/java/io/metersphere/base/domain/IssuesExample.java +++ b/backend/src/main/java/io/metersphere/base/domain/IssuesExample.java @@ -643,6 +643,76 @@ public class IssuesExample { addCriterion("platform not between", value1, value2, "platform"); return (Criteria) this; } + + public Criteria andProjectIdIsNull() { + addCriterion("project_id is null"); + return (Criteria) this; + } + + public Criteria andProjectIdIsNotNull() { + addCriterion("project_id is not null"); + return (Criteria) this; + } + + public Criteria andProjectIdEqualTo(String value) { + addCriterion("project_id =", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdNotEqualTo(String value) { + addCriterion("project_id <>", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdGreaterThan(String value) { + addCriterion("project_id >", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdGreaterThanOrEqualTo(String value) { + addCriterion("project_id >=", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdLessThan(String value) { + addCriterion("project_id <", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdLessThanOrEqualTo(String value) { + addCriterion("project_id <=", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdLike(String value) { + addCriterion("project_id like", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdNotLike(String value) { + addCriterion("project_id not like", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdIn(List values) { + addCriterion("project_id in", values, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdNotIn(List values) { + addCriterion("project_id not in", values, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdBetween(String value1, String value2) { + addCriterion("project_id between", value1, value2, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdNotBetween(String value1, String value2) { + addCriterion("project_id not between", value1, value2, "projectId"); + return (Criteria) this; + } } public static class Criteria extends GeneratedCriteria { diff --git a/backend/src/main/java/io/metersphere/base/domain/IssuesWithBLOBs.java b/backend/src/main/java/io/metersphere/base/domain/IssuesWithBLOBs.java new file mode 100644 index 0000000000..4df0825f00 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/domain/IssuesWithBLOBs.java @@ -0,0 +1,17 @@ +package io.metersphere.base.domain; + +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class IssuesWithBLOBs extends Issues implements Serializable { + private String description; + + private String customFields; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/IssuesMapper.java b/backend/src/main/java/io/metersphere/base/mapper/IssuesMapper.java index 0dd8d77d7d..3df4df3f5d 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/IssuesMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/IssuesMapper.java @@ -2,6 +2,7 @@ package io.metersphere.base.mapper; import io.metersphere.base.domain.Issues; import io.metersphere.base.domain.IssuesExample; +import io.metersphere.base.domain.IssuesWithBLOBs; import java.util.List; import org.apache.ibatis.annotations.Param; @@ -12,25 +13,25 @@ public interface IssuesMapper { int deleteByPrimaryKey(String id); - int insert(Issues record); + int insert(IssuesWithBLOBs record); - int insertSelective(Issues record); + int insertSelective(IssuesWithBLOBs record); - List selectByExampleWithBLOBs(IssuesExample example); + List selectByExampleWithBLOBs(IssuesExample example); List selectByExample(IssuesExample example); - Issues selectByPrimaryKey(String id); + IssuesWithBLOBs selectByPrimaryKey(String id); - int updateByExampleSelective(@Param("record") Issues record, @Param("example") IssuesExample example); + int updateByExampleSelective(@Param("record") IssuesWithBLOBs record, @Param("example") IssuesExample example); - int updateByExampleWithBLOBs(@Param("record") Issues record, @Param("example") IssuesExample example); + int updateByExampleWithBLOBs(@Param("record") IssuesWithBLOBs record, @Param("example") IssuesExample example); int updateByExample(@Param("record") Issues record, @Param("example") IssuesExample example); - int updateByPrimaryKeySelective(Issues record); + int updateByPrimaryKeySelective(IssuesWithBLOBs record); - int updateByPrimaryKeyWithBLOBs(Issues record); + int updateByPrimaryKeyWithBLOBs(IssuesWithBLOBs record); int updateByPrimaryKey(Issues record); } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/IssuesMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/IssuesMapper.xml index 5d5bac2cb6..5f6ca6d4e8 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/IssuesMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/IssuesMapper.xml @@ -10,9 +10,11 @@ + - + + @@ -73,10 +75,10 @@ - id, title, `status`, create_time, update_time, reporter, lastmodify, platform + id, title, `status`, create_time, update_time, reporter, lastmodify, platform, project_id - description + description, custom_fields @@ -230,9 +244,15 @@ platform = #{record.platform,jdbcType=VARCHAR}, + + project_id = #{record.projectId,jdbcType=VARCHAR}, + description = #{record.description,jdbcType=LONGVARCHAR}, + + custom_fields = #{record.customFields,jdbcType=LONGVARCHAR}, + @@ -248,7 +268,9 @@ reporter = #{record.reporter,jdbcType=VARCHAR}, lastmodify = #{record.lastmodify,jdbcType=VARCHAR}, platform = #{record.platform,jdbcType=VARCHAR}, - description = #{record.description,jdbcType=LONGVARCHAR} + project_id = #{record.projectId,jdbcType=VARCHAR}, + description = #{record.description,jdbcType=LONGVARCHAR}, + custom_fields = #{record.customFields,jdbcType=LONGVARCHAR} @@ -262,12 +284,13 @@ update_time = #{record.updateTime,jdbcType=BIGINT}, reporter = #{record.reporter,jdbcType=VARCHAR}, lastmodify = #{record.lastmodify,jdbcType=VARCHAR}, - platform = #{record.platform,jdbcType=VARCHAR} + platform = #{record.platform,jdbcType=VARCHAR}, + project_id = #{record.projectId,jdbcType=VARCHAR} - + update issues @@ -291,13 +314,19 @@ platform = #{platform,jdbcType=VARCHAR}, + + project_id = #{projectId,jdbcType=VARCHAR}, + description = #{description,jdbcType=LONGVARCHAR}, + + custom_fields = #{customFields,jdbcType=LONGVARCHAR}, + where id = #{id,jdbcType=VARCHAR} - + update issues set title = #{title,jdbcType=VARCHAR}, `status` = #{status,jdbcType=VARCHAR}, @@ -306,7 +335,9 @@ reporter = #{reporter,jdbcType=VARCHAR}, lastmodify = #{lastmodify,jdbcType=VARCHAR}, platform = #{platform,jdbcType=VARCHAR}, - description = #{description,jdbcType=LONGVARCHAR} + project_id = #{projectId,jdbcType=VARCHAR}, + description = #{description,jdbcType=LONGVARCHAR}, + custom_fields = #{customFields,jdbcType=LONGVARCHAR} where id = #{id,jdbcType=VARCHAR} @@ -317,7 +348,8 @@ update_time = #{updateTime,jdbcType=BIGINT}, reporter = #{reporter,jdbcType=VARCHAR}, lastmodify = #{lastmodify,jdbcType=VARCHAR}, - platform = #{platform,jdbcType=VARCHAR} + platform = #{platform,jdbcType=VARCHAR}, + project_id = #{projectId,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtIssuesMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtIssuesMapper.java index 8bd29e8c0b..f2daf5f3f1 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtIssuesMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtIssuesMapper.java @@ -1,11 +1,14 @@ package io.metersphere.base.mapper.ext; -import io.metersphere.base.domain.Issues; +import io.metersphere.base.domain.IssuesDao; +import io.metersphere.track.request.testcase.IssuesRequest; import org.apache.ibatis.annotations.Param; import java.util.List; public interface ExtIssuesMapper { - List getIssues(@Param("caseId") String caseId, @Param("platform") String platform); + List getIssuesByCaseId(@Param("request") IssuesRequest issuesRequest); + + List getIssuesByProjectId(@Param("request") IssuesRequest issuesRequest); } diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtIssuesMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtIssuesMapper.xml index 8d0382ba42..a3e72ed22e 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtIssuesMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtIssuesMapper.xml @@ -2,12 +2,61 @@ - select issues.* - from test_case_issues, issues - where test_case_issues.issues_id = issues.id - and test_case_issues.test_case_id = #{caseId} - and issues.platform = #{platform} - order by issues.create_time DESC + from issues + inner join test_case_issues + on test_case_issues.issues_id = issues.id + + - \ No newline at end of file + + + + + + + + and issues.project_id = #{request.projectId} + + + + and test_case_issues.test_case_id = #{request.testCaseId} + + + + and issues.platform = #{request.platform} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.java index f499b8eacb..7d74c9411e 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.java @@ -32,6 +32,14 @@ public interface ExtTestCaseMapper { */ List getTestCaseByNotInPlan(@Param("request") QueryTestCaseRequest request); + /** + * 获取不在测试缺陷中的用例 + * + * @param request + * @return + */ + List getTestCaseByNotInIssue(@Param("request") QueryTestCaseRequest request); + /** * 获取不在评审范围中的用例 * @@ -78,4 +86,6 @@ public interface ExtTestCaseMapper { List listForMinder(@Param("request") QueryTestCaseRequest request); + + List getTestCaseByIds(@Param("ids")List ids); } diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml index c8bf5666d9..0b9a4cc501 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml @@ -76,6 +76,12 @@ select test_case.id, test_case.name, test_case.priority, test_case.type, test_case.review_status from test_case as test_case left join test_case_review_test_case as T2 on test_case.id=T2.case_id and T2.review_id =#{request.reviewId} + and T2.case_id is null + + ORDER BY test_case.update_time DESC + + + @@ -84,11 +90,15 @@ - and T2.case_id is null + + and test_case.id not in + + #{id} + + and test_case.name like CONCAT('%', #{request.name},'%') - AND test_case.project_id = #{request.projectId} @@ -100,37 +110,14 @@ - ORDER BY test_case.update_time DESC - + @@ -428,5 +415,21 @@ from test_case - + + diff --git a/backend/src/main/java/io/metersphere/commons/constants/IssuesStatus.java b/backend/src/main/java/io/metersphere/commons/constants/IssuesStatus.java new file mode 100644 index 0000000000..22bc7451e9 --- /dev/null +++ b/backend/src/main/java/io/metersphere/commons/constants/IssuesStatus.java @@ -0,0 +1,14 @@ +package io.metersphere.commons.constants; + +public enum IssuesStatus { + NEW("new"), CLOSED("closed"), RESOLVED("resolved"), DELETE("delete"); + private String value; + IssuesStatus(String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } +} diff --git a/backend/src/main/java/io/metersphere/controller/IssueTemplateController.java b/backend/src/main/java/io/metersphere/controller/IssueTemplateController.java index 19ae7a8c7c..d24300e6d8 100644 --- a/backend/src/main/java/io/metersphere/controller/IssueTemplateController.java +++ b/backend/src/main/java/io/metersphere/controller/IssueTemplateController.java @@ -8,6 +8,7 @@ import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.Pager; import io.metersphere.controller.request.BaseQueryRequest; import io.metersphere.controller.request.UpdateIssueTemplateRequest; +import io.metersphere.dto.IssueTemplateDao; import io.metersphere.service.IssueTemplateService; import org.apache.shiro.authz.annotation.Logical; import org.apache.shiro.authz.annotation.RequiresRoles; @@ -48,4 +49,9 @@ public class IssueTemplateController { public List list(@PathVariable String workspaceId) { return issueTemplateService.getOption(workspaceId); } + + @GetMapping("/get/relate/{projectId}") + public IssueTemplateDao getTemplate(@PathVariable String projectId) { + return issueTemplateService.getTemplate(projectId); + } } diff --git a/backend/src/main/java/io/metersphere/dto/IssueTemplateDao.java b/backend/src/main/java/io/metersphere/dto/IssueTemplateDao.java new file mode 100644 index 0000000000..8d0a6afded --- /dev/null +++ b/backend/src/main/java/io/metersphere/dto/IssueTemplateDao.java @@ -0,0 +1,11 @@ +package io.metersphere.dto; + +import io.metersphere.base.domain.IssueTemplate; +import lombok.Data; + +import java.util.List; + +@Data +public class IssueTemplateDao extends IssueTemplate { + List customFields; +} diff --git a/backend/src/main/java/io/metersphere/service/CustomFieldService.java b/backend/src/main/java/io/metersphere/service/CustomFieldService.java index 76acb915a3..6c7dbfe5a4 100644 --- a/backend/src/main/java/io/metersphere/service/CustomFieldService.java +++ b/backend/src/main/java/io/metersphere/service/CustomFieldService.java @@ -4,13 +4,16 @@ import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import io.metersphere.base.domain.CustomField; import io.metersphere.base.domain.CustomFieldExample; +import io.metersphere.base.domain.CustomFieldTemplate; import io.metersphere.base.mapper.CustomFieldMapper; import io.metersphere.base.mapper.ext.ExtCustomFieldMapper; import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.BeanUtils; import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.controller.request.QueryCustomFieldRequest; +import io.metersphere.dto.CustomFieldDao; import io.metersphere.i18n.Translator; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -19,10 +22,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.stream.Collectors; @Service @@ -102,6 +102,28 @@ public class CustomFieldService { .andSceneEqualTo(scene); return customFieldMapper.selectByExampleWithBLOBs(example); } + + public List getCustomFieldByTemplateId(String templateId) { + List customFields = customFieldTemplateService.getCustomFields(templateId); + List fieldIds = customFields.stream() + .map(CustomFieldTemplate::getFieldId) + .collect(Collectors.toList()); + + List fields = getFieldByIds(fieldIds); + Map fieldMap = fields.stream() + .collect(Collectors.toMap(CustomField::getId, item -> item)); + + List result = new ArrayList<>(); + customFields.forEach((item) -> { + CustomFieldDao customFieldDao = new CustomFieldDao(); + CustomField customField = fieldMap.get(item.getFieldId()); + BeanUtils.copyBean(customFieldDao, customField); + BeanUtils.copyBean(customFieldDao, item); + result.add(customFieldDao); + }); + return result; + } + public List getFieldByIds(List ids) { if (CollectionUtils.isNotEmpty(ids)) { CustomFieldExample example = new CustomFieldExample(); diff --git a/backend/src/main/java/io/metersphere/service/IssueTemplateService.java b/backend/src/main/java/io/metersphere/service/IssueTemplateService.java index 3f0c88a593..b9ba3c90b2 100644 --- a/backend/src/main/java/io/metersphere/service/IssueTemplateService.java +++ b/backend/src/main/java/io/metersphere/service/IssueTemplateService.java @@ -9,6 +9,8 @@ import io.metersphere.commons.utils.BeanUtils; import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.controller.request.BaseQueryRequest; import io.metersphere.controller.request.UpdateIssueTemplateRequest; +import io.metersphere.dto.CustomFieldDao; +import io.metersphere.dto.IssueTemplateDao; import io.metersphere.i18n.Translator; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -35,6 +37,9 @@ public class IssueTemplateService { @Resource CustomFieldService customFieldService; + @Resource + ProjectService projectService; + public void add(UpdateIssueTemplateRequest request) { checkExist(request); IssueTemplate template = new IssueTemplate(); @@ -163,4 +168,23 @@ public class IssueTemplateService { issueTemplates.add(getDefaultTemplate(workspaceId)); return issueTemplates; } + + public IssueTemplateDao getTemplate(String projectId) { + Project project = projectService.getProjectById(projectId); + String caseTemplateId = project.getCaseTemplateId(); + IssueTemplate issueTemplate = null; + IssueTemplateDao issueTemplateDao = new IssueTemplateDao(); + if (StringUtils.isNotBlank(caseTemplateId)) { + issueTemplate = issueTemplateMapper.selectByPrimaryKey(caseTemplateId); + if (issueTemplate == null) { + issueTemplate = getDefaultTemplate(project.getWorkspaceId()); + } + } else { + issueTemplate = getDefaultTemplate(project.getWorkspaceId()); + } + BeanUtils.copyBean(issueTemplateDao, issueTemplate); + List result = customFieldService.getCustomFieldByTemplateId(issueTemplate.getId()); + issueTemplateDao.setCustomFields(result); + return issueTemplateDao; + } } diff --git a/backend/src/main/java/io/metersphere/service/ProjectService.java b/backend/src/main/java/io/metersphere/service/ProjectService.java index d44beaa170..4b8db3baba 100644 --- a/backend/src/main/java/io/metersphere/service/ProjectService.java +++ b/backend/src/main/java/io/metersphere/service/ProjectService.java @@ -89,6 +89,15 @@ public class ProjectService { return extProjectMapper.getProjectWithWorkspace(request); } + public List getProjectByIds(List ids) { + if (!CollectionUtils.isEmpty(ids)) { + ProjectExample example = new ProjectExample(); + example.createCriteria().andIdIn(ids); + return projectMapper.selectByExample(example); + } + return new ArrayList<>(); + } + public void deleteProject(String projectId) { // delete test LoadTestExample loadTestExample = new LoadTestExample(); diff --git a/backend/src/main/java/io/metersphere/service/TestCaseTemplateService.java b/backend/src/main/java/io/metersphere/service/TestCaseTemplateService.java index 9a77168fe0..04f4988f36 100644 --- a/backend/src/main/java/io/metersphere/service/TestCaseTemplateService.java +++ b/backend/src/main/java/io/metersphere/service/TestCaseTemplateService.java @@ -179,27 +179,14 @@ public class TestCaseTemplateService { TestCaseTemplateDao caseTemplateDao = new TestCaseTemplateDao(); if (StringUtils.isNotBlank(caseTemplateId)) { caseTemplate = testCaseTemplateMapper.selectByPrimaryKey(caseTemplateId); + if (caseTemplate == null) { + caseTemplate = getDefaultTemplate(project.getWorkspaceId()); + } } else { caseTemplate = getDefaultTemplate(project.getWorkspaceId()); } BeanUtils.copyBean(caseTemplateDao, caseTemplate); - List customFields = customFieldTemplateService.getCustomFields(caseTemplate.getId()); - List fieldIds = customFields.stream() - .map(CustomFieldTemplate::getFieldId) - .collect(Collectors.toList()); - - List fields = customFieldService.getFieldByIds(fieldIds); - Map fieldMap = fields.stream() - .collect(Collectors.toMap(CustomField::getId, item -> item)); - - List result = new ArrayList<>(); - customFields.forEach((item) -> { - CustomFieldDao customFieldDao = new CustomFieldDao(); - CustomField customField = fieldMap.get(item.getFieldId()); - BeanUtils.copyBean(customFieldDao, customField); - BeanUtils.copyBean(customFieldDao, item); - result.add(customFieldDao); - }); + List result = customFieldService.getCustomFieldByTemplateId(caseTemplate.getId()); caseTemplateDao.setCustomFields(result); return caseTemplateDao; } diff --git a/backend/src/main/java/io/metersphere/track/controller/IssuesController.java b/backend/src/main/java/io/metersphere/track/controller/IssuesController.java new file mode 100644 index 0000000000..a8172e042f --- /dev/null +++ b/backend/src/main/java/io/metersphere/track/controller/IssuesController.java @@ -0,0 +1,78 @@ +package io.metersphere.track.controller; + +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; +import io.metersphere.base.domain.Issues; +import io.metersphere.base.domain.IssuesDao; +import io.metersphere.commons.utils.PageUtils; +import io.metersphere.commons.utils.Pager; +import io.metersphere.track.issue.domain.PlatformUser; +import io.metersphere.track.issue.domain.ZentaoBuild; +import io.metersphere.track.request.testcase.IssuesRequest; +import io.metersphere.track.request.testcase.IssuesUpdateRequest; +import io.metersphere.track.service.IssuesService; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +@RequestMapping("issues") +@RestController +public class IssuesController { + + @Resource + private IssuesService issuesService; + + @PostMapping("/list/{goPage}/{pageSize}") + public Pager> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody IssuesRequest request) { + Page> page = PageHelper.startPage(goPage, pageSize, true); + return PageUtils.setPageInfo(page, issuesService.list(request)); + } + + @PostMapping("/add") + public void addIssues(@RequestBody IssuesUpdateRequest issuesRequest) { + issuesService.addIssues(issuesRequest); + } + + @PostMapping("/update") + public void updateIssues(@RequestBody IssuesUpdateRequest issuesRequest) { + issuesService.updateIssues(issuesRequest); + } + + @GetMapping("/get/{id}") + public List getIssues(@PathVariable String id) { + return issuesService.getIssues(id); + } + + @GetMapping("/auth/{platform}") + public void testAuth(@PathVariable String platform) { + issuesService.testAuth(platform); + } + + @GetMapping("/close/{id}") + public void closeLocalIssue(@PathVariable String id) { + issuesService.closeLocalIssue(id); + } + + @PostMapping("/delete") + public void deleteIssue(@RequestBody IssuesRequest request) { + issuesService.deleteIssue(request); + } + + @GetMapping("/tapd/user/{caseId}") + public List getTapdUsers(@PathVariable String caseId) { + return issuesService.getTapdProjectUsers(caseId); + } + + @GetMapping("/zentao/user/{caseId}") + public List getZentaoUsers(@PathVariable String caseId) { + return issuesService.getZentaoUsers(caseId); + } + + @GetMapping("/zentao/builds/{caseId}") + public List getZentaoBuilds(@PathVariable String caseId) { + return issuesService.getZentaoBuilds(caseId); + } + + +} diff --git a/backend/src/main/java/io/metersphere/track/controller/TestCaseController.java b/backend/src/main/java/io/metersphere/track/controller/TestCaseController.java index 19456e0fa6..daa7f054db 100644 --- a/backend/src/main/java/io/metersphere/track/controller/TestCaseController.java +++ b/backend/src/main/java/io/metersphere/track/controller/TestCaseController.java @@ -92,10 +92,16 @@ public class TestCaseController { return testCaseService.getTestCaseByNodeId(nodeIds); } - @PostMapping("/name/{goPage}/{pageSize}") - public Pager> getTestCaseNames(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestCaseRequest request) { + @PostMapping("/relate/{goPage}/{pageSize}") + public Pager> getTestCaseRelateList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestCaseRequest request) { Page page = PageHelper.startPage(goPage, pageSize, true); - return PageUtils.setPageInfo(page,testCaseService.getTestCaseNames(request)); + return PageUtils.setPageInfo(page,testCaseService.getTestCaseRelateList(request)); + } + + @PostMapping("/relate/issue/{goPage}/{pageSize}") + public Pager> getTestCaseIssueRelateList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestCaseRequest request) { + Page page = PageHelper.startPage(goPage, pageSize, true); + return PageUtils.setPageInfo(page,testCaseService.getTestCaseIssueRelateList(request)); } @PostMapping("/reviews/case/{goPage}/{pageSize}") diff --git a/backend/src/main/java/io/metersphere/track/controller/TestCaseIssuesController.java b/backend/src/main/java/io/metersphere/track/controller/TestCaseIssuesController.java index 72c409936e..1385e96ae7 100644 --- a/backend/src/main/java/io/metersphere/track/controller/TestCaseIssuesController.java +++ b/backend/src/main/java/io/metersphere/track/controller/TestCaseIssuesController.java @@ -1,61 +1,25 @@ package io.metersphere.track.controller; -import io.metersphere.base.domain.Issues; -import io.metersphere.track.issue.domain.PlatformUser; -import io.metersphere.track.issue.domain.ZentaoBuild; -import io.metersphere.track.service.IssuesService; -import io.metersphere.track.request.testcase.IssuesRequest; -import org.springframework.web.bind.annotation.*; +import io.metersphere.track.dto.TestCaseDTO; +import io.metersphere.track.request.issues.IssuesRelevanceRequest; +import io.metersphere.track.service.TestCaseIssueService; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.List; -@RequestMapping("issues") +@RequestMapping("test/case/issues") @RestController public class TestCaseIssuesController { @Resource - private IssuesService issuesService; + private TestCaseIssueService testCaseIssueService; - @PostMapping("/add") - public void addIssues(@RequestBody IssuesRequest issuesRequest) { - issuesService.addIssues(issuesRequest); + @PostMapping("/list") + public List list(@RequestBody IssuesRelevanceRequest request) { + return testCaseIssueService.list(request); } - - @GetMapping("/get/{id}") - public List getIssues(@PathVariable String id) { - return issuesService.getIssues(id); - } - - @GetMapping("/auth/{platform}") - public void testAuth(@PathVariable String platform) { - issuesService.testAuth(platform); - } - - @GetMapping("/close/{id}") - public void closeLocalIssue(@PathVariable String id) { - issuesService.closeLocalIssue(id); - } - - @PostMapping("/delete") - public void deleteIssue(@RequestBody IssuesRequest request) { - issuesService.deleteIssue(request); - } - - @GetMapping("/tapd/user/{caseId}") - public List getTapdUsers(@PathVariable String caseId) { - return issuesService.getTapdProjectUsers(caseId); - } - - @GetMapping("/zentao/user/{caseId}") - public List getZentaoUsers(@PathVariable String caseId) { - return issuesService.getZentaoUsers(caseId); - } - - @GetMapping("/zentao/builds/{caseId}") - public List getZentaoBuilds(@PathVariable String caseId) { - return issuesService.getZentaoBuilds(caseId); - } - - } diff --git a/backend/src/main/java/io/metersphere/track/controller/TestCaseNodeController.java b/backend/src/main/java/io/metersphere/track/controller/TestCaseNodeController.java index bbd6c88697..32e6dac6e6 100644 --- a/backend/src/main/java/io/metersphere/track/controller/TestCaseNodeController.java +++ b/backend/src/main/java/io/metersphere/track/controller/TestCaseNodeController.java @@ -37,6 +37,12 @@ public class TestCaseNodeController { return testCaseNodeService.getAllNodeByPlanId(request); } + /*模块列表列表*/ + @PostMapping("/list/project") + public List getAllNodeByProjectId(@RequestBody QueryNodeRequest request) { + return testCaseNodeService.getAllNodeByProjectId(request); + } + @PostMapping("/list/all/review") public List getAllNodeByReviewId(@RequestBody QueryNodeRequest request) { return testCaseNodeService.getAllNodeByReviewId(request); diff --git a/backend/src/main/java/io/metersphere/track/dto/TestCaseDTO.java b/backend/src/main/java/io/metersphere/track/dto/TestCaseDTO.java index 8db63a2f6d..2a27b0eb73 100644 --- a/backend/src/main/java/io/metersphere/track/dto/TestCaseDTO.java +++ b/backend/src/main/java/io/metersphere/track/dto/TestCaseDTO.java @@ -15,6 +15,7 @@ public class TestCaseDTO extends TestCaseWithBLOBs { private String apiName; private String performName; private String lastResultId; + private String projectName; private List caseTags = new ArrayList<>(); } diff --git a/backend/src/main/java/io/metersphere/track/dto/TestCaseReportMetricDTO.java b/backend/src/main/java/io/metersphere/track/dto/TestCaseReportMetricDTO.java index bd8f4c84a1..8275120d0b 100644 --- a/backend/src/main/java/io/metersphere/track/dto/TestCaseReportMetricDTO.java +++ b/backend/src/main/java/io/metersphere/track/dto/TestCaseReportMetricDTO.java @@ -1,6 +1,6 @@ package io.metersphere.track.dto; -import io.metersphere.base.domain.Issues; +import io.metersphere.base.domain.IssuesDao; import lombok.Getter; import lombok.Setter; @@ -15,7 +15,7 @@ public class TestCaseReportMetricDTO { private List moduleExecuteResult; private FailureTestCasesAdvanceDTO failureTestCases; // private List failureTestCases; - private List Issues; + private List Issues; private List executors; private String principal; private Long startTime; diff --git a/backend/src/main/java/io/metersphere/track/issue/AbstractIssuePlatform.java b/backend/src/main/java/io/metersphere/track/issue/AbstractIssuePlatform.java index 3f809848aa..6b7a6de183 100644 --- a/backend/src/main/java/io/metersphere/track/issue/AbstractIssuePlatform.java +++ b/backend/src/main/java/io/metersphere/track/issue/AbstractIssuePlatform.java @@ -1,6 +1,6 @@ package io.metersphere.track.issue; -import io.metersphere.base.domain.ServiceIntegration; +import io.metersphere.base.domain.*; import io.metersphere.base.mapper.IssuesMapper; import io.metersphere.base.mapper.TestCaseIssuesMapper; import io.metersphere.base.mapper.ext.ExtIssuesMapper; @@ -14,6 +14,7 @@ import io.metersphere.controller.request.IntegrationRequest; import io.metersphere.service.IntegrationService; import io.metersphere.service.ProjectService; import io.metersphere.track.request.testcase.IssuesRequest; +import io.metersphere.track.request.testcase.IssuesUpdateRequest; import io.metersphere.track.service.TestCaseService; import org.apache.commons.lang3.StringUtils; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; @@ -22,10 +23,13 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.springframework.http.HttpHeaders; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.util.CollectionUtils; import org.springframework.web.client.RestTemplate; import javax.net.ssl.SSLContext; import java.security.cert.X509Certificate; +import java.util.List; +import java.util.UUID; public abstract class AbstractIssuePlatform implements IssuesPlatform { @@ -41,6 +45,11 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform { protected RestTemplate restTemplateIgnoreSSL; protected String testCaseId; + protected String key; + + public String getKey() { + return key; + } static { try { @@ -112,4 +121,45 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform { return StringUtils.isNotBlank(integration.getId()); } + protected void insertTestCaseIssues(String issuesId, String caseId) { + if (StringUtils.isNotBlank(caseId)) { + TestCaseIssues testCaseIssues = new TestCaseIssues(); + testCaseIssues.setId(UUID.randomUUID().toString()); + testCaseIssues.setIssuesId(issuesId); + testCaseIssues.setTestCaseId(caseId); + testCaseIssuesMapper.insert(testCaseIssues); + } + } + + protected void handleIssueUpdate(IssuesUpdateRequest request) { + request.setUpdateTime(System.currentTimeMillis()); + issuesMapper.updateByPrimaryKeySelective(request); + handleTestCaseIssues(request); + } + + protected void handleTestCaseIssues(IssuesUpdateRequest issuesRequest) { + String issuesId = issuesRequest.getId(); + if (StringUtils.isNotBlank(issuesRequest.getTestCaseId())) { + insertTestCaseIssues(issuesId, issuesRequest.getTestCaseId()); + } else { + List testCaseIds = issuesRequest.getTestCaseIds(); + TestCaseIssuesExample example = new TestCaseIssuesExample(); + example.createCriteria().andIssuesIdEqualTo(issuesId); + testCaseIssuesMapper.deleteByExample(example); + if (!CollectionUtils.isEmpty(testCaseIds)) { + testCaseIds.forEach(caseId -> { + insertTestCaseIssues(issuesId, caseId); + }); + } + } + } + + protected void insertIssuesWithoutContext(String id, IssuesUpdateRequest issuesRequest) { + IssuesWithBLOBs issues = new IssuesWithBLOBs(); + issues.setId(id); + issues.setPlatform(issuesRequest.getPlatform()); + issues.setProjectId(issuesRequest.getProjectId()); + issues.setCustomFields(issuesRequest.getCustomFields()); + issuesMapper.insert(issues); + } } diff --git a/backend/src/main/java/io/metersphere/track/issue/IssueFactory.java b/backend/src/main/java/io/metersphere/track/issue/IssueFactory.java index b578caac05..3960a34ce2 100644 --- a/backend/src/main/java/io/metersphere/track/issue/IssueFactory.java +++ b/backend/src/main/java/io/metersphere/track/issue/IssueFactory.java @@ -5,7 +5,9 @@ import io.metersphere.track.request.testcase.IssuesRequest; import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class IssueFactory { public static AbstractIssuePlatform createPlatform(String platform, IssuesRequest addIssueRequest) { @@ -15,7 +17,7 @@ public class IssueFactory { return new JiraPlatform(addIssueRequest); } else if (StringUtils.equals(IssuesManagePlatform.Zentao.toString(), platform)) { return new ZentaoPlatform(addIssueRequest); - } else if (StringUtils.equals("LOCAL", platform)) { + } else if (StringUtils.equalsIgnoreCase(IssuesManagePlatform.Local.toString(), platform)) { return new LocalPlatform(addIssueRequest); } return null; @@ -31,4 +33,15 @@ public class IssueFactory { }); return platforms; } + + public static Map createPlatformsForMap(List types, IssuesRequest addIssueRequest) { + Map platformMap = new HashMap<>(); + types.forEach(type -> { + AbstractIssuePlatform abstractIssuePlatform = createPlatform(type, addIssueRequest); + if (abstractIssuePlatform != null) { + platformMap.put(type, abstractIssuePlatform); + } + }); + return platformMap; + } } diff --git a/backend/src/main/java/io/metersphere/track/issue/IssuesPlatform.java b/backend/src/main/java/io/metersphere/track/issue/IssuesPlatform.java index 8e70ef30a6..4a32253952 100644 --- a/backend/src/main/java/io/metersphere/track/issue/IssuesPlatform.java +++ b/backend/src/main/java/io/metersphere/track/issue/IssuesPlatform.java @@ -1,9 +1,10 @@ package io.metersphere.track.issue; -import io.metersphere.base.domain.Issues; +import io.metersphere.base.domain.IssuesDao; import io.metersphere.track.dto.DemandDTO; import io.metersphere.track.issue.domain.PlatformUser; import io.metersphere.track.request.testcase.IssuesRequest; +import io.metersphere.track.request.testcase.IssuesUpdateRequest; import java.util.List; @@ -14,7 +15,13 @@ public interface IssuesPlatform { * * @return platform issues list */ - List getIssue(); + List getIssue(IssuesRequest request); + + /** + * 过滤分页数据 + * @param issues + */ + void filter(List issues); /*获取平台相关需求*/ List getDemandList(String projectId); @@ -24,7 +31,13 @@ public interface IssuesPlatform { * * @param issuesRequest issueRequest */ - void addIssue(IssuesRequest issuesRequest); + void addIssue(IssuesUpdateRequest issuesRequest); + + /** + * 更新缺陷 + * @param request + */ + void updateIssue(IssuesUpdateRequest request); /** * 删除缺陷平台缺陷 diff --git a/backend/src/main/java/io/metersphere/track/issue/JiraPlatform.java b/backend/src/main/java/io/metersphere/track/issue/JiraPlatform.java index 437000f1cb..0287337ea2 100644 --- a/backend/src/main/java/io/metersphere/track/issue/JiraPlatform.java +++ b/backend/src/main/java/io/metersphere/track/issue/JiraPlatform.java @@ -5,12 +5,14 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import io.metersphere.base.domain.*; import io.metersphere.commons.constants.IssuesManagePlatform; +import io.metersphere.commons.constants.IssuesStatus; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.EncryptUtils; import io.metersphere.commons.utils.LogUtil; import io.metersphere.track.dto.DemandDTO; import io.metersphere.track.issue.domain.PlatformUser; import io.metersphere.track.request.testcase.IssuesRequest; +import io.metersphere.track.request.testcase.IssuesUpdateRequest; import org.apache.commons.lang3.StringUtils; import org.commonmark.node.Node; import org.commonmark.parser.Parser; @@ -28,40 +30,31 @@ import org.springframework.web.client.RestTemplate; import java.util.ArrayList; import java.util.List; -import java.util.UUID; import java.util.stream.Collectors; public class JiraPlatform extends AbstractIssuePlatform { + protected String key = IssuesManagePlatform.Jira.toString(); public JiraPlatform(IssuesRequest issuesRequest) { super(issuesRequest); } @Override - public List getIssue() { - List list = new ArrayList<>(); + public List getIssue(IssuesRequest issuesRequest) { + List list = new ArrayList<>(); + + issuesRequest.setPlatform(IssuesManagePlatform.Jira.toString()); + List issues = extIssuesMapper.getIssuesByCaseId(issuesRequest); String config = getPlatformConfig(IssuesManagePlatform.Jira.toString()); JSONObject object = JSON.parseObject(config); - - if (object == null) { - MSException.throwException("tapd config is null"); - } - - String account = object.getString("account"); - String password = object.getString("password"); + HttpHeaders headers = getAuthHeader(object); String url = object.getString("url"); - HttpHeaders headers = auth(account, password); - - TestCaseIssuesExample example = new TestCaseIssuesExample(); - example.createCriteria().andTestCaseIdEqualTo(testCaseId); - - List issues = extIssuesMapper.getIssues(testCaseId, IssuesManagePlatform.Jira.toString()); List issuesIds = issues.stream().map(Issues::getId).collect(Collectors.toList()); issuesIds.forEach(issuesId -> { - Issues dto = getJiraIssues(headers, url, issuesId); + IssuesDao dto = getJiraIssues(headers, url, issuesId); if (StringUtils.isBlank(dto.getId())) { // 缺陷不存在,解除用例和缺陷的关联 TestCaseIssuesExample issuesExample = new TestCaseIssuesExample(); @@ -80,6 +73,37 @@ public class JiraPlatform extends AbstractIssuePlatform { return list; } + public HttpHeaders getAuthHeader(JSONObject object) { + if (object == null) { + MSException.throwException("tapd config is null"); + } + + String account = object.getString("account"); + String password = object.getString("password"); + return auth(account, password); + } + + @Override + public void filter(List issues) { + String config = getPlatformConfig(IssuesManagePlatform.Jira.toString()); + JSONObject object = JSON.parseObject(config); + HttpHeaders headers = getAuthHeader(object); + String url = object.getString("url"); + + issues.forEach((issuesDao) -> { + IssuesDao dto = getJiraIssues(headers, url, issuesDao.getId()); + if (StringUtils.isBlank(dto.getId())) { + // 标记成删除 + issuesDao.setStatus(IssuesStatus.DELETE.toString()); + } else { + // 缺陷状态为 完成,则不显示 + if (!StringUtils.equals("done", dto.getStatus())) { + issuesDao.setStatus(IssuesStatus.RESOLVED.toString()); + } + } + }); + } + @Override public List getDemandList(String projectId) { List list = new ArrayList<>(); @@ -134,8 +158,9 @@ public class JiraPlatform extends AbstractIssuePlatform { } @Override - public void addIssue(IssuesRequest issuesRequest) { + public void addIssue(IssuesUpdateRequest issuesRequest) { String config = getPlatformConfig(IssuesManagePlatform.Jira.toString()); + issuesRequest.setPlatform(IssuesManagePlatform.Jira.toString()); JSONObject object = JSON.parseObject(config); if (object == null) { @@ -151,7 +176,6 @@ public class JiraPlatform extends AbstractIssuePlatform { } String auth = EncryptUtils.base64Encoding(account + ":" + password); - String testCaseId = issuesRequest.getTestCaseId(); String jiraKey = getProjectId(null); @@ -159,7 +183,7 @@ public class JiraPlatform extends AbstractIssuePlatform { MSException.throwException("未关联Jira 项目Key"); } - String content = issuesRequest.getContent(); + String content = issuesRequest.getDescription(); Document document = Jsoup.parse(content); document.outputSettings(new Document.OutputSettings().prettyPrint(false)); @@ -187,18 +211,19 @@ public class JiraPlatform extends AbstractIssuePlatform { JSONObject jsonObject = JSON.parseObject(result); String id = jsonObject.getString("key"); + issuesRequest.setId(id); // 用例与第三方缺陷平台中的缺陷关联 - TestCaseIssues testCaseIssues = new TestCaseIssues(); - testCaseIssues.setId(UUID.randomUUID().toString()); - testCaseIssues.setIssuesId(id); - testCaseIssues.setTestCaseId(testCaseId); - testCaseIssuesMapper.insert(testCaseIssues); + handleTestCaseIssues(issuesRequest); // 插入缺陷表 - Issues issues = new Issues(); - issues.setId(id); - issues.setPlatform(IssuesManagePlatform.Jira.toString()); - issuesMapper.insert(issues); + insertIssuesWithoutContext(id, issuesRequest); + } + + @Override + public void updateIssue(IssuesUpdateRequest request) { + // todo 调用接口 + request.setDescription(null); + handleIssueUpdate(request); } private String addJiraIssue(String url, String auth, String json) { @@ -258,12 +283,12 @@ public class JiraPlatform extends AbstractIssuePlatform { return project.getJiraKey(); } - private Issues getJiraIssues(HttpHeaders headers, String url, String issuesId) { + private IssuesDao getJiraIssues(HttpHeaders headers, String url, String issuesId) { HttpEntity requestEntity = new HttpEntity<>(headers); RestTemplate restTemplate = new RestTemplate(); //post ResponseEntity responseEntity; - Issues issues = new Issues(); + IssuesDao issues = new IssuesDao(); try { responseEntity = restTemplate.exchange(url + "/rest/api/2/issue/" + issuesId, HttpMethod.GET, requestEntity, String.class); String body = responseEntity.getBody(); @@ -307,7 +332,7 @@ public class JiraPlatform extends AbstractIssuePlatform { issues.setPlatform(IssuesManagePlatform.Jira.toString()); } catch (HttpClientErrorException.NotFound e) { LogUtil.error(e.getStackTrace(), e); - return new Issues(); + return new IssuesDao(); } catch (HttpClientErrorException.Unauthorized e) { LogUtil.error(e.getStackTrace(), e); MSException.throwException("获取Jira缺陷失败,检查Jira配置信息"); diff --git a/backend/src/main/java/io/metersphere/track/issue/LocalPlatform.java b/backend/src/main/java/io/metersphere/track/issue/LocalPlatform.java index 51479778e2..fa241c900e 100644 --- a/backend/src/main/java/io/metersphere/track/issue/LocalPlatform.java +++ b/backend/src/main/java/io/metersphere/track/issue/LocalPlatform.java @@ -1,26 +1,35 @@ package io.metersphere.track.issue; -import io.metersphere.base.domain.Issues; -import io.metersphere.base.domain.TestCaseIssues; +import io.metersphere.base.domain.IssuesDao; +import io.metersphere.base.domain.IssuesWithBLOBs; import io.metersphere.commons.constants.IssuesManagePlatform; import io.metersphere.commons.user.SessionUser; +import io.metersphere.commons.utils.BeanUtils; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.track.dto.DemandDTO; import io.metersphere.track.issue.domain.PlatformUser; import io.metersphere.track.request.testcase.IssuesRequest; +import io.metersphere.track.request.testcase.IssuesUpdateRequest; import java.util.List; import java.util.UUID; public class LocalPlatform extends AbstractIssuePlatform { + protected String key = IssuesManagePlatform.Local.toString(); + public LocalPlatform(IssuesRequest issuesRequest) { super(issuesRequest); } @Override - public List getIssue() { - return extIssuesMapper.getIssues(testCaseId, IssuesManagePlatform.Local.toString()); + public List getIssue(IssuesRequest issuesRequest) { + issuesRequest.setPlatform(IssuesManagePlatform.Local.toString()); + return extIssuesMapper.getIssuesByCaseId(issuesRequest); + } + + @Override + public void filter(List issues) { } @Override @@ -29,25 +38,26 @@ public class LocalPlatform extends AbstractIssuePlatform { } @Override - public void addIssue(IssuesRequest issuesRequest) { + public void addIssue(IssuesUpdateRequest issuesRequest) { SessionUser user = SessionUtils.getUser(); String id = UUID.randomUUID().toString(); - Issues issues = new Issues(); + IssuesWithBLOBs issues = new IssuesWithBLOBs(); + BeanUtils.copyBean(issues, issuesRequest); issues.setId(id); issues.setStatus("new"); issues.setReporter(user.getId()); - issues.setTitle(issuesRequest.getTitle()); - issues.setDescription(issuesRequest.getContent()); issues.setCreateTime(System.currentTimeMillis()); issues.setUpdateTime(System.currentTimeMillis()); - issues.setPlatform(IssuesManagePlatform.Local.toString()); + issues.setPlatform(IssuesManagePlatform.Local.toString());; issuesMapper.insert(issues); - TestCaseIssues testCaseIssues = new TestCaseIssues(); - testCaseIssues.setId(UUID.randomUUID().toString()); - testCaseIssues.setIssuesId(id); - testCaseIssues.setTestCaseId(issuesRequest.getTestCaseId()); - testCaseIssuesMapper.insert(testCaseIssues); + issuesRequest.setId(id); + handleTestCaseIssues(issuesRequest); + } + + @Override + public void updateIssue(IssuesUpdateRequest request) { + handleIssueUpdate(request); } @Override @@ -71,7 +81,7 @@ public class LocalPlatform extends AbstractIssuePlatform { } public void closeIssue(String issueId) { - Issues issues = new Issues(); + IssuesWithBLOBs issues = new IssuesWithBLOBs(); issues.setId(issueId); issues.setStatus("closed"); issuesMapper.updateByPrimaryKeySelective(issues); diff --git a/backend/src/main/java/io/metersphere/track/issue/TapdPlatform.java b/backend/src/main/java/io/metersphere/track/issue/TapdPlatform.java index 41efb3e496..db593ae54c 100644 --- a/backend/src/main/java/io/metersphere/track/issue/TapdPlatform.java +++ b/backend/src/main/java/io/metersphere/track/issue/TapdPlatform.java @@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import io.metersphere.base.domain.*; import io.metersphere.commons.constants.IssuesManagePlatform; +import io.metersphere.commons.constants.IssuesStatus; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.SessionUtils; @@ -12,6 +13,7 @@ import io.metersphere.controller.ResultHolder; import io.metersphere.track.dto.DemandDTO; import io.metersphere.track.issue.domain.PlatformUser; import io.metersphere.track.request.testcase.IssuesRequest; +import io.metersphere.track.request.testcase.IssuesUpdateRequest; import org.apache.commons.lang3.StringUtils; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; @@ -23,29 +25,30 @@ import org.springframework.web.client.RestTemplate; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.UUID; import java.util.stream.Collectors; public class TapdPlatform extends AbstractIssuePlatform { + protected String key = IssuesManagePlatform.Tapd.toString(); public TapdPlatform(IssuesRequest issueRequest) { super(issueRequest); } @Override - public List getIssue() { - List list = new ArrayList<>(); + public List getIssue(IssuesRequest issuesRequest) { + List list = new ArrayList<>(); String tapdId = getProjectId(""); TestCaseIssuesExample example = new TestCaseIssuesExample(); example.createCriteria().andTestCaseIdEqualTo(testCaseId); - List issues = extIssuesMapper.getIssues(testCaseId, IssuesManagePlatform.Tapd.toString()); + issuesRequest.setPlatform(IssuesManagePlatform.Tapd.toString()); + List issues = extIssuesMapper.getIssuesByCaseId(issuesRequest); List issuesIds = issues.stream().map(Issues::getId).collect(Collectors.toList()); issuesIds.forEach(issuesId -> { - Issues dto = getTapdIssues(tapdId, issuesId); + IssuesDao dto = getTapdIssues(tapdId, issuesId); if (StringUtils.isBlank(dto.getId())) { // 缺陷不存在,解除用例和缺陷的关联 TestCaseIssuesExample issuesExample = new TestCaseIssuesExample(); @@ -57,7 +60,7 @@ public class TapdPlatform extends AbstractIssuePlatform { } else { dto.setPlatform(IssuesManagePlatform.Tapd.toString()); // 缺陷状态为 关闭,则不显示 - if (!StringUtils.equals("closed", dto.getStatus())) { + if (!StringUtils.equals(IssuesStatus.CLOSED.toString(), dto.getStatus())) { list.add(dto); } } @@ -65,6 +68,30 @@ public class TapdPlatform extends AbstractIssuePlatform { return list; } + @Override + public void filter(List issues) { + String tapdId = ""; + for (IssuesDao item : issues) { + if (StringUtils.isNotBlank(item.getProjectId())) { + tapdId = getProjectId(issues.get(0).getProjectId()); + break; + } + } + + for (IssuesDao item : issues) { + IssuesDao dto = getTapdIssues(tapdId, item.getId()); + if (StringUtils.isBlank(dto.getId())) { + // 标记成删除 + item.setStatus(IssuesStatus.DELETE.toString()); + } else { + // 缺陷状态为 完成,则不显示 + if (!StringUtils.equals(IssuesStatus.CLOSED.toString(), dto.getStatus())) { + item.setStatus(IssuesStatus.CLOSED.toString()); + } + } + } + } + @Override public List getDemandList(String projectId) { List demandList = new ArrayList<>(); @@ -86,17 +113,17 @@ public class TapdPlatform extends AbstractIssuePlatform { return demandList; } - private Issues getTapdIssues(String projectId, String issuesId) { + private IssuesDao getTapdIssues(String projectId, String issuesId) { String url = "https://api.tapd.cn/bugs?workspace_id=" + projectId + "&id=" + issuesId; ResultHolder call = call(url); String listJson = JSON.toJSONString(call.getData()); if (StringUtils.equals(Boolean.FALSE.toString(), listJson)) { - return new Issues(); + return new IssuesDao(); } JSONObject jsonObject = JSONObject.parseObject(listJson); JSONObject bug = jsonObject.getJSONObject("Bug"); Long created = bug.getLong("created"); - Issues issues = jsonObject.getObject("Bug", Issues.class); + IssuesDao issues = jsonObject.getObject("Bug", IssuesDao.class); // 获取工作流中缺陷状态名称 String workflow = "https://api.tapd.cn/workflows/status_map?workspace_id=" + projectId + "&system=bug"; @@ -112,7 +139,9 @@ public class TapdPlatform extends AbstractIssuePlatform { } @Override - public void addIssue(IssuesRequest issuesRequest) { + public void addIssue(IssuesUpdateRequest issuesRequest) { + issuesRequest.setPlatform(IssuesManagePlatform.Tapd.toString()); + String url = "https://api.tapd.cn/bugs"; String testCaseId = issuesRequest.getTestCaseId(); String tapdId = getProjectId(""); @@ -129,7 +158,7 @@ public class TapdPlatform extends AbstractIssuePlatform { MultiValueMap paramMap = new LinkedMultiValueMap<>(); paramMap.add("title", issuesRequest.getTitle()); paramMap.add("workspace_id", tapdId); - paramMap.add("description", issuesRequest.getContent()); + paramMap.add("description", issuesRequest.getDescription()); paramMap.add("reporter", username); paramMap.add("current_owner", usersStr); @@ -139,18 +168,19 @@ public class TapdPlatform extends AbstractIssuePlatform { JSONObject jsonObject = JSONObject.parseObject(listJson); String issuesId = jsonObject.getObject("Bug", Issues.class).getId(); + issuesRequest.setId(issuesId); // 用例与第三方缺陷平台中的缺陷关联 - TestCaseIssues testCaseIssues = new TestCaseIssues(); - testCaseIssues.setId(UUID.randomUUID().toString()); - testCaseIssues.setIssuesId(issuesId); - testCaseIssues.setTestCaseId(testCaseId); - testCaseIssuesMapper.insert(testCaseIssues); + handleTestCaseIssues(issuesRequest); // 插入缺陷表 - Issues issues = new Issues(); - issues.setId(issuesId); - issues.setPlatform(IssuesManagePlatform.Tapd.toString()); - issuesMapper.insert(issues); + insertIssuesWithoutContext(issuesId, issuesRequest); + } + + @Override + public void updateIssue(IssuesUpdateRequest request) { + // todo 调用接口 + request.setDescription(null); + handleIssueUpdate(request); } @Override diff --git a/backend/src/main/java/io/metersphere/track/issue/ZentaoPlatform.java b/backend/src/main/java/io/metersphere/track/issue/ZentaoPlatform.java index 2659cb1c88..47a10632c9 100644 --- a/backend/src/main/java/io/metersphere/track/issue/ZentaoPlatform.java +++ b/backend/src/main/java/io/metersphere/track/issue/ZentaoPlatform.java @@ -5,12 +5,14 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import io.metersphere.base.domain.*; import io.metersphere.commons.constants.IssuesManagePlatform; +import io.metersphere.commons.constants.IssuesStatus; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.LogUtil; import io.metersphere.track.dto.DemandDTO; import io.metersphere.track.issue.domain.PlatformUser; import io.metersphere.track.issue.domain.ZentaoBuild; import io.metersphere.track.request.testcase.IssuesRequest; +import io.metersphere.track.request.testcase.IssuesUpdateRequest; import org.apache.commons.lang3.StringUtils; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; @@ -38,6 +40,8 @@ public class ZentaoPlatform extends AbstractIssuePlatform { */ private final String url; + protected String key = IssuesManagePlatform.Zentao.toString(); + public ZentaoPlatform(IssuesRequest issuesRequest) { super(issuesRequest); String config = getPlatformConfig(IssuesManagePlatform.Zentao.toString()); @@ -58,17 +62,19 @@ public class ZentaoPlatform extends AbstractIssuePlatform { } @Override - public List getIssue() { - List list = new ArrayList<>(); + public List getIssue(IssuesRequest issuesRequest) { + List list = new ArrayList<>(); TestCaseIssuesExample example = new TestCaseIssuesExample(); example.createCriteria().andTestCaseIdEqualTo(testCaseId); - List issues = extIssuesMapper.getIssues(testCaseId, IssuesManagePlatform.Zentao.toString()); + issuesRequest.setPlatform(IssuesManagePlatform.Zentao.toString()); + + List issues = extIssuesMapper.getIssuesByCaseId(issuesRequest); List issuesIds = issues.stream().map(Issues::getId).collect(Collectors.toList()); issuesIds.forEach(issuesId -> { - Issues dto = getZentaoIssues(issuesId); + IssuesDao dto = getZentaoIssues(issuesId); if (StringUtils.isBlank(dto.getId())) { // 缺陷不存在,解除用例和缺陷的关联 TestCaseIssuesExample issuesExample = new TestCaseIssuesExample(); @@ -89,6 +95,22 @@ public class ZentaoPlatform extends AbstractIssuePlatform { } + @Override + public void filter(List issues) { + issues.forEach((issuesDao) -> { + IssuesDao dto = getZentaoIssues(issuesDao.getId()); + if (StringUtils.isBlank(dto.getId())) { + // 标记成删除 + issuesDao.setStatus(IssuesStatus.DELETE.toString()); + } else { + // 缺陷状态为 完成,则不显示 + if (!StringUtils.equals("done", dto.getStatus())) { + issuesDao.setStatus(IssuesStatus.RESOLVED.toString()); + } + } + }); + } + @Override public List getDemandList(String projectId) { //getTestStories @@ -126,7 +148,7 @@ public class ZentaoPlatform extends AbstractIssuePlatform { return list; } - private Issues getZentaoIssues(String bugId) { + private IssuesDao getZentaoIssues(String bugId) { String session = login(); HttpEntity requestEntity = new HttpEntity<>(new HttpHeaders()); RestTemplate restTemplate = new RestTemplate(); @@ -148,9 +170,9 @@ public class ZentaoPlatform extends AbstractIssuePlatform { String reporter = bug.getString("openedBy"); int deleted = bug.getInteger("deleted"); if (deleted == 1) { - return new Issues(); + return new IssuesDao(); } - Issues issues = new Issues(); + IssuesDao issues = new IssuesDao(); issues.setId(id); issues.setTitle(title); issues.setDescription(description); @@ -163,11 +185,12 @@ public class ZentaoPlatform extends AbstractIssuePlatform { LogUtil.error("get zentao bug fail " + e.getMessage()); } - return new Issues(); + return new IssuesDao(); } @Override - public void addIssue(IssuesRequest issuesRequest) { + public void addIssue(IssuesUpdateRequest issuesRequest) { + issuesRequest.setPlatform(IssuesManagePlatform.Zentao.toString()); String session = login(); String projectId = getProjectId(null); @@ -183,7 +206,7 @@ public class ZentaoPlatform extends AbstractIssuePlatform { MultiValueMap paramMap = new LinkedMultiValueMap<>(); paramMap.add("product", projectId); paramMap.add("title", issuesRequest.getTitle()); - paramMap.add("steps", issuesRequest.getContent()); + paramMap.add("steps", issuesRequest.getDescription()); if (!CollectionUtils.isEmpty(issuesRequest.getZentaoBuilds())) { List builds = issuesRequest.getZentaoBuilds(); builds.forEach(build -> { @@ -208,27 +231,28 @@ public class ZentaoPlatform extends AbstractIssuePlatform { JSONObject data = obj.getJSONObject("data"); String id = data.getString("id"); if (StringUtils.isNotBlank(id)) { + issuesRequest.setId(id); // 用例与第三方缺陷平台中的缺陷关联 - TestCaseIssues testCaseIssues = new TestCaseIssues(); - testCaseIssues.setId(UUID.randomUUID().toString()); - testCaseIssues.setIssuesId(id); - testCaseIssues.setTestCaseId(testCaseId); - testCaseIssuesMapper.insert(testCaseIssues); + handleTestCaseIssues(issuesRequest); IssuesExample issuesExample = new IssuesExample(); issuesExample.createCriteria().andIdEqualTo(id) .andPlatformEqualTo(IssuesManagePlatform.Zentao.toString()); if (issuesMapper.selectByExample(issuesExample).size() <= 0) { // 插入缺陷表 - Issues issues = new Issues(); - issues.setId(id); - issues.setPlatform(IssuesManagePlatform.Zentao.toString()); - issuesMapper.insert(issues); + insertIssuesWithoutContext(id, issuesRequest); } } } } + @Override + public void updateIssue(IssuesUpdateRequest request) { + // todo 调用接口 + request.setDescription(null); + handleIssueUpdate(request); + } + @Override public void deleteIssue(String id) { diff --git a/backend/src/main/java/io/metersphere/track/request/issues/IssuesRelevanceRequest.java b/backend/src/main/java/io/metersphere/track/request/issues/IssuesRelevanceRequest.java new file mode 100644 index 0000000000..7e5b724674 --- /dev/null +++ b/backend/src/main/java/io/metersphere/track/request/issues/IssuesRelevanceRequest.java @@ -0,0 +1,29 @@ +package io.metersphere.track.request.issues; + +import io.metersphere.track.request.testcase.QueryTestCaseRequest; +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +public class IssuesRelevanceRequest { + /** + * 缺陷ID + */ + private String issuesId; + + /** + * 当选择关联全部用例时把加载条件送到后台,从后台查询 + */ + private QueryTestCaseRequest request; + + /** + * 具体要关联的用例 + */ + private List testCaseIds = new ArrayList<>(); + + private Boolean checked; +} diff --git a/backend/src/main/java/io/metersphere/track/request/testcase/IssuesRequest.java b/backend/src/main/java/io/metersphere/track/request/testcase/IssuesRequest.java index 127e18a0d5..5235715529 100644 --- a/backend/src/main/java/io/metersphere/track/request/testcase/IssuesRequest.java +++ b/backend/src/main/java/io/metersphere/track/request/testcase/IssuesRequest.java @@ -1,5 +1,6 @@ package io.metersphere.track.request.testcase; +import io.metersphere.controller.request.BaseQueryRequest; import lombok.Getter; import lombok.Setter; @@ -7,7 +8,7 @@ import java.util.List; @Getter @Setter -public class IssuesRequest { +public class IssuesRequest extends BaseQueryRequest { private String title; private String content; private String projectId; @@ -27,4 +28,7 @@ public class IssuesRequest { */ private String id; private String caseId; + private String platform; + private String customFields; + private List testCaseIds; } diff --git a/backend/src/main/java/io/metersphere/track/request/testcase/IssuesUpdateRequest.java b/backend/src/main/java/io/metersphere/track/request/testcase/IssuesUpdateRequest.java new file mode 100644 index 0000000000..b45af3d259 --- /dev/null +++ b/backend/src/main/java/io/metersphere/track/request/testcase/IssuesUpdateRequest.java @@ -0,0 +1,24 @@ +package io.metersphere.track.request.testcase; + +import io.metersphere.base.domain.IssuesWithBLOBs; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +public class IssuesUpdateRequest extends IssuesWithBLOBs { + private String content; + private String testCaseId; + private List tapdUsers; + /** + * zentao bug 处理人 + */ + private String zentaoUser; + /** + * zentao bug 影响版本 + */ + private List zentaoBuilds; + private List testCaseIds; +} diff --git a/backend/src/main/java/io/metersphere/track/request/testcase/QueryTestCaseRequest.java b/backend/src/main/java/io/metersphere/track/request/testcase/QueryTestCaseRequest.java index 69cbe332a8..93230b9558 100644 --- a/backend/src/main/java/io/metersphere/track/request/testcase/QueryTestCaseRequest.java +++ b/backend/src/main/java/io/metersphere/track/request/testcase/QueryTestCaseRequest.java @@ -19,6 +19,8 @@ public class QueryTestCaseRequest extends BaseQueryRequest { private String planId; + private String issuesId; + private String userId; private String reviewId; @@ -30,4 +32,5 @@ public class QueryTestCaseRequest extends BaseQueryRequest { private long createTime = 0; private long relevanceCreateTime = 0; + private List testCaseContainIds; } diff --git a/backend/src/main/java/io/metersphere/track/service/IssuesService.java b/backend/src/main/java/io/metersphere/track/service/IssuesService.java index ee737fcf8c..e32cc9ae8f 100644 --- a/backend/src/main/java/io/metersphere/track/service/IssuesService.java +++ b/backend/src/main/java/io/metersphere/track/service/IssuesService.java @@ -3,9 +3,11 @@ package io.metersphere.track.service; import io.metersphere.base.domain.*; import io.metersphere.base.mapper.IssuesMapper; import io.metersphere.base.mapper.TestCaseIssuesMapper; +import io.metersphere.base.mapper.ext.ExtIssuesMapper; import io.metersphere.commons.constants.IssuesManagePlatform; import io.metersphere.commons.constants.NoticeConstants; import io.metersphere.commons.user.SessionUser; +import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.controller.request.IntegrationRequest; import io.metersphere.i18n.Translator; @@ -13,11 +15,17 @@ import io.metersphere.notice.sender.NoticeModel; import io.metersphere.notice.service.NoticeSendService; import io.metersphere.service.IntegrationService; import io.metersphere.service.ProjectService; -import io.metersphere.track.issue.*; +import io.metersphere.track.issue.AbstractIssuePlatform; +import io.metersphere.track.issue.IssueFactory; +import io.metersphere.track.issue.ZentaoPlatform; import io.metersphere.track.issue.domain.PlatformUser; import io.metersphere.track.issue.domain.ZentaoBuild; import io.metersphere.track.request.testcase.IssuesRequest; +import io.metersphere.track.request.testcase.IssuesUpdateRequest; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.ibatis.session.SqlSessionFactory; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -35,6 +43,7 @@ public class IssuesService { private IntegrationService integrationService; @Resource private ProjectService projectService; + @Lazy @Resource private TestCaseService testCaseService; @Resource @@ -43,53 +52,27 @@ public class IssuesService { private NoticeSendService noticeSendService; @Resource private TestCaseIssuesMapper testCaseIssuesMapper; + @Resource + private SqlSessionFactory sqlSessionFactory; + @Resource + private ExtIssuesMapper extIssuesMapper; public void testAuth(String platform) { AbstractIssuePlatform abstractPlatform = IssueFactory.createPlatform(platform, new IssuesRequest()); abstractPlatform.testAuth(); } - public void addIssues(IssuesRequest issuesRequest) { - SessionUser user = SessionUtils.getUser(); - String orgId = user.getLastOrganizationId(); - - boolean tapd = isIntegratedPlatform(orgId, IssuesManagePlatform.Tapd.toString()); - boolean jira = isIntegratedPlatform(orgId, IssuesManagePlatform.Jira.toString()); - boolean zentao = isIntegratedPlatform(orgId, IssuesManagePlatform.Zentao.toString()); - - String tapdId = getTapdProjectId(issuesRequest.getTestCaseId()); - String jiraKey = getJiraProjectKey(issuesRequest.getTestCaseId()); - String zentaoId = getZentaoProjectId(issuesRequest.getTestCaseId()); - - List platforms = new ArrayList<>(); - - if (tapd) { - // 是否关联了项目 - if (StringUtils.isNotBlank(tapdId)) { - platforms.add(IssuesManagePlatform.Tapd.name()); - } - } - - if (jira) { - if (StringUtils.isNotBlank(jiraKey)) { - platforms.add(IssuesManagePlatform.Jira.name()); - } - } - - if (zentao) { - if (StringUtils.isNotBlank(zentaoId)) { - platforms.add(IssuesManagePlatform.Zentao.name()); - } - } - - if (StringUtils.isBlank(tapdId) && StringUtils.isBlank(jiraKey) && StringUtils.isBlank(zentaoId)) { - platforms.add("LOCAL"); - } - - List platformList = IssueFactory.createPlatforms(platforms, issuesRequest); + public void addIssues(IssuesUpdateRequest issuesRequest) { + List platformList = getUpdatePlatforms(issuesRequest); platformList.forEach(platform -> { platform.addIssue(issuesRequest); }); + noticeIssueEven(issuesRequest, "IssuesCreate"); + } + + public void noticeIssueEven(IssuesUpdateRequest issuesRequest, String type) { + SessionUser user = SessionUtils.getUser(); + String orgId = user.getLastOrganizationId(); List userIds = new ArrayList<>(); userIds.add(orgId); String context = getIssuesContext(user, issuesRequest, NoticeConstants.Event.CREATE); @@ -100,18 +83,75 @@ public class IssuesService { .context(context) .relatedUsers(userIds) .subject(Translator.get("task_defect_notification")) - .mailTemplate("IssuesCreate") + .mailTemplate(type) .paramMap(paramMap) .event(NoticeConstants.Event.CREATE) .build(); noticeSendService.send(NoticeConstants.TaskType.DEFECT_TASK, noticeModel); } - public List getIssues(String caseId) { - List list = new ArrayList<>(); + + public void updateIssues(IssuesUpdateRequest issuesRequest) { + List platformList = getUpdatePlatforms(issuesRequest); + platformList.forEach(platform -> { + platform.updateIssue(issuesRequest); + }); + // todo 缺陷更新事件? + } + + public List getUpdatePlatforms(IssuesUpdateRequest updateRequest) { + List platforms = null; + if (StringUtils.isNotBlank(updateRequest.getTestCaseId())) { + // 测试计划关联 + platforms = getPlatformsByCaseId(updateRequest.getTestCaseId()); + } else { + // 缺陷管理关联 + platforms = getPlatformsByProjectId(updateRequest.getProjectId()); + } + + if (CollectionUtils.isEmpty(platforms)) { + platforms.add("LOCAL"); + } + IssuesRequest issuesRequest = new IssuesRequest(); + issuesRequest.setTestCaseId(updateRequest.getTestCaseId()); + return IssueFactory.createPlatforms(platforms, issuesRequest); + } + + public List getIssues(String caseId) { + IssuesRequest issueRequest = new IssuesRequest(); + issueRequest.setTestCaseId(caseId); + ServiceUtils.getDefaultOrder(issueRequest.getOrders()); + Project project = getProjectByCaseId(caseId); + return getIssuesByProject(issueRequest, project); + } + public List getIssuesByProject(IssuesRequest issueRequest, Project project) { + List list = new ArrayList<>(); + List platforms = getPlatforms(project); + platforms.add(IssuesManagePlatform.Local.toString()); + List platformList = IssueFactory.createPlatforms(platforms, issueRequest); + platformList.forEach(platform -> { + List issue = platform.getIssue(issueRequest); + list.addAll(issue); + }); + + return list; + } + + public List getPlatformsByProjectId(String projectId) { + return getPlatforms(projectService.getProjectById(projectId)); + } + + public List getPlatformsByCaseId(String caseId) { + TestCaseWithBLOBs testCase = testCaseService.getTestCase(caseId); + Project project = projectService.getProjectById(testCase.getProjectId()); + List platforms = getPlatforms(project); + platforms.add("LOCAL"); + return getPlatforms(project); + } + + public List getPlatforms(Project project) { SessionUser user = SessionUtils.getUser(); String orgId = user.getLastOrganizationId(); - boolean tapd = isIntegratedPlatform(orgId, IssuesManagePlatform.Tapd.toString()); boolean jira = isIntegratedPlatform(orgId, IssuesManagePlatform.Jira.toString()); boolean zentao = isIntegratedPlatform(orgId, IssuesManagePlatform.Zentao.toString()); @@ -119,7 +159,7 @@ public class IssuesService { List platforms = new ArrayList<>(); if (tapd) { // 是否关联了项目 - String tapdId = getTapdProjectId(caseId); + String tapdId = project.getTapdId(); if (StringUtils.isNotBlank(tapdId)) { platforms.add(IssuesManagePlatform.Tapd.name()); } @@ -127,29 +167,25 @@ public class IssuesService { } if (jira) { - String jiraKey = getJiraProjectKey(caseId); + String jiraKey = project.getJiraKey(); if (StringUtils.isNotBlank(jiraKey)) { platforms.add(IssuesManagePlatform.Jira.name()); } } if (zentao) { - String zentaoId = getZentaoProjectId(caseId); + String zentaoId = project.getZentaoId(); if (StringUtils.isNotBlank(zentaoId)) { platforms.add(IssuesManagePlatform.Zentao.name()); } } + return platforms; + } - platforms.add("LOCAL"); - IssuesRequest issueRequest = new IssuesRequest(); - issueRequest.setTestCaseId(caseId); - List platformList = IssueFactory.createPlatforms(platforms, issueRequest); - platformList.forEach(platform -> { - List issue = platform.getIssue(); - list.addAll(issue); - }); - - return list; + private Project getProjectByCaseId(String testCaseId) { + TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId); + Project project = projectService.getProjectById(testCase.getProjectId()); + return project; } private String getTapdProjectId(String testCaseId) { @@ -182,7 +218,7 @@ public class IssuesService { } public void closeLocalIssue(String issueId) { - Issues issues = new Issues(); + IssuesWithBLOBs issues = new IssuesWithBLOBs(); issues.setId(issueId); issues.setStatus("closed"); issuesMapper.updateByPrimaryKeySelective(issues); @@ -212,7 +248,7 @@ public class IssuesService { testCaseIssuesMapper.deleteByExample(example); } - private static String getIssuesContext(SessionUser user, IssuesRequest issuesRequest, String type) { + private static String getIssuesContext(SessionUser user, IssuesUpdateRequest issuesRequest, String type) { String context = ""; if (StringUtils.equals(NoticeConstants.Event.CREATE, type)) { context = "缺陷任务通知:" + user.getName() + "发起了一个缺陷" + "'" + issuesRequest.getTitle() + "'" + "请跟进"; @@ -226,4 +262,41 @@ public class IssuesService { ZentaoPlatform platform = (ZentaoPlatform) IssueFactory.createPlatform(IssuesManagePlatform.Zentao.name(), issueRequest); return platform.getBuilds(); } + + public List list(IssuesRequest request) { + request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders())); + List issues = extIssuesMapper.getIssuesByProjectId(request); + Map> issueMap = getIssueMap(issues); + Map platformMap = getPlatformMap(request); + issueMap.forEach((platformName, data) -> { + AbstractIssuePlatform platform = platformMap.get(platformName); + platform.filter(data); + }); + return issues; + } + + public Map> getIssueMap(List issues) { + Map> issueMap = new HashMap<>(); + issues.forEach(item -> { + String platForm = item.getPlatform(); + if (StringUtils.equalsIgnoreCase(IssuesManagePlatform.Local.toString(), item.getPlatform())) { + // 可能有大小写的问题 + platForm = IssuesManagePlatform.Local.toString(); + } + List issuesDao = issueMap.get(platForm); + if (issuesDao == null) { + issuesDao = new ArrayList<>(); + } + issuesDao.add(item); + issueMap.put(platForm, issuesDao); + }); + return issueMap; + } + + public Map getPlatformMap(IssuesRequest request) { + Project project = projectService.getProjectById(request.getProjectId()); + List platforms = getPlatforms(project); + platforms.add(IssuesManagePlatform.Local.toString()); + return IssueFactory.createPlatformsForMap(platforms, request); + } } diff --git a/backend/src/main/java/io/metersphere/track/service/TestCaseIssueService.java b/backend/src/main/java/io/metersphere/track/service/TestCaseIssueService.java index de4505799f..5f711f0664 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestCaseIssueService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestCaseIssueService.java @@ -4,6 +4,9 @@ import io.metersphere.base.domain.TestCaseIssues; import io.metersphere.base.domain.TestCaseIssuesExample; import io.metersphere.base.mapper.IssuesMapper; import io.metersphere.base.mapper.TestCaseIssuesMapper; +import io.metersphere.track.dto.TestCaseDTO; +import io.metersphere.track.request.issues.IssuesRelevanceRequest; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; @@ -18,6 +21,9 @@ public class TestCaseIssueService { @Resource private TestCaseIssuesMapper testCaseIssuesMapper; + @Lazy + @Resource + private TestCaseService testCaseService; @Resource private IssuesMapper issuesMapper; @@ -33,4 +39,23 @@ public class TestCaseIssueService { } testCaseIssuesMapper.deleteByExample(example); } + + public List list(IssuesRelevanceRequest request) { + List testCaseIds = getTestCaseIdsByIssuesId(request.getIssuesId()); + List list = testCaseService.getTestCaseByIds(testCaseIds); + testCaseService.addProjectName(list); + return list; + } + + public List getTestCaseIssuesByIssuesId(String issuesId) { + TestCaseIssuesExample example = new TestCaseIssuesExample(); + example.createCriteria().andIssuesIdEqualTo(issuesId); + return testCaseIssuesMapper.selectByExample(example); + } + + public List getTestCaseIdsByIssuesId(String issuesId) { + return getTestCaseIssuesByIssuesId(issuesId).stream() + .map(TestCaseIssues::getTestCaseId) + .collect(Collectors.toList()); + } } diff --git a/backend/src/main/java/io/metersphere/track/service/TestCaseNodeService.java b/backend/src/main/java/io/metersphere/track/service/TestCaseNodeService.java index 636deb6ac0..85492cee02 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestCaseNodeService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestCaseNodeService.java @@ -337,13 +337,15 @@ public class TestCaseNodeService extends NodeTreeService { public List getAllNodeByPlanId(QueryNodeRequest request) { String planId = request.getTestPlanId(); - String projectId = request.getProjectId(); TestPlan testPlan = testPlanMapper.selectByPrimaryKey(planId); if (testPlan == null) { return Collections.emptyList(); } + return getAllNodeByProjectId(request); + } - return getNodeTreeByProjectId(projectId); + public List getAllNodeByProjectId(QueryNodeRequest request) { + return getNodeTreeByProjectId(request.getProjectId()); } public List getAllNodeByReviewId(QueryNodeRequest request) { diff --git a/backend/src/main/java/io/metersphere/track/service/TestCaseService.java b/backend/src/main/java/io/metersphere/track/service/TestCaseService.java index 11c9135293..1687cbd437 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestCaseService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestCaseService.java @@ -23,6 +23,7 @@ import io.metersphere.excel.listener.TestCaseDataListener; import io.metersphere.excel.utils.EasyExcelExporter; import io.metersphere.i18n.Translator; import io.metersphere.service.FileService; +import io.metersphere.service.ProjectService; import io.metersphere.track.dto.TestCaseDTO; import io.metersphere.track.request.testcase.EditTestCaseRequest; import io.metersphere.track.request.testcase.QueryTestCaseRequest; @@ -35,6 +36,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -70,6 +72,10 @@ public class TestCaseService { @Resource ProjectMapper projectMapper; + @Lazy + @Resource + ProjectService projectService; + @Resource SqlSessionFactory sqlSessionFactory; @@ -278,16 +284,41 @@ public class TestCaseService { * @param request * @return */ - public List getTestCaseNames(QueryTestCaseRequest request) { + public List getTestCaseRelateList(QueryTestCaseRequest request) { List orderList = ServiceUtils.getDefaultOrder(request.getOrders()); OrderRequest order = new OrderRequest(); order.setName("sort"); order.setType("desc"); orderList.add(order); request.setOrders(orderList); + return getTestCaseByNotInPlan(request); + } + + public List getTestCaseByNotInPlan(QueryTestCaseRequest request) { return extTestCaseMapper.getTestCaseByNotInPlan(request); } + public List getTestCaseByNotInIssue(QueryTestCaseRequest request) { + List list = extTestCaseMapper.getTestCaseByNotInIssue(request); + addProjectName(list); + return list; + } + + public void addProjectName(List list) { + List projectIds = list.stream() + .map(TestCase::getProjectId) + .collect(Collectors.toList()); + List projects = projectService.getProjectByIds(projectIds); + Map projectMap = projects.stream() + .collect(Collectors.toMap(Project::getId, Project::getName)); + list.forEach(item -> { + String projectName = projectMap.get(item.getProjectId()); + if (StringUtils.isNotBlank(projectName)) { + item.setProjectName(projectName); + } + }); + } + public List getReviewCase(QueryTestCaseRequest request) { List orderList = ServiceUtils.getDefaultOrder(request.getOrders()); OrderRequest order = new OrderRequest(); @@ -925,4 +956,17 @@ public class TestCaseService { public List listTestCaseForMinder(QueryTestCaseRequest request) { return extTestCaseMapper.listForMinder(request); } + + public List getTestCaseByIds(List testCaseIds) { + if (CollectionUtils.isNotEmpty(testCaseIds)) { + return extTestCaseMapper.getTestCaseByIds(testCaseIds); + } else { + return new ArrayList<>(); + } + } + + public List getTestCaseIssueRelateList(QueryTestCaseRequest request) { + request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders())); + return getTestCaseByNotInIssue(request); + } } diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanReportService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanReportService.java index b367467eaa..81cd84ae51 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanReportService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanReportService.java @@ -271,7 +271,7 @@ public class TestPlanReportService { testPlanService.buildLoadCaseReport(testPlanReport.getTestPlanId(), components); if (StringUtils.equals(ReportTriggerMode.MANUAL.name(), triggerMode)) { - List issues = testPlanService.buildFunctionalCaseReport(testPlanReport.getTestPlanId(), components); + List issues = testPlanService.buildFunctionalCaseReport(testPlanReport.getTestPlanId(), components); issuesInfo = JSONArray.toJSONString(issues); } diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanService.java index ef4a14564b..b601b379fd 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanService.java @@ -133,6 +133,9 @@ public class TestPlanService { private ApiScenarioReportMapper apiScenarioReportMapper; @Resource private TestPlanReportMapper testPlanReportMapper; + @Lazy + @Resource + private IssuesService issuesService; public synchronized String addTestPlan(AddTestPlanRequest testPlan) { if (getTestPlanByName(testPlan.getName()).size() > 0) { @@ -620,7 +623,7 @@ public class TestPlanService { JSONArray componentIds = content.getJSONArray("components"); List components = ReportComponentFactory.createComponents(componentIds.toJavaList(String.class), testPlan); - List issues = buildFunctionalCaseReport(planId, components); + List issues = buildFunctionalCaseReport(planId, components); buildApiCaseReport(planId, components); buildScenarioCaseReport(planId, components); buildLoadCaseReport(planId, components); @@ -780,7 +783,7 @@ public class TestPlanService { JSONArray componentIds = content.getJSONArray("components"); List components = ReportComponentFactory.createComponents(componentIds.toJavaList(String.class), testPlan); - List issues = buildFunctionalCaseReport(planId, components); + List issues = buildFunctionalCaseReport(planId, components); buildApiCaseReport(planId, components); buildScenarioCaseReport(planId, components); buildLoadCaseReport(planId, components); @@ -826,14 +829,13 @@ public class TestPlanService { } } - public List buildFunctionalCaseReport(String planId, List components) { - IssuesService issuesService = (IssuesService) CommonBeanFactory.getBean("issuesService"); + public List buildFunctionalCaseReport(String planId, List components) { List testPlanTestCases = listTestCaseByPlanId(planId); - List issues = new ArrayList<>(); + List issues = new ArrayList<>(); for (TestPlanCaseDTO testCase : testPlanTestCases) { - List issue = issuesService.getIssues(testCase.getCaseId()); + List issue = issuesService.getIssues(testCase.getCaseId()); if (issue.size() > 0) { - for (Issues i : issue) { + for (IssuesDao i : issue) { i.setModel(testCase.getNodePath()); i.setProjectName(testCase.getProjectName()); String des = i.getDescription().replaceAll("

", "").replaceAll("

", ""); diff --git a/backend/src/main/resources/db/migration/V80__v1.9.0_release.sql b/backend/src/main/resources/db/migration/V80__v1.9.0_release.sql index 38edefb1e4..5f862857e1 100644 --- a/backend/src/main/resources/db/migration/V80__v1.9.0_release.sql +++ b/backend/src/main/resources/db/migration/V80__v1.9.0_release.sql @@ -37,7 +37,7 @@ VALUES ('09642424-7b1b-4004-867e-ff9c798a1933','i43sf4_issueCreator','ISSUE','me INSERT INTO custom_field (id,name,scene,`type`,remark,`options`,`system`,`global`,workspace_id,create_time,update_time) VALUES ('a577bc60-75fe-47ec-8aa6-32dca23bf3d6','i43sf4_issueProcessor','ISSUE','member','','[]',1,1,'global',unix_timestamp() * 1000,unix_timestamp() * 1000); INSERT INTO custom_field (id,name,scene,`type`,remark,`options`,`system`,`global`,workspace_id,create_time,update_time) -VALUES ('beb57501-19c8-4ca3-8dfb-2cef7c0ea087','i43sf4_issueStatus','ISSUE','select','','[{"text":"test_track.issue.status_new","value":"NEW","system": true},{"text":"test_track.issue.status_resolved","value":"RESOLVED","system": true},{"text":"test_track.issue.status_closed","value":"CLOSED","system": true}]',1,1,'global',unix_timestamp() * 1000,unix_timestamp() * 1000); +VALUES ('beb57501-19c8-4ca3-8dfb-2cef7c0ea087','i43sf4_issueStatus','ISSUE','select','','[{"text":"test_track.issue.status_new","value":"new","system": true},{"text":"test_track.issue.status_resolved","value":"resolved","system": true},{"text":"test_track.issue.status_closed","value":"closed","system": true}]',1,1,'global',unix_timestamp() * 1000,unix_timestamp() * 1000); INSERT INTO custom_field (id,name,scene,`type`,remark,`options`,`system`,`global`,workspace_id,create_time,update_time) VALUES ('d392af07-fdfe-4475-a459-87d59f0b1626','i43sf4_issueSeverity','ISSUE','select','','[{"text":"P0","value":"P0","system": true},{"text":"P1","value":"P1","system": true},{"text":"P2","value":"P2","system": true},{"text":"P3","value":"P3","system": true}]',1,1,'global',unix_timestamp() * 1000,unix_timestamp() * 1000); @@ -119,7 +119,7 @@ VALUES ('657e70c3-0d1b-4bbe-b52f-bfadee05148a','09642424-7b1b-4004-867e-ff9c798a INSERT INTO custom_field_template (id,field_id,template_id,scene,required,default_value) VALUES ('b8921cbc-05b3-4d8f-a96e-d1e4ae9d8664','a577bc60-75fe-47ec-8aa6-32dca23bf3d6','5d7c87d2-f405-4ec1-9a3d-71b514cdfda3','ISSUE',1,''); INSERT INTO custom_field_template (id,field_id,template_id,scene,required,default_value) -VALUES ('d5908553-1b29-4868-9001-e938822b92ef','beb57501-19c8-4ca3-8dfb-2cef7c0ea087','5d7c87d2-f405-4ec1-9a3d-71b514cdfda3','ISSUE',1,'"NEW"'); +VALUES ('d5908553-1b29-4868-9001-e938822b92ef','beb57501-19c8-4ca3-8dfb-2cef7c0ea087','5d7c87d2-f405-4ec1-9a3d-71b514cdfda3','ISSUE',1,'"new"'); ALTER TABLE project ADD case_template_id varchar(50) NULL COMMENT 'Relate test case template id'; @@ -192,6 +192,29 @@ VALUES ('metersphere.module.reportStat', 'ENABLE', 'text', 1); INSERT INTO system_parameter (param_key, param_value, type, sort) VALUES ('metersphere.module.testTrack', 'ENABLE', 'text', 1); + +-- issue表添加自定义字段和项目id列 +ALTER TABLE issues ADD custom_fields TEXT NULL COMMENT 'CustomField'; +ALTER TABLE issues ADD project_id varchar(50) NULL; + +-- 兼容旧数据,初始化issue表的project_id +update issues i + inner join + ( + select tc.project_id, tci.issues_id + from test_case_issues tci + inner join test_case tc + on tci.test_case_id = tc.id + ) as tmp +on i.id = tmp.issues_id + set i.project_id = tmp.project_id; + +-- 修改issue表主键 +alter table issues drop primary key; +alter table issues + add constraint issues_pk + primary key (id); + -- init prometheus host INSERT INTO system_parameter (param_key, param_value, type, sort) VALUES ('prometheus.host', 'http://ms-prometheus:9090', 'text', 1); @@ -206,3 +229,4 @@ alter table load_test_report alter table load_test_report add tps VARCHAR(10) null; + diff --git a/backend/src/main/resources/generatorConfig.xml b/backend/src/main/resources/generatorConfig.xml index 617840fc84..ca4db23830 100644 --- a/backend/src/main/resources/generatorConfig.xml +++ b/backend/src/main/resources/generatorConfig.xml @@ -80,7 +80,7 @@ -
+
diff --git a/frontend/src/business/components/common/components/table/MsTable.vue b/frontend/src/business/components/common/components/table/MsTable.vue index 10ec301f79..fd6c16e01e 100644 --- a/frontend/src/business/components/common/components/table/MsTable.vue +++ b/frontend/src/business/components/common/components/table/MsTable.vue @@ -1,5 +1,5 @@ @@ -46,12 +46,12 @@ import {CASE_TYPE_OPTION} from "@/common/js/table-constants"; import CustomFieldFormList from "@/business/components/settings/workspace/template/CustomFieldFormList"; import CustomFieldRelateList from "@/business/components/settings/workspace/template/CustomFieldRelateList"; import FieldTemplateEdit from "@/business/components/settings/workspace/template/FieldTemplateEdit"; -import TestCaseRIchTextItem from "@/business/components/track/case/components/FormRichTextItem"; +import FormRichTextItem from "@/business/components/track/case/components/FormRichTextItem"; export default { name: "TestCaseTemplateEdit", components: { - TestCaseRIchTextItem, + FormRichTextItem, FieldTemplateEdit, CustomFieldRelateList, CustomFieldFormList, diff --git a/frontend/src/business/components/track/case/components/FormRichTextItem.vue b/frontend/src/business/components/track/case/components/FormRichTextItem.vue index 04d808144e..e0ffb03202 100644 --- a/frontend/src/business/components/track/case/components/FormRichTextItem.vue +++ b/frontend/src/business/components/track/case/components/FormRichTextItem.vue @@ -1,9 +1,7 @@ + + diff --git a/frontend/src/business/components/track/case/components/TestPlanIssueEdit.vue b/frontend/src/business/components/track/case/components/TestPlanIssueEdit.vue new file mode 100644 index 0000000000..8f9a20a3aa --- /dev/null +++ b/frontend/src/business/components/track/case/components/TestPlanIssueEdit.vue @@ -0,0 +1,53 @@ + + + + diff --git a/frontend/src/business/components/track/head/TrackHeaderMenus.vue b/frontend/src/business/components/track/head/TrackHeaderMenus.vue index 3a72504195..b2dcd0603d 100644 --- a/frontend/src/business/components/track/head/TrackHeaderMenus.vue +++ b/frontend/src/business/components/track/head/TrackHeaderMenus.vue @@ -46,6 +46,10 @@ :title="$t('test_track.plan.create_plan')"/> + + {{ $t("缺陷管理") }} + + {{ $t("commons.report") }} diff --git a/frontend/src/business/components/track/issue/IssueDescriptionTableItem.vue b/frontend/src/business/components/track/issue/IssueDescriptionTableItem.vue new file mode 100644 index 0000000000..3550f52e86 --- /dev/null +++ b/frontend/src/business/components/track/issue/IssueDescriptionTableItem.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/frontend/src/business/components/track/issue/IssueEdit.vue b/frontend/src/business/components/track/issue/IssueEdit.vue new file mode 100644 index 0000000000..6be5ca9489 --- /dev/null +++ b/frontend/src/business/components/track/issue/IssueEdit.vue @@ -0,0 +1,50 @@ + + + + diff --git a/frontend/src/business/components/track/issue/IssueEditDetail.vue b/frontend/src/business/components/track/issue/IssueEditDetail.vue new file mode 100644 index 0000000000..ad048222dd --- /dev/null +++ b/frontend/src/business/components/track/issue/IssueEditDetail.vue @@ -0,0 +1,271 @@ + + + + + diff --git a/frontend/src/business/components/track/issue/IssueList.vue b/frontend/src/business/components/track/issue/IssueList.vue new file mode 100644 index 0000000000..3589ae18c9 --- /dev/null +++ b/frontend/src/business/components/track/issue/IssueList.vue @@ -0,0 +1,161 @@ + + + + + diff --git a/frontend/src/business/components/track/issue/TestCaseIssueList.vue b/frontend/src/business/components/track/issue/TestCaseIssueList.vue new file mode 100644 index 0000000000..eca545babe --- /dev/null +++ b/frontend/src/business/components/track/issue/TestCaseIssueList.vue @@ -0,0 +1,122 @@ + + + + + diff --git a/frontend/src/business/components/track/issue/TestCaseRelateList.vue b/frontend/src/business/components/track/issue/TestCaseRelateList.vue new file mode 100644 index 0000000000..07ef9d0724 --- /dev/null +++ b/frontend/src/business/components/track/issue/TestCaseRelateList.vue @@ -0,0 +1,178 @@ + + + + + diff --git a/frontend/src/business/components/track/plan/view/comonents/functional/FunctionalTestCaseEdit.vue b/frontend/src/business/components/track/plan/view/comonents/functional/FunctionalTestCaseEdit.vue index 3a9e79f1d9..9797b006e6 100644 --- a/frontend/src/business/components/track/plan/view/comonents/functional/FunctionalTestCaseEdit.vue +++ b/frontend/src/business/components/track/plan/view/comonents/functional/FunctionalTestCaseEdit.vue @@ -42,169 +42,61 @@
- - - {{ $t('test_track.case.priority') }}: - {{ testCase.priority }} - - - {{ $t('test_track.case.module') }}: - {{ testCase.nodePath }} - - - - - - - - - {{ $t('test_track.plan.plan_project') }}: - {{ testCase.projectName }} - - - - - - {{ $t('test_track.case.test_name') }}: - {{ testCase.otherTestName }} - - - - + - - - - + + {{ $t('test_track.case.priority') }}: + {{ testCase.priority }} + + + {{ $t('test_track.case.module') }}: + {{ testCase.nodePath }} + + + - - - -
- - - - -
-
-
+ + + {{ $t('test_track.plan.plan_project') }}: + {{ testCase.projectName }} + + - - - - - - - - - + + + {{ $t('test_track.case.test_name') }}: + {{ testCase.otherTestName }} + + - - - - - - {{ $t('test_track.issue.tapd_current_owner') }} - - - + + + + + + + - - {{ $t('test_track.issue.zentao_bug_build') }} - - - - {{ $t('test_track.issue.zentao_bug_assigned') }} - - - - - {{ $t('commons.save') }} - {{ $t('commons.cancel') }} - - +
- - - - - - - - - - - - - - - - + + +
+ + + + +
+
+
-
@@ -255,10 +147,12 @@ import MsFormDivider from "@/business/components/common/components/MsFormDivider import TestCaseEditOtherInfo from "@/business/components/track/case/components/TestCaseEditOtherInfo"; import CustomFiledComponent from "@/business/components/settings/workspace/template/CustomFiledComponent"; import {SYSTEM_FIELD_NAME_MAP} from "@/common/js/table-constants"; +import IssueDescriptionTableItem from "@/business/components/track/issue/IssueDescriptionTableItem"; export default { name: "FunctionalTestCaseEdit", components: { + IssueDescriptionTableItem, CustomFiledComponent, TestCaseEditOtherInfo, MsFormDivider, @@ -279,9 +173,7 @@ export default { showDialog: false, testCase: {}, index: 0, - issuesSwitch: false, testCases: [], - issues: [], editor: ClassicEditor, editorConfig: { toolbar: ['heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'insertTable', '|', 'undo', 'redo'], @@ -443,13 +335,11 @@ export default { // 如果没值,使用模板的默认值 this.testCase.actualResult = this.testCaseTemplate.actualResult; } - this.getIssues(item.caseId); this.getComments(item); }); }, openTestCaseEdit(testCase) { this.showDialog = true; - this.issuesSwitch = false; this.activeTab = 'detail'; this.hasTapdId = false; this.hasZentaoId = false; @@ -509,101 +399,12 @@ export default { } } }, - issuesChange() { - if (this.issuesSwitch) { - let desc = this.addPLabel('[' + this.$t('test_track.plan_view.operate_step') + ']'); - let result = this.addPLabel('[' + this.$t('test_track.case.expected_results') + ']'); - let actualResult = this.addPLabel('[' + this.$t('test_track.plan_view.actual_result') + ']'); - this.testCase.steps.forEach(step => { - let stepPrefix = this.$t('test_track.plan_view.step') + step.num + ':'; - desc += this.addPLabel(stepPrefix + (step.desc === undefined ? '' : step.desc)); - result += this.addPLabel(stepPrefix + (step.result === undefined ? '' : step.result)); - actualResult += this.addPLabel(stepPrefix + (step.actualResult === undefined ? '' : step.actualResult)); - }); - this.testCase.issues.content = desc + this.addPLabel('') + result + this.addPLabel('') + actualResult + this.addPLabel(''); - - this.$get("/test/case/project/" + this.testCase.caseId, res => { - const project = res.data; - if (project.tapdId) { - this.hasTapdId = true; - this.result = this.$get("/issues/tapd/user/" + this.testCase.caseId).then(response => { - this.users = response.data.data; - }).catch(() => { - console.log("get tapd user error."); - }) - } - if (project.zentaoId) { - this.hasZentaoId = true; - this.result = this.$get("/issues/zentao/builds/" + this.testCase.caseId).then(response => { - this.Builds = response.data.data; - }).catch(() => { - console.log("get zentao builds error."); - }) - this.result = this.$get("/issues/zentao/user/" + this.testCase.caseId).then(response => { - this.zentaoUsers = response.data.data; - }).catch(() => { - console.log("get zentao user error."); - }) - } - }) - } - }, addPLabel(str) { return "

" + str + "

"; }, setPlanStatus(planId) { this.$post('/test/plan/edit/status/' + planId); - }, - saveIssues() { - if (!this.testCase.issues.title || !this.testCase.issues.content) { - this.$warning(this.$t('test_track.issue.title_description_required')); - return; - } - - let param = {}; - param.title = this.testCase.issues.title; - param.content = this.testCase.issues.content; - param.testCaseId = this.testCase.caseId; - param.tapdUsers = this.testCase.tapdUsers; - param.zentaoBuilds = this.testCase.zentaoBuilds; - param.zentaoUser = this.testCase.zentaoAssigned; - - this.result = this.$post("/issues/add", param, () => { - this.$success(this.$t('commons.save_success')); - this.getIssues(param.testCaseId); - }); - - this.issuesSwitch = false; - this.testCase.issues.title = ""; - this.testCase.issues.content = ""; - this.testCase.tapdUsers = []; - this.testCase.zentaoBuilds = []; - this.testCase.zentaoAssigned = ""; - }, - getIssues(caseId) { - this.result = this.$get("/issues/get/" + caseId).then(response => { - this.issues = response.data.data; - }).catch(() => { - console.log("get issues error") - }) - }, - closeIssue(row) { - if (row.status === 'closed') { - this.$success(this.$t('test_track.issue.close_success')); - } else { - this.result = this.$get("/issues/close/" + row.id, () => { - this.getIssues(this.testCase.caseId); - this.$success(this.$t('test_track.issue.close_success')); - }); - } - }, - deleteIssue(row) { - let caseId = this.testCase.caseId; - this.result = this.$post("/issues/delete", {id: row.id, caseId: caseId}, () => { - this.getIssues(caseId); - this.$success(this.$t('commons.delete_success')); - }) - }, + } } } diff --git a/frontend/src/business/components/track/plan/view/comonents/report/TemplateComponentEditHeader.vue b/frontend/src/business/components/track/plan/view/comonents/report/TemplateComponentEditHeader.vue index be0f1ba30f..5a194c9fff 100644 --- a/frontend/src/business/components/track/plan/view/comonents/report/TemplateComponentEditHeader.vue +++ b/frontend/src/business/components/track/plan/view/comonents/report/TemplateComponentEditHeader.vue @@ -2,10 +2,10 @@ -
- - {{template.name}} - {{$t('test_track.plan_view.input_template_name')}} +
+ + {{template[prop]}} + {{$t('test_track.plan_view.input_template_name')}}
@@ -32,6 +32,18 @@ return {} } }, + prop: { + type: String, + default() { + return 'name'; + } + }, + showEdit: { + type: Boolean, + default() { + return true; + } + }, }, methods: { handleCancel() { @@ -39,9 +51,6 @@ }, handleSave() { this.$emit('save'); - }, - change() { - this.$emit('update:template', this.templateName); } } } diff --git a/frontend/src/business/components/track/router.js b/frontend/src/business/components/track/router.js index db1f16232d..56559ba19c 100644 --- a/frontend/src/business/components/track/router.js +++ b/frontend/src/business/components/track/router.js @@ -7,6 +7,7 @@ const TestCaseReview = () => import('@/business/components/track/review/TestCase const TestCaseReviewView = () => import('@/business/components/track/review/view/TestCaseReviewView') const TestPlanView = () => import('@/business/components/track/plan/view/TestPlanView') const reportListView = () => import('@/business/components/track/report/TestPlanReport') +const issueList = () => import('@/business/components/track/issue/IssueList.vue') // const reportListView = () => import('@/business/components/track/plan/TestPlan') export default { @@ -42,6 +43,11 @@ export default { name: 'testPlanReportList', component: reportListView, }, + { + path: 'issue', + name: 'issueManagement', + component: issueList, + }, { path: "plan/:type", name: "testPlan", diff --git a/frontend/src/common/js/custom_field.js b/frontend/src/common/js/custom_field.js index e924b757ec..0bfad03b66 100644 --- a/frontend/src/common/js/custom_field.js +++ b/frontend/src/common/js/custom_field.js @@ -58,6 +58,7 @@ export function parseCustomField(data, template, customFieldForm, rules, oldFiel }); } +// 将template的属性值设置给customFields export function buildCustomFields(data, param, template) { if (template.customFields) { let customFields = data.customFields; diff --git a/frontend/src/common/js/table-constants.js b/frontend/src/common/js/table-constants.js index 082aea7883..d1e6d907cc 100644 --- a/frontend/src/common/js/table-constants.js +++ b/frontend/src/common/js/table-constants.js @@ -58,3 +58,10 @@ export const SYSTEM_FIELD_NAME_MAP = { i43sf4_issueStatus: 'custom_field.issue_status', i43sf4_issueSeverity: 'custom_field.issue_severity', } + + +export const ISSUE_STATUS_MAP = { + 'new': '新建', + 'closed': '已关闭', + 'resolved': '已解决' +} diff --git a/frontend/src/common/js/tableUtils.js b/frontend/src/common/js/tableUtils.js index ea9855b2fa..c3db0d07c5 100644 --- a/frontend/src/common/js/tableUtils.js +++ b/frontend/src/common/js/tableUtils.js @@ -45,12 +45,14 @@ export function setUnSelectIds(tableData, condition, selectRows) { let thisUnSelectIds = allIDs.filter(function (val) { return ids.indexOf(val) === -1; }); - let needPushIds = thisUnSelectIds.filter(function (val) { - return condition.unSelectIds.indexOf(val) === -1; - }); - needPushIds.forEach(id => { - condition.unSelectIds.push(id); - }); + if (condition.unSelectIds) { + let needPushIds = thisUnSelectIds.filter(function (val) { + return condition.unSelectIds.indexOf(val) === -1; + }); + needPushIds.forEach(id => { + condition.unSelectIds.push(id); + }); + } } export function getSelectDataCounts(condition, total, selectRows) {