Merge remote-tracking branch 'origin/master'

This commit is contained in:
Captain.B 2021-03-05 16:43:43 +08:00
commit d6b73f1305
26 changed files with 1549 additions and 592 deletions

View File

@ -44,6 +44,15 @@ public class ApiAutomationController {
return PageUtils.setPageInfo(page, apiAutomationService.list(request));
}
@GetMapping("/list/{projectId}")
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER, RoleConstants.TEST_VIEWER}, logical = Logical.OR)
public List<ApiScenarioDTO> list(@PathVariable String projectId) {
ApiScenarioRequest request = new ApiScenarioRequest();
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
request.setProjectId(projectId);
return apiAutomationService.list(request);
}
@PostMapping(value = "/create")
public ApiScenario create(@RequestPart("request") SaveApiScenarioRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
return apiAutomationService.create(request, bodyFiles);

View File

@ -44,7 +44,7 @@ public class ApiTestCaseController {
if(!list.isEmpty()){
return list.get(0);
}else {
return null;
return null;
}
}
@ -55,6 +55,14 @@ public class ApiTestCaseController {
return PageUtils.setPageInfo(page, apiTestCaseService.listSimple(request));
}
@GetMapping("/list/{projectId}")
public List<ApiTestCaseDTO> list(@PathVariable String projectId) {
ApiTestCaseRequest request = new ApiTestCaseRequest();
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
request.setProjectId(projectId);
return apiTestCaseService.listSimple(request);
}
@PostMapping("/get/request")
public Map<String, String> listSimple(@RequestBody ApiTestCaseRequest request) {
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());

View File

@ -42,5 +42,9 @@ public class TestCase implements Serializable {
private String tags;
private String demandId;
private String demandName;
private static final long serialVersionUID = 1L;
}

View File

@ -1323,6 +1323,146 @@ public class TestCaseExample {
addCriterion("tags not between", value1, value2, "tags");
return (Criteria) this;
}
public Criteria andDemandIdIsNull() {
addCriterion("demand_id is null");
return (Criteria) this;
}
public Criteria andDemandIdIsNotNull() {
addCriterion("demand_id is not null");
return (Criteria) this;
}
public Criteria andDemandIdEqualTo(String value) {
addCriterion("demand_id =", value, "demandId");
return (Criteria) this;
}
public Criteria andDemandIdNotEqualTo(String value) {
addCriterion("demand_id <>", value, "demandId");
return (Criteria) this;
}
public Criteria andDemandIdGreaterThan(String value) {
addCriterion("demand_id >", value, "demandId");
return (Criteria) this;
}
public Criteria andDemandIdGreaterThanOrEqualTo(String value) {
addCriterion("demand_id >=", value, "demandId");
return (Criteria) this;
}
public Criteria andDemandIdLessThan(String value) {
addCriterion("demand_id <", value, "demandId");
return (Criteria) this;
}
public Criteria andDemandIdLessThanOrEqualTo(String value) {
addCriterion("demand_id <=", value, "demandId");
return (Criteria) this;
}
public Criteria andDemandIdLike(String value) {
addCriterion("demand_id like", value, "demandId");
return (Criteria) this;
}
public Criteria andDemandIdNotLike(String value) {
addCriterion("demand_id not like", value, "demandId");
return (Criteria) this;
}
public Criteria andDemandIdIn(List<String> values) {
addCriterion("demand_id in", values, "demandId");
return (Criteria) this;
}
public Criteria andDemandIdNotIn(List<String> values) {
addCriterion("demand_id not in", values, "demandId");
return (Criteria) this;
}
public Criteria andDemandIdBetween(String value1, String value2) {
addCriterion("demand_id between", value1, value2, "demandId");
return (Criteria) this;
}
public Criteria andDemandIdNotBetween(String value1, String value2) {
addCriterion("demand_id not between", value1, value2, "demandId");
return (Criteria) this;
}
public Criteria andDemandNameIsNull() {
addCriterion("demand_name is null");
return (Criteria) this;
}
public Criteria andDemandNameIsNotNull() {
addCriterion("demand_name is not null");
return (Criteria) this;
}
public Criteria andDemandNameEqualTo(String value) {
addCriterion("demand_name =", value, "demandName");
return (Criteria) this;
}
public Criteria andDemandNameNotEqualTo(String value) {
addCriterion("demand_name <>", value, "demandName");
return (Criteria) this;
}
public Criteria andDemandNameGreaterThan(String value) {
addCriterion("demand_name >", value, "demandName");
return (Criteria) this;
}
public Criteria andDemandNameGreaterThanOrEqualTo(String value) {
addCriterion("demand_name >=", value, "demandName");
return (Criteria) this;
}
public Criteria andDemandNameLessThan(String value) {
addCriterion("demand_name <", value, "demandName");
return (Criteria) this;
}
public Criteria andDemandNameLessThanOrEqualTo(String value) {
addCriterion("demand_name <=", value, "demandName");
return (Criteria) this;
}
public Criteria andDemandNameLike(String value) {
addCriterion("demand_name like", value, "demandName");
return (Criteria) this;
}
public Criteria andDemandNameNotLike(String value) {
addCriterion("demand_name not like", value, "demandName");
return (Criteria) this;
}
public Criteria andDemandNameIn(List<String> values) {
addCriterion("demand_name in", values, "demandName");
return (Criteria) this;
}
public Criteria andDemandNameNotIn(List<String> values) {
addCriterion("demand_name not in", values, "demandName");
return (Criteria) this;
}
public Criteria andDemandNameBetween(String value1, String value2) {
addCriterion("demand_name between", value1, value2, "demandName");
return (Criteria) this;
}
public Criteria andDemandNameNotBetween(String value1, String value2) {
addCriterion("demand_name not between", value1, value2, "demandName");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -10,16 +10,18 @@
<result column="type" jdbcType="VARCHAR" property="type" />
<result column="maintainer" jdbcType="VARCHAR" property="maintainer" />
<result column="priority" jdbcType="VARCHAR" property="priority" />
<result column="method" jdbcType="VARCHAR" property="method" />
<result column="prerequisite" jdbcType="VARCHAR" property="prerequisite" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="test_id" jdbcType="VARCHAR" property="testId" />
<result column="sort" jdbcType="INTEGER" property="sort" />
<result column="num" jdbcType="INTEGER" property="num" />
<result column="other_test_name" jdbcType="VARCHAR" property="otherTestName" />
<result column="review_status" jdbcType="VARCHAR" property="reviewStatus" />
<result column="tags" jdbcType="VARCHAR" property="tags" />
<result column="method" jdbcType="VARCHAR" property="method"/>
<result column="prerequisite" jdbcType="VARCHAR" property="prerequisite"/>
<result column="create_time" jdbcType="BIGINT" property="createTime"/>
<result column="update_time" jdbcType="BIGINT" property="updateTime"/>
<result column="test_id" jdbcType="VARCHAR" property="testId"/>
<result column="sort" jdbcType="INTEGER" property="sort"/>
<result column="num" jdbcType="INTEGER" property="num"/>
<result column="other_test_name" jdbcType="VARCHAR" property="otherTestName"/>
<result column="review_status" jdbcType="VARCHAR" property="reviewStatus"/>
<result column="tags" jdbcType="VARCHAR" property="tags"/>
<result column="demand_id" jdbcType="VARCHAR" property="demandId"/>
<result column="demand_name" jdbcType="VARCHAR" property="demandName"/>
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.TestCaseWithBLOBs">
<result column="remark" jdbcType="LONGVARCHAR" property="remark" />
@ -86,7 +88,7 @@
<sql id="Base_Column_List">
id, node_id, node_path, project_id, `name`, `type`, maintainer, priority, `method`,
prerequisite, create_time, update_time, test_id, sort, num, other_test_name, review_status,
tags
tags, demand_id, demand_name
</sql>
<sql id="Blob_Column_List">
remark, steps
@ -140,20 +142,22 @@
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.TestCaseWithBLOBs">
insert into test_case (id, node_id, node_path,
project_id, `name`, `type`,
maintainer, priority, `method`,
prerequisite, create_time, update_time,
test_id, sort, num,
other_test_name, review_status, tags,
remark, steps)
values (#{id,jdbcType=VARCHAR}, #{nodeId,jdbcType=VARCHAR}, #{nodePath,jdbcType=VARCHAR},
#{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR},
#{maintainer,jdbcType=VARCHAR}, #{priority,jdbcType=VARCHAR}, #{method,jdbcType=VARCHAR},
#{prerequisite,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{testId,jdbcType=VARCHAR}, #{sort,jdbcType=INTEGER}, #{num,jdbcType=INTEGER},
#{otherTestName,jdbcType=VARCHAR}, #{reviewStatus,jdbcType=VARCHAR}, #{tags,jdbcType=VARCHAR},
#{remark,jdbcType=LONGVARCHAR}, #{steps,jdbcType=LONGVARCHAR})
insert into test_case (id, node_id, node_path,
project_id, `name`, `type`,
maintainer, priority, `method`,
prerequisite, create_time, update_time,
test_id, sort, num,
other_test_name, review_status, tags,
demand_id, demand_name, remark,
steps)
values (#{id,jdbcType=VARCHAR}, #{nodeId,jdbcType=VARCHAR}, #{nodePath,jdbcType=VARCHAR},
#{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR},
#{maintainer,jdbcType=VARCHAR}, #{priority,jdbcType=VARCHAR}, #{method,jdbcType=VARCHAR},
#{prerequisite,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{testId,jdbcType=VARCHAR}, #{sort,jdbcType=INTEGER}, #{num,jdbcType=INTEGER},
#{otherTestName,jdbcType=VARCHAR}, #{reviewStatus,jdbcType=VARCHAR}, #{tags,jdbcType=VARCHAR},
#{demandId,jdbcType=VARCHAR}, #{demandName,jdbcType=VARCHAR}, #{remark,jdbcType=LONGVARCHAR},
#{steps,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestCaseWithBLOBs">
insert into test_case
@ -212,6 +216,12 @@
<if test="tags != null">
tags,
</if>
<if test="demandId != null">
demand_id,
</if>
<if test="demandName != null">
demand_name,
</if>
<if test="remark != null">
remark,
</if>
@ -274,6 +284,12 @@
<if test="tags != null">
#{tags,jdbcType=VARCHAR},
</if>
<if test="demandId != null">
#{demandId,jdbcType=VARCHAR},
</if>
<if test="demandName != null">
#{demandName,jdbcType=VARCHAR},
</if>
<if test="remark != null">
#{remark,jdbcType=LONGVARCHAR},
</if>
@ -345,6 +361,12 @@
<if test="record.tags != null">
tags = #{record.tags,jdbcType=VARCHAR},
</if>
<if test="record.demandId != null">
demand_id = #{record.demandId,jdbcType=VARCHAR},
</if>
<if test="record.demandName != null">
demand_name = #{record.demandName,jdbcType=VARCHAR},
</if>
<if test="record.remark != null">
remark = #{record.remark,jdbcType=LONGVARCHAR},
</if>
@ -366,18 +388,20 @@
`type` = #{record.type,jdbcType=VARCHAR},
maintainer = #{record.maintainer,jdbcType=VARCHAR},
priority = #{record.priority,jdbcType=VARCHAR},
`method` = #{record.method,jdbcType=VARCHAR},
prerequisite = #{record.prerequisite,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
test_id = #{record.testId,jdbcType=VARCHAR},
sort = #{record.sort,jdbcType=INTEGER},
num = #{record.num,jdbcType=INTEGER},
other_test_name = #{record.otherTestName,jdbcType=VARCHAR},
review_status = #{record.reviewStatus,jdbcType=VARCHAR},
tags = #{record.tags,jdbcType=VARCHAR},
remark = #{record.remark,jdbcType=LONGVARCHAR},
steps = #{record.steps,jdbcType=LONGVARCHAR}
`method` = #{record.method,jdbcType=VARCHAR},
prerequisite = #{record.prerequisite,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
test_id = #{record.testId,jdbcType=VARCHAR},
sort = #{record.sort,jdbcType=INTEGER},
num = #{record.num,jdbcType=INTEGER},
other_test_name = #{record.otherTestName,jdbcType=VARCHAR},
review_status = #{record.reviewStatus,jdbcType=VARCHAR},
tags = #{record.tags,jdbcType=VARCHAR},
demand_id = #{record.demandId,jdbcType=VARCHAR},
demand_name = #{record.demandName,jdbcType=VARCHAR},
remark = #{record.remark,jdbcType=LONGVARCHAR},
steps = #{record.steps,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -391,17 +415,19 @@
`name` = #{record.name,jdbcType=VARCHAR},
`type` = #{record.type,jdbcType=VARCHAR},
maintainer = #{record.maintainer,jdbcType=VARCHAR},
priority = #{record.priority,jdbcType=VARCHAR},
`method` = #{record.method,jdbcType=VARCHAR},
prerequisite = #{record.prerequisite,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
test_id = #{record.testId,jdbcType=VARCHAR},
sort = #{record.sort,jdbcType=INTEGER},
num = #{record.num,jdbcType=INTEGER},
other_test_name = #{record.otherTestName,jdbcType=VARCHAR},
review_status = #{record.reviewStatus,jdbcType=VARCHAR},
tags = #{record.tags,jdbcType=VARCHAR}
priority = #{record.priority,jdbcType=VARCHAR},
`method` = #{record.method,jdbcType=VARCHAR},
prerequisite = #{record.prerequisite,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
test_id = #{record.testId,jdbcType=VARCHAR},
sort = #{record.sort,jdbcType=INTEGER},
num = #{record.num,jdbcType=INTEGER},
other_test_name = #{record.otherTestName,jdbcType=VARCHAR},
review_status = #{record.reviewStatus,jdbcType=VARCHAR},
tags = #{record.tags,jdbcType=VARCHAR},
demand_id = #{record.demandId,jdbcType=VARCHAR},
demand_name = #{record.demandName,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -460,6 +486,12 @@
<if test="tags != null">
tags = #{tags,jdbcType=VARCHAR},
</if>
<if test="demandId != null">
demand_id = #{demandId,jdbcType=VARCHAR},
</if>
<if test="demandName != null">
demand_name = #{demandName,jdbcType=VARCHAR},
</if>
<if test="remark != null">
remark = #{remark,jdbcType=LONGVARCHAR},
</if>
@ -471,46 +503,50 @@
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.TestCaseWithBLOBs">
update test_case
set node_id = #{nodeId,jdbcType=VARCHAR},
node_path = #{nodePath,jdbcType=VARCHAR},
project_id = #{projectId,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR},
`type` = #{type,jdbcType=VARCHAR},
maintainer = #{maintainer,jdbcType=VARCHAR},
priority = #{priority,jdbcType=VARCHAR},
`method` = #{method,jdbcType=VARCHAR},
prerequisite = #{prerequisite,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
test_id = #{testId,jdbcType=VARCHAR},
sort = #{sort,jdbcType=INTEGER},
num = #{num,jdbcType=INTEGER},
other_test_name = #{otherTestName,jdbcType=VARCHAR},
review_status = #{reviewStatus,jdbcType=VARCHAR},
tags = #{tags,jdbcType=VARCHAR},
remark = #{remark,jdbcType=LONGVARCHAR},
steps = #{steps,jdbcType=LONGVARCHAR}
set node_id = #{nodeId,jdbcType=VARCHAR},
node_path = #{nodePath,jdbcType=VARCHAR},
project_id = #{projectId,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR},
`type` = #{type,jdbcType=VARCHAR},
maintainer = #{maintainer,jdbcType=VARCHAR},
priority = #{priority,jdbcType=VARCHAR},
`method` = #{method,jdbcType=VARCHAR},
prerequisite = #{prerequisite,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
test_id = #{testId,jdbcType=VARCHAR},
sort = #{sort,jdbcType=INTEGER},
num = #{num,jdbcType=INTEGER},
other_test_name = #{otherTestName,jdbcType=VARCHAR},
review_status = #{reviewStatus,jdbcType=VARCHAR},
tags = #{tags,jdbcType=VARCHAR},
demand_id = #{demandId,jdbcType=VARCHAR},
demand_name = #{demandName,jdbcType=VARCHAR},
remark = #{remark,jdbcType=LONGVARCHAR},
steps = #{steps,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.TestCase">
update test_case
set node_id = #{nodeId,jdbcType=VARCHAR},
node_path = #{nodePath,jdbcType=VARCHAR},
project_id = #{projectId,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR},
`type` = #{type,jdbcType=VARCHAR},
maintainer = #{maintainer,jdbcType=VARCHAR},
priority = #{priority,jdbcType=VARCHAR},
`method` = #{method,jdbcType=VARCHAR},
prerequisite = #{prerequisite,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
test_id = #{testId,jdbcType=VARCHAR},
sort = #{sort,jdbcType=INTEGER},
num = #{num,jdbcType=INTEGER},
other_test_name = #{otherTestName,jdbcType=VARCHAR},
review_status = #{reviewStatus,jdbcType=VARCHAR},
tags = #{tags,jdbcType=VARCHAR}
set node_id = #{nodeId,jdbcType=VARCHAR},
node_path = #{nodePath,jdbcType=VARCHAR},
project_id = #{projectId,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR},
`type` = #{type,jdbcType=VARCHAR},
maintainer = #{maintainer,jdbcType=VARCHAR},
priority = #{priority,jdbcType=VARCHAR},
`method` = #{method,jdbcType=VARCHAR},
prerequisite = #{prerequisite,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
test_id = #{testId,jdbcType=VARCHAR},
sort = #{sort,jdbcType=INTEGER},
num = #{num,jdbcType=INTEGER},
other_test_name = #{otherTestName,jdbcType=VARCHAR},
review_status = #{reviewStatus,jdbcType=VARCHAR},
tags = #{tags,jdbcType=VARCHAR},
demand_id = #{demandId,jdbcType=VARCHAR},
demand_name = #{demandName,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -0,0 +1,23 @@
package io.metersphere.track.controller;
import io.metersphere.track.dto.DemandDTO;
import io.metersphere.track.service.DemandService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
@RequestMapping("demand")
@RestController
public class TestCaseDemandController {
@Resource
private DemandService DemandService;
@GetMapping("/list/{projectId}")
public List<DemandDTO> getDemandList(@PathVariable String projectId) {
return DemandService.getDemandList(projectId);
}
}

View File

@ -45,8 +45,8 @@ public class TestCaseReviewController {
@PostMapping("/save")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public void saveCaseReview(@RequestBody SaveTestCaseReviewRequest reviewRequest) {
testCaseReviewService.saveTestCaseReview(reviewRequest);
public String saveCaseReview(@RequestBody SaveTestCaseReviewRequest reviewRequest) {
return testCaseReviewService.saveTestCaseReview(reviewRequest);
}
@PostMapping("/project")

View File

@ -0,0 +1,11 @@
package io.metersphere.track.dto;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class DemandDTO {
private String id;
private String name;
}

View File

@ -41,7 +41,9 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
protected String getPlatformConfig(String platform) {
SessionUser user = SessionUtils.getUser();
String orgId = user.getLastOrganizationId();
/*
String orgId = "88aceecf-5764-4094-96a9-f82bd52e77ad";
*/
IntegrationRequest request = new IntegrationRequest();
if (StringUtils.isBlank(orgId)) {
MSException.throwException("organization id is null");

View File

@ -1,6 +1,7 @@
package io.metersphere.track.issue;
import io.metersphere.base.domain.Issues;
import io.metersphere.track.dto.DemandDTO;
import io.metersphere.track.issue.domain.PlatformUser;
import io.metersphere.track.request.testcase.IssuesRequest;
@ -10,18 +11,24 @@ public interface IssuesPlatform {
/**
* 获取平台相关联的缺陷
*
* @return platform issues list
*/
List<Issues> getIssue();
/*获取平台相关需求*/
List<DemandDTO> getDemandList(String projectId);
/**
* 添加缺陷到缺陷平台
*
* @param issuesRequest issueRequest
*/
void addIssue(IssuesRequest issuesRequest);
/**
* 删除缺陷平台缺陷
*
* @param id issue id
*/
void deleteIssue(String id);

View File

@ -7,6 +7,7 @@ import io.metersphere.commons.constants.IssuesManagePlatform;
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 org.apache.commons.lang3.StringUtils;
@ -78,6 +79,11 @@ public class JiraPlatform extends AbstractIssuePlatform {
return list;
}
@Override
public List<DemandDTO> getDemandList(String projectId) {
return null;
}
@Override
public void addIssue(IssuesRequest issuesRequest) {
String config = getPlatformConfig(IssuesManagePlatform.Jira.toString());

View File

@ -5,6 +5,7 @@ import io.metersphere.base.domain.TestCaseIssues;
import io.metersphere.commons.constants.IssuesManagePlatform;
import io.metersphere.commons.user.SessionUser;
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;
@ -22,6 +23,11 @@ public class LocalPlatform extends AbstractIssuePlatform {
return extIssuesMapper.getIssues(testCaseId, IssuesManagePlatform.Local.toString());
}
@Override
public List<DemandDTO> getDemandList(String projectId) {
return null;
}
@Override
public void addIssue(IssuesRequest issuesRequest) {
SessionUser user = SessionUtils.getUser();

View File

@ -9,6 +9,7 @@ import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils;
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 org.apache.commons.lang3.StringUtils;
@ -64,6 +65,23 @@ public class TapdPlatform extends AbstractIssuePlatform {
return list;
}
@Override
public List<DemandDTO> getDemandList(String projectId) {
System.out.println(projectId);
List<DemandDTO> demandList = new ArrayList<>();
String url = "https://api.tapd.cn/stories?workspace_id=" + projectId;
ResultHolder call = call(url);
String listJson = JSON.toJSONString(call.getData());
JSONArray jsonArray = JSON.parseArray(listJson);
System.out.println(jsonArray);
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject o = jsonArray.getJSONObject(i);
DemandDTO demand = o.getObject("Story", DemandDTO.class);
demandList.add(demand);
}
return demandList;
}
private Issues getTapdIssues(String projectId, String issuesId) {
String url = "https://api.tapd.cn/bugs?workspace_id=" + projectId + "&id=" + issuesId;
ResultHolder call = call(url);
@ -208,4 +226,5 @@ public class TapdPlatform extends AbstractIssuePlatform {
}
}

View File

@ -7,6 +7,7 @@ import io.metersphere.base.domain.*;
import io.metersphere.commons.constants.IssuesManagePlatform;
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;
@ -85,6 +86,11 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
}
@Override
public List<DemandDTO> getDemandList(String projectId) {
return null;
}
private Issues getZentaoIssues(String bugId) {
String session = login();
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<>(new HttpHeaders());

View File

@ -0,0 +1,76 @@
package io.metersphere.track.service;
import io.metersphere.base.domain.Issues;
import io.metersphere.base.domain.Project;
import io.metersphere.base.mapper.ProjectMapper;
import io.metersphere.commons.constants.IssuesManagePlatform;
import io.metersphere.commons.user.SessionUser;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.service.ProjectService;
import io.metersphere.track.dto.DemandDTO;
import io.metersphere.track.issue.AbstractIssuePlatform;
import io.metersphere.track.issue.IssueFactory;
import io.metersphere.track.request.testcase.IssuesRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Service
@Transactional(rollbackFor = Exception.class)
public class DemandService {
@Resource
private ProjectService projectService;
@Resource
private IssuesService issuesService;
@Resource
private ProjectMapper projectMapper;
public List<DemandDTO> getDemandList(String projectId) {
Project project = projectMapper.selectByPrimaryKey(projectId);
SessionUser user = SessionUtils.getUser();
/*
String orgId = "88aceecf-5764-4094-96a9-f82bd52e77ad";
*/
String orgId = user.getLastOrganizationId();
boolean tapd = issuesService.isIntegratedPlatform(orgId, IssuesManagePlatform.Tapd.toString());
boolean jira = issuesService.isIntegratedPlatform(orgId, IssuesManagePlatform.Jira.toString());
boolean zentao = issuesService.isIntegratedPlatform(orgId, IssuesManagePlatform.Zentao.toString());
List<DemandDTO> list = new ArrayList<>();
List<String> platforms = new ArrayList<>();
IssuesRequest issueRequest = new IssuesRequest();
if (tapd) {
// 是否关联了项目
String tapdId = project.getTapdId();
if (StringUtils.isNotBlank(tapdId)) {
platforms.add(IssuesManagePlatform.Tapd.name());
}
issueRequest.setProjectId(tapdId);
}
if (jira) {
String jiraKey = project.getJiraKey();
if (StringUtils.isNotBlank(jiraKey)) {
platforms.add(IssuesManagePlatform.Jira.name());
}
issueRequest.setProjectId(jiraKey);
}
if (zentao) {
String zentaoId = project.getZentaoId();
if (StringUtils.isNotBlank(zentaoId)) {
platforms.add(IssuesManagePlatform.Zentao.name());
}
issueRequest.setProjectId(zentaoId);
}
List<AbstractIssuePlatform> platformList = IssueFactory.createPlatforms(platforms, issueRequest);
platformList.forEach(platform -> {
List<DemandDTO> demand = platform.getDemandList(issueRequest.getProjectId());
list.addAll(demand);
});
return list;
}
}

View File

@ -78,7 +78,7 @@ public class TestCaseReviewService {
@Resource
private SystemParameterService systemParameterService;
public void saveTestCaseReview(SaveTestCaseReviewRequest reviewRequest) {
public String saveTestCaseReview(SaveTestCaseReviewRequest reviewRequest) {
checkCaseReviewExist(reviewRequest);
String reviewId = UUID.randomUUID().toString();
List<String> userIds = reviewRequest.getUserIds();//执行人
@ -109,6 +109,7 @@ public class TestCaseReviewService {
.event(NoticeConstants.Event.CREATE)
.build();
noticeSendService.send(NoticeConstants.TaskType.REVIEW_TASK, noticeModel);
return reviewRequest.getId();
}
//评审内容

View File

@ -100,6 +100,8 @@ public class TestCaseService {
testCase.setUpdateTime(System.currentTimeMillis());
testCase.setNum(getNextNum(testCase.getProjectId()));
testCase.setReviewStatus(TestCaseReviewStatus.Prepare.name());
testCase.setDemandId(testCase.getDemandId());
testCase.setDemandName(testCase.getDemandName());
testCaseMapper.insert(testCase);
return testCase;
}

View File

@ -16,17 +16,34 @@ ALTER TABLE test_resource_pool ADD gc_algo VARCHAR(200) NULL;
-- create tale api_document_share
CREATE TABLE IF NOT EXISTS `api_document_share` (
`id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Api Document Share Info ID',
`create_time` BIGINT ( 13 ) NOT NULL COMMENT 'Create timestamp',
`create_user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`update_time` BIGINT ( 13 ) NOT NULL COMMENT 'last visit timestamp',
`share_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'single or batch',
`share_api_id` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'APiDefinition.id (JSONArray format. Order by TreeSet)',
PRIMARY KEY (`id`) USING BTREE,
INDEX `share_type`(`share_type`) USING BTREE,
INDEX `share_api_id`(`share_api_id`(125)) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
`id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Api Document Share Info ID',
`create_time` BIGINT ( 13 ) NOT NULL COMMENT 'Create timestamp',
`create_user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`update_time` BIGINT(13) NOT NULL COMMENT 'last visit timestamp',
`share_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'single or batch',
`share_api_id` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'APiDefinition.id (JSONArray format. Order by TreeSet)',
PRIMARY KEY (`id`) USING BTREE,
INDEX `share_type` (`share_type`) USING BTREE,
INDEX `share_api_id` (`share_api_id`(125)) USING BTREE
) ENGINE = InnoDB
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci
ROW_FORMAT = Dynamic;
-- test_case_review add coloumn
ALTER TABLE test_case_review
ADD tags VARCHAR(2000) NULL;
-- swagger_url_project
alter table swagger_url_project
modify module_id varchar(120) null;
-- add_test_case
alter table test_case
add demand_id varchar(50) null;
alter table test_case
add demand_name varchar(999) null;
-- test_case_review add column
ALTER TABLE test_case_review ADD tags VARCHAR(2000) NULL;

View File

@ -64,13 +64,14 @@
<!--要生成的数据库表 -->
<table tableName="auth_source"/>
<!--<table tableName="auth_source"/>
<table tableName="swagger_url_project"/>
<table tableName="user_header"/>
<table tableName="user_header"/>-->
<!--<table tableName="test_plan_api_scenario"/>-->
<!--<table tableName="test_plan"/>-->
<!--<table tableName="api_scenario_report"/>-->
<table tableName="test_case_review"/>
<!--<table tableName="test_case_review"/>-->
<table tableName="test_case"/>
</context>
</generatorConfiguration>

View File

@ -61,6 +61,11 @@ export const CASE_PRIORITY = [
{id: 'P3', label: 'P3'}
]
export const REVIEW_STATUS = [
{id: 'Prepare', label: '未评审'},
{id: 'Pass', label: '通过'},
{id: 'UnPass', label: '未通过'}
]
export const API_STATUS = [
{id: 'Prepare', label: '未开始'},
{id: 'Underway', label: '进行中'},

View File

@ -1,40 +1,72 @@
<template>
<ms-container>
<ms-container v-if="renderComponent" v-loading="loading">
<ms-aside-container>
<test-case-node-tree
@nodeSelectEvent="nodeChange"
@refreshTable="refresh"
@setTreeNodes="setTreeNodes"
@exportTestCase="exportTestCase"
:type="'edit'"
ref="nodeTree"/>
</ms-aside-container>
<ms-main-container>
<test-case-list
:module-options="moduleOptions"
:select-node-ids="selectNodeIds"
:select-parent-nodes="selectParentNodes"
:tree-nodes="treeNodes"
@testCaseEdit="editTestCase"
@testCaseCopy="copyTestCase"
@testCaseDetail="showTestCaseDetail"
@refresh="refresh"
@refreshAll="refreshAll"
@setCondition="setCondition"
ref="testCaseList">
</test-case-list>
</ms-main-container>
<el-tabs v-model="activeName" @tab-click="addTab" @tab-remove="removeTab">
<el-tab-pane name="default" :label="$t('api_test.definition.case_title')">
<test-case-list
:checkRedirectID="checkRedirectID"
:module-options="moduleOptions"
:select-node-ids="selectNodeIds"
:isRedirectEdit="isRedirectEdit"
:select-parent-nodes="selectParentNodes"
:tree-nodes="treeNodes"
@testCaseEdit="editTestCase"
@testCaseCopy="copyTestCase"
@testCaseDetail="showTestCaseDetail"
@refresh="refresh"
@refreshAll="refreshAll"
@setCondition="setCondition"
ref="testCaseList">
</test-case-list>
</el-tab-pane>
<el-tab-pane
:key="item.name"
v-for="(item) in tabs"
:label="item.label"
:name="item.name"
closable>
<div class="ms-api-scenario-div">
<test-case-edit
:currentTestCaseInfo="item.testCaseInfo"
@refresh="refreshTable"
@setModuleOptions="setModuleOptions"
:read-only="testCaseReadOnly"
:tree-nodes="treeNodes"
:select-node="selectNode"
:select-condition="condition"
:type="type"
@addTab="addTab"
ref="testCaseEdit">
</test-case-edit>
</div>
</el-tab-pane>
<el-tab-pane name="add">
<template v-slot:label>
<el-dropdown @command="handleCommand" v-tester>
<el-button type="primary" plain icon="el-icon-plus" size="mini" v-tester/>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="ADD">{{ $t('test_track.case.create') }}</el-dropdown-item>
<el-dropdown-item command="CLOSE_ALL">{{ $t('api_test.definition.request.close_all_label') }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-tab-pane>
<test-case-edit
@refresh="refreshTable"
@setModuleOptions="setModuleOptions"
:read-only="testCaseReadOnly"
:tree-nodes="treeNodes"
:select-node="selectNode"
:select-condition="condition"
ref="testCaseEditDialog">
</test-case-edit>
</el-tabs>
</ms-main-container>
</ms-container>
@ -50,7 +82,7 @@ import SelectMenu from "../common/SelectMenu";
import MsContainer from "../../common/components/MsContainer";
import MsAsideContainer from "../../common/components/MsAsideContainer";
import MsMainContainer from "../../common/components/MsMainContainer";
import {checkoutTestManagerOrTestUser, getCurrentProjectID, hasRoles} from "../../../../common/js/utils";
import {checkoutTestManagerOrTestUser, getCurrentProjectID, getUUID, hasRoles} from "../../../../common/js/utils";
import TestCaseNodeTree from "../common/TestCaseNodeTree";
import {TrackEvent,LIST_CHANGE} from "@/business/components/common/head/ListEvent";
@ -72,18 +104,152 @@ export default {
testCaseReadOnly: true,
selectNode: {},
condition: {},
moduleOptions: []
moduleOptions: [],
activeName: 'default',
tabs: [],
renderComponent:true,
loading: false,
type:''
}
},
mounted() {
this.init(this.$route);
},
watch: {
redirectID() {
this.renderComponent = false;
this.$nextTick(() => {
// DOM my-component
this.renderComponent = true;
});
},
'$route'(to, from) {
this.init(to);
if (to.path.indexOf('/track/case/all') == -1) {
if (this.$refs && this.$refs.autoScenarioConfig) {
console.log(this.$refs.autoScenarioConfig);
this.$refs.autoScenarioConfig.forEach(item => {
/*item.removeListener();*/
});
}
}
},
},
computed: {
checkRedirectID: function () {
let redirectIDParam = this.$route.params.redirectID;
this.changeRedirectParam(redirectIDParam);
return redirectIDParam;
},
isRedirectEdit: function () {
let redirectParam = this.$route.params.dataSelectRange;
this.checkRedirectEditPage(redirectParam);
return redirectParam;
}
},
methods: {
handleCommand(e) {
switch (e) {
case "ADD":
this.addTab({name: 'add'});
break;
case "CLOSE_ALL":
this.handleTabClose();
break;
default:
this.addTab({name: 'add'});
break;
}
},
changeRedirectParam(redirectIDParam) {
this.redirectID = redirectIDParam;
if (redirectIDParam != null) {
if (this.redirectFlag == "none") {
this.activeName = "default";
this.addListener();
this.redirectFlag = "redirected";
}
} else {
this.redirectFlag = "none";
}
},
checkRedirectEditPage(redirectParam) {
if (redirectParam != null) {
let selectParamArr = redirectParam.split("edit:");
if (selectParamArr.length == 2) {
let scenarioId = selectParamArr[1];
let projectId = getCurrentProjectID();
//
/* let url = "/api/automation/list/" + 1 + "/" + 1;
this.$post(url, {id: scenarioId, projectId: projectId}, response => {
let data = response.data;
if (data != null) {
//
if (JSON.stringify(this.moduleOptions) === '{}') {
this.$refs.nodeTree.list();
}
let row = data.listObject[0];
row.tags = JSON.parse(row.tags);
this.editScenario(row);
}
});*/
}
}
},
addTab(tab) {
if (!getCurrentProjectID()) {
this.$warning(this.$t('commons.check_project_tip'));
return;
}
if (tab.name === 'add') {
let label = this.$t('test_track.case.create');
let name = getUUID().substring(0, 8);
this.activeName = name;
this.type='add'
this.tabs.push({label: label, name: name, testCaseInfo: {testCaseModuleId: "", id: getUUID()}});
}
if (tab.name === 'edit') {
let label = this.$t('test_track.case.create');
let name = getUUID().substring(0, 8);
this.activeName = name;
label = tab.testCaseInfo.name;
this.tabs.push({label: label, name: name, testCaseInfo: tab.testCaseInfo});
}
if (this.$refs && this.$refs.testCaseEdit) {
this.$refs.testCaseEdit.forEach(item => {
/* item.removeListener();*/
}); // tab ctrl + s
this.addListener();
}
},
handleTabClose() {
this.tabs = [];
this.activeName = "default";
this.refresh();
},
removeTab(targetName) {
this.tabs = this.tabs.filter(tab => tab.name !== targetName);
if (this.tabs.length > 0) {
this.activeName = this.tabs[this.tabs.length - 1].name;
this.addListener(); //
} else {
this.activeName = "default"
}
},
exportTestCase(){
this.$refs.testCaseList.exportTestCase()
},
addListener() {
let index = this.tabs.findIndex(item => item.name === this.activeName); // tabindex
if (index != -1) { // tab
this.$nextTick(() => {
/*
this.$refs.testCaseEdit[index].addListener();
*/
});
}
},
init(route) {
let path = route.path;
if (path.indexOf("/track/case/edit") >= 0 || path.indexOf("/track/case/create") >= 0) {
@ -96,7 +262,9 @@ export default {
this.$warning(this.$t('commons.check_project_tip'));
return;
}
/*
this.openRecentTestCaseEditDialog(caseId);
*/
this.$router.push('/track/case/all');
}
},
@ -109,24 +277,32 @@ export default {
this.$refs.testCaseList.initTableData();
},
editTestCase(testCase) {
this.type="edit"
this.testCaseReadOnly = false;
if (this.treeNodes.length < 1) {
this.$warning(this.$t('test_track.case.create_module_first'));
return;
}
this.$refs.testCaseEditDialog.open(testCase);
this.addTab({name: 'edit', testCaseInfo: testCase});
},
copyTestCase(testCase) {
this.type="copy"
this.testCaseReadOnly = false;
let item = {};
Object.assign(item, testCase);
item.name = '';
item.isCopy = true;
testCase.isCopy = true;
this.addTab({name: 'edit', testCaseInfo: testCase});
/*
this.$refs.testCaseEditDialog.open(item);
*/
},
showTestCaseDetail(testCase) {
this.testCaseReadOnly = true;
/*
this.$refs.testCaseEditDialog.open(testCase);
*/
},
refresh() {
this.selectNodeIds = [];
@ -143,11 +319,15 @@ export default {
// this.getProjectByCaseId(caseId);
this.$get('/test/case/get/' + caseId, response => {
if (response.data) {
/*
this.$refs.testCaseEditDialog.open(response.data);
*/
}
});
} else {
/*
this.$refs.testCaseEditDialog.open();
*/
}
},
setTreeNodes(data) {

View File

@ -0,0 +1,86 @@
<template>
<el-dialog :visible.sync="dialogTableVisible">
<div v-loading="result.loading">
<div>
<el-input
type="textarea"
:placeholder="$t('test_track.comment.send_comment')"
v-model="textarea"
maxlength="60"
show-word-limit
resize="none"
:autosize="{ minRows: 4, maxRows: 4}"
@keyup.ctrl.enter.native="sendComment"
:disabled="isReadOnly"
>
</el-input>
<el-button type="primary" size="mini" class="send-btn" @click="sendComment" :disabled="isReadOnly">
{{ $t('test_track.comment.send') }}
</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import ReviewCommentItem from "@/business/components/track/review/commom/ReviewCommentItem";
import {checkoutTestManagerOrTestUser, getUUID} from "@/common/js/utils";
export default {
name: "TestCaseComment",
components: {ReviewCommentItem},
props: {
caseId: String,
reviewId: String,
},
data() {
return {
result: {},
textarea: '',
isReadOnly: false,
dialogTableVisible: false
}
},
created() {
this.isReadOnly = !checkoutTestManagerOrTestUser();
},
methods: {
open() {
this.dialogTableVisible = true
},
sendComment() {
let comment = {};
comment.caseId = this.caseId;
comment.description = this.textarea;
if (!this.textarea) {
this.$warning(this.$t('test_track.comment.description_is_null'));
return;
}
this.result = this.$post('/test/case/comment/save', comment, () => {
this.$success(this.$t('test_track.comment.send_success'));
this.refresh(comment.caseId);
this.textarea = '';
this.dialogTableVisible = false
});
},
refresh(id) {
this.$emit('getComments');
},
}
}
</script>
<style scoped>
.send-btn {
margin-top: 5px;
width: 100%;
}
.comment-list {
overflow-y: scroll;
height: calc(100vh - 250px);
}
</style>

View File

@ -0,0 +1,135 @@
<template>
<el-dialog :close-on-click-modal="false" :title="$t('test_track.case.create')" :visible.sync="visible"
width="45%"
:destroy-on-close="true">
<el-form :model="testCaseForm" label-position="right" label-width="80px" size="small" :rules="rule"
ref="testCaseForm">
<el-form-item :label="$t('commons.name')" prop="name">
<el-input v-model="testCaseForm.name" autocomplete="off" :placeholder="$t('commons.name')"/>
</el-form-item>
<el-form-item :label="$t('api_test.automation.scenario.principal')" prop="principal">
<el-select v-model="testCaseForm.maintainer"
:placeholder="$t('api_test.automation.scenario.principal')" filterable size="small"
style="width: 100%">
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.id + ' (' + item.name + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('api_test.automation.scenario.follow_people')" prop="followPeople">
<el-select v-model="testCaseForm.followPeople"
:placeholder="$t('api_test.automation.scenario.follow_people')" filterable size="small"
style="width: 100%">
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.id + ' (' + item.name + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('commons.description')" prop="description" style="margin-bottom: 29px">
<el-input class="ms-http-textarea" v-model="testCaseForm.description"
type="textarea"
:autosize="{ minRows: 2, maxRows: 10}"
:rows="2" size="small"/>
</el-form-item>
</el-form>
<template v-slot:footer>
<ms-dialog-footer
@cancel="visible = false"
:isShow="true"
title="编辑详情"
@saveAsEdit="saveTestCase(true)"
@confirm="saveTestCase">
</ms-dialog-footer>
</template>
</el-dialog>
</template>
<script>
import {getCurrentProjectID, getCurrentUser, getUUID} from "@/common/js/utils";
import {WORKSPACE_ID} from "@/common/js/constants";
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
export default {
name: "TestCaseCreate",
components: {MsDialogFooter},
data(){
return{
testCaseForm:{},
visible: false,
currentModule: {},
userOptions: [],
rule: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
{max: 100, message: this.$t('test_track.length_less_than') + '100', trigger: 'blur'}
],
principal: [{
required: true,
message: this.$t('api_test.automation.scenario.select_principal'),
trigger: 'change'
}],
},
}
},
methods:{
saveTestCase(){
this.$refs['testCaseForm'].validate((valid) => {
if (valid) {
let path = "/api/automation/create";
this.setParameter();
/* this.$fileUpload(path, null, [], this.scenarioForm, () => {
this.visible = false;
if (saveAs) {
this.scenarioForm.request = JSON.stringify(this.scenarioForm.request);
this.$emit('saveAsEdit', this.scenarioForm);
} else {
this.$emit('refresh');
}
});*/
} else {
return false;
}
})
},
setParameter() {
this.scenarioForm.projectId = getCurrentProjectID();
this.scenarioForm.id = getUUID().substring(0, 8);
this.scenarioForm.protocol = this.currentProtocol;
if (this.currentModule && this.currentModule.id != "root") {
this.scenarioForm.modulePath = this.currentModule.method !== undefined ? this.currentModule.method : null;
this.scenarioForm.apiScenarioModuleId = this.currentModule.id;
}
},
getMaintainerOptions() {
let workspaceId = localStorage.getItem(WORKSPACE_ID);
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
this.userOptions = response.data;
});
},
open(currentModule) {
this.scenarioForm = {principal: getCurrentUser().id};
this.currentModule = currentModule;
this.getMaintainerOptions();
this.visible = true;
}
}
}
</script>
<style scoped>
</style>

View File

@ -1,283 +1,302 @@
<template>
<el-card>
<div class="card-content">
<div class="ms-main-div" @click="showAll">
<el-dialog :close-on-click-modal="false" class="case-dialog"
@close="close"
:title="operationType == 'edit' ? ( readOnly ? $t('test_track.case.view_case') : $t('test_track.case.edit_case')) : $t('test_track.case.create')"
:visible.sync="dialogFormVisible" width="85%" v-if="dialogFormVisible">
<!--操作按钮-->
<div class="ms-opt-btn">
<el-button v-if="type!='add'" id="inputDelay" type="primary" size="small" @click="saveCase" title="ctrl + s">
{{ $t('commons.save') }}
</el-button>
<el-dropdown v-else split-button type="primary" class="ms-api-buttion" @click="handleCommand"
@command="handleCommand" size="small" style="float: right;margin-right: 20px">
{{ $t('commons.save') }}
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="ADD_AND_CREATE">{{ $t('test_track.case.save_create_continue') }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<el-form :model="form" :rules="rules" ref="caseFrom" v-loading="result.loading" class="case-form">
<div class="tip">{{ $t('test_track.plan_view.base_info') }}</div>
<el-row>
<el-col :span="7">
<el-form-item
:placeholder="$t('test_track.case.input_name')"
:label="$t('test_track.case.name')"
:label-width="formLabelWidth"
prop="name">
<el-input :disabled="readOnly" v-model="form.name" size="small" class="ms-case-input"></el-input>
</el-form-item>
</el-col>
<template v-slot:title>
<el-row>
<el-col :span="4">
<span>
{{
operationType == 'edit' ? (readOnly ? $t('test_track.case.view_case') : $t('test_track.case.edit_case')) : $t('test_track.case.create')
}}
</span>
</el-col>
<el-col class="head-right" :span="19">
<ms-previous-next-button v-if="operationType == 'edit'" :index="index" @pre="handlePre" @next="handleNext" :list="testCases"/>
</el-col>
</el-row>
</template>
<el-col :span="7">
<el-form-item :label="$t('test_track.case.module')" :label-width="formLabelWidth" prop="module">
<el-select
v-model="form.module"
:disabled="readOnly"
:placeholder="$t('test_track.case.input_module')"
filterable
class="ms-case-input">
<el-option
v-for="item in moduleOptions"
:key="item.id"
:label="item.path"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item label="状态" :label-width="formLabelWidth" prop="reviewStatus">
<el-select size="small" v-model="form.reviewStatus" class="ms-case-input">
<el-option v-for="item in options" :key="item.id" :label="item.label" :value="item.id"/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<div>
<el-col :span="17">
<el-card class="container">
<el-form :model="form" :rules="rules" ref="caseFrom" v-loading="result.loading" class="case-form">
<el-row>
<el-col :span="7">
<el-form-item :label="$t('commons.tag')" :label-width="formLabelWidth" prop="tag">
<ms-input-tag :currentScenario="form" v-if="showInputTag" ref="tag" class="ms-case-input"/>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item label="责任人" :label-width="formLabelWidth" prop="maintainer">
<el-select :disabled="readOnly" v-model="form.maintainer"
:placeholder="$t('test_track.case.input_maintainer')" filterable class="ms-case-input">
<el-option
v-for="item in maintainerOptions"
:key="item.id"
:label="item.id + ' (' + item.name + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-row>
<el-col :span="8" :offset="1">
<el-form-item
:placeholder="$t('test_track.case.input_name')"
:label="$t('test_track.case.name')"
:label-width="formLabelWidth"
prop="name">
<el-input class="case-name" :disabled="readOnly" v-model="form.name"></el-input>
</el-form-item>
</el-col>
</el-col>
<el-col :span="11" :offset="2">
<el-form-item :label="$t('test_track.case.module')" :label-width="formLabelWidth" prop="module">
<el-select
v-model="form.module"
<el-col :span="7">
<el-form-item :label="$t('test_track.case.priority')" :label-width="formLabelWidth" prop="priority">
<el-select :disabled="readOnly" v-model="form.priority" clearable
:placeholder="$t('test_track.case.input_priority')" class="ms-case-input">
<el-option label="P0" value="P0"></el-option>
<el-option label="P1" value="P1"></el-option>
<el-option label="P2" value="P2"></el-option>
<el-option label="P3" value="P3"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="7">
<el-form-item :label="$t('test_track.case.type')" :label-width="formLabelWidth" prop="type">
<el-select @change="typeChange" :disabled="readOnly" v-model="form.type"
:placeholder="$t('test_track.case.input_type')" class="ms-case-input">
<el-option :label="$t('commons.performance')" value="performance"></el-option>
<el-option :label="$t('commons.api')" value="api"></el-option>
<el-option :label="$t('api_test.home_page.failed_case_list.table_value.case_type.api')"
value="testcase"></el-option>
<el-option :label="$t('api_test.home_page.failed_case_list.table_value.case_type.scene')"
value="automation"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item :label="$t('test_track.case.relate_test')" :label-width="formLabelWidth" prop="testId">
<el-select filterable :disabled="readOnly" v-model="form.testId"
:placeholder="$t('test_track.case.input_type')" class="ms-case-input">
<el-option
v-for="item in testOptions"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="7" v-if="form.testId=='other'">
<el-form-item :label="$t('test_track.case.test_name')" :label-width="formLabelWidth" prop="testId">
<el-input v-model="form.otherTestName" :placeholder="$t('test_track.case.input_test_case')"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="10">
<el-form-item label="关联需求" :label-width="formLabelWidth" prop="demandId">
<el-select filterable :disabled="readOnly" v-model="form.demandId"
:placeholder="$t('test_track.case.input_type')" class="ms-case-input">
<el-option
v-for="item in demandOptions"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="需求名称" :label-width="formLabelWidth" prop="demandName" v-if="form.demandId=='other'">
<el-input v-model="form.demandName"></el-input>
</el-form-item>
</el-col>
</el-row>
<div class="tip">步骤信息</div>
<el-row style="margin-top: 10px;">
<el-col :span="1" :offset="1">{{ $t('test_track.case.prerequisite') }}:</el-col>
<el-col :span="19">
<el-form-item prop="prerequisite">
<el-input :disabled="readOnly" v-model="form.prerequisite"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
:rows="2"
:placeholder="$t('test_track.case.input_prerequisite')"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="1" :offset="1">{{ $t('test_track.case.steps') }}:</el-col>
<el-col :span="19">
<el-table
v-if="isStepTableAlive"
:data="form.steps"
class="tb-edit"
border
size="mini"
:default-sort="{prop: 'num', order: 'ascending'}"
highlight-current-row>
<el-table-column :label="$t('test_track.case.number')" prop="num" min-width="10%"></el-table-column>
<el-table-column :label="$t('test_track.case.step_desc')" prop="desc" min-width="35%">
<template v-slot:default="scope">
<el-input
class="table-edit-input"
size="mini"
:disabled="readOnly"
:placeholder="$t('test_track.case.input_module')"
filterable>
<el-option
v-for="item in moduleOptions"
:key="item.id"
:label="item.path"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="10" :offset="1">
<el-form-item :label="$t('test_track.case.maintainer')" :label-width="formLabelWidth" prop="maintainer">
<el-select :disabled="readOnly" v-model="form.maintainer"
:placeholder="$t('test_track.case.input_maintainer')" filterable>
<el-option
v-for="item in maintainerOptions"
:key="item.id"
:label="item.id + ' (' + item.name + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="$t('test_track.case.priority')" :label-width="formLabelWidth" prop="priority">
<el-select :disabled="readOnly" v-model="form.priority" clearable
:placeholder="$t('test_track.case.input_priority')">
<el-option label="P0" value="P0"></el-option>
<el-option label="P1" value="P1"></el-option>
<el-option label="P2" value="P2"></el-option>
<el-option label="P3" value="P3"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="10" :offset="1">
<el-form-item :label="$t('commons.tag')" :label-width="formLabelWidth" prop="tag">
<ms-input-tag :currentScenario="form" v-if="showInputTag" ref="tag"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="10" :offset="1">
<el-form-item :label="$t('test_track.case.type')" :label-width="formLabelWidth" prop="type">
<el-select @change="typeChange" :disabled="readOnly" v-model="form.type"
:placeholder="$t('test_track.case.input_type')">
<el-option :label="$t('commons.functional')" value="functional"></el-option>
<el-option :label="$t('commons.performance')" value="performance"></el-option>
<el-option :label="$t('commons.api')" value="api"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="$t('test_track.case.method')" :label-width="formLabelWidth" prop="method">
<el-select :disabled="readOnly" v-model="form.method" :placeholder="$t('test_track.case.input_method')">
<el-option
v-for="item in methodOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="form.method && form.method == 'auto'">
<el-col :span="9" :offset="1">
<el-form-item :label="$t('test_track.case.relate_test')" :label-width="formLabelWidth" prop="testId">
<el-select filterable :disabled="readOnly" v-model="form.testId"
:placeholder="$t('test_track.case.input_type')">
<el-option
v-for="item in testOptions"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="9" :offset="1" v-if="form.testId=='other'">
<el-form-item :label="$t('test_track.case.test_name')" :label-width="formLabelWidth" prop="testId">
<el-input v-model="form.otherTestName" :placeholder="$t('test_track.case.input_test_case')"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row style="margin-top: 15px;">
<el-col :offset="2">{{ $t('test_track.case.prerequisite') }}:</el-col>
</el-row>
<el-row type="flex" justify="center" style="margin-top: 10px;">
<el-col :span="20">
<el-form-item prop="prerequisite">
<el-input :disabled="readOnly" v-model="form.prerequisite"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
:rows="2"
:placeholder="$t('test_track.case.input_prerequisite')"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="form.method && form.method != 'auto'" style="margin-bottom: 10px">
<el-col :offset="2">{{ $t('test_track.case.steps') }}:</el-col>
</el-row>
<el-row v-if="form.method && form.method != 'auto'" type="flex" justify="center">
<el-col :span="20">
<el-table
v-if="isStepTableAlive"
:data="form.steps"
class="tb-edit"
border
size="mini"
:default-sort="{prop: 'num', order: 'ascending'}"
highlight-current-row>
<el-table-column :label="$t('test_track.case.number')" prop="num" min-width="10%"></el-table-column>
<el-table-column :label="$t('test_track.case.step_desc')" prop="desc" min-width="35%">
<template v-slot:default="scope">
<el-input
class="table-edit-input"
size="mini"
:disabled="readOnly"
type="textarea"
:autosize="{ minRows: 1, maxRows: 6}"
:rows="2"
v-model="scope.row.desc"
:placeholder="$t('commons.input_content')"
clearable/>
</template>
</el-table-column>
<el-table-column :label="$t('test_track.case.expected_results')" prop="result" min-width="35%">
<template v-slot:default="scope">
<el-input
class="table-edit-input"
size="mini"
:disabled="readOnly"
type="textarea"
:autosize="{ minRows: 1, maxRows: 6}"
:rows="2"
v-model="scope.row.result"
:placeholder="$t('commons.input_content')"
clearable/>
</template>
</el-table-column>
<el-table-column :label="$t('commons.input_content')" min-width="25%">
<template v-slot:default="scope">
<el-button
type="primary"
:disabled="readOnly"
icon="el-icon-plus"
circle size="mini"
@click="handleAddStep(scope.$index, scope.row)"></el-button>
<el-button
icon="el-icon-document-copy"
type="success"
:disabled="readOnly"
circle size="mini"
@click="handleCopyStep(scope.$index, scope.row)"></el-button>
<el-button
type="danger"
icon="el-icon-delete"
circle size="mini"
@click="handleDeleteStep(scope.$index, scope.row)"
:disabled="readOnly || (scope.$index == 0 && form.steps.length <= 1)"></el-button>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
<el-row style="margin-top: 10px;">
<el-col :span="1" :offset="1">{{ $t('commons.remark') }}:</el-col>
<el-col :span="19">
<el-form-item prop="remark">
<el-input v-model="form.remark"
:autosize="{ minRows: 2, maxRows: 4}"
type="textarea"
:autosize="{ minRows: 1, maxRows: 6}"
:disabled="readOnly"
:rows="2"
v-model="scope.row.desc"
:placeholder="$t('commons.input_content')"
clearable/>
</template>
</el-table-column>
<el-table-column :label="$t('test_track.case.expected_results')" prop="result" min-width="35%">
<template v-slot:default="scope">
<el-input
class="table-edit-input"
size="mini"
:disabled="readOnly"
type="textarea"
:autosize="{ minRows: 1, maxRows: 6}"
:rows="2"
v-model="scope.row.result"
:placeholder="$t('commons.input_content')"
clearable/>
</template>
</el-table-column>
<el-table-column :label="$t('commons.input_content')" min-width="25%">
<template v-slot:default="scope">
<el-button
type="primary"
:disabled="readOnly"
icon="el-icon-plus"
circle size="mini"
@click="handleAddStep(scope.$index, scope.row)"></el-button>
<el-button
icon="el-icon-document-copy"
type="success"
:disabled="readOnly"
circle size="mini"
@click="handleCopyStep(scope.$index, scope.row)"></el-button>
<el-button
type="danger"
icon="el-icon-delete"
circle size="mini"
@click="handleDeleteStep(scope.$index, scope.row)"
:disabled="readOnly || (scope.$index == 0 && form.steps.length <= 1)"></el-button>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
:placeholder="$t('commons.input_content')"></el-input>
</el-form-item>
</el-col>
</el-row>
<div class="tip">其他信息</div>
<el-row>
<el-col :span="20" :offset="1">{{ $t('test_track.case.attachment') }}:</el-col>
</el-row>
<el-row>
<el-col :span="19" :offset="2">
<el-upload
accept=".jpg,.jpeg,.png,.xlsx,.doc,.pdf,.docx"
action=""
:show-file-list="false"
:before-upload="beforeUpload"
:http-request="handleUpload"
:on-exceed="handleExceed"
multiple
:limit="8"
:file-list="fileList">
<el-button icon="el-icon-plus" size="mini"></el-button>
<span slot="tip" class="el-upload__tip"> {{ $t('test_track.case.upload_tip') }} </span>
</el-upload>
</el-col>
</el-row>
<el-row>
<el-col :span="19" :offset="2">
<test-case-attachment :table-data="tableData"
:read-only="readOnly"
:is-delete="true"
@handleDelete="handleDelete"
/>
</el-col>
</el-row>
<el-row style="margin-top: 10px" v-if="type!='add'">
<el-col :span="20" :offset="1">{{ $t('test_track.review.comment') }}:
<el-button icon="el-icon-plus" type="mini" @click="openComment"></el-button>
</el-col>
</el-row>
<el-row v-if="type!='add'">
<el-col :span="20" :offset="1">
<el-row style="margin-top: 15px;margin-bottom: 10px">
<el-col :offset="2">{{ $t('commons.remark') }}:</el-col>
</el-row>
<el-row type="flex" justify="center">
<el-col :span="20">
<el-form-item prop="remark">
<el-input v-model="form.remark"
:autosize="{ minRows: 2, maxRows: 4}"
type="textarea"
:disabled="readOnly"
:rows="2"
:placeholder="$t('commons.input_content')"></el-input>
</el-form-item>
</el-col>
</el-row>
<review-comment-item v-for="(comment,index) in comments"
:key="index"
:comment="comment"
@refresh="getComments"/>
<div v-if="comments.length === 0" style="text-align: center">
<i class="el-icon-chat-line-square" style="font-size: 15px;color: #8a8b8d;">
<span style="font-size: 15px; color: #8a8b8d;">
{{ $t('test_track.comment.no_comment') }}
</span>
</i>
</div>
</el-col>
</el-row>
<test-case-comment :case-id="form.id"
@getComments="getComments" ref="testCaseComment"/>
<el-row style="margin-top: 15px;margin-bottom: 10px">
<el-col :offset="2" :span="20">{{ $t('test_track.case.attachment') }}:
<el-upload
accept=".jpg,.jpeg,.png,.xlsx,.doc,.pdf,.docx"
action=""
:show-file-list="false"
:before-upload="beforeUpload"
:http-request="handleUpload"
:on-exceed="handleExceed"
multiple
:limit="8"
:file-list="fileList">
<el-button icon="el-icon-plus" size="mini"></el-button>
<span slot="tip" class="el-upload__tip"> {{ $t('test_track.case.upload_tip') }} </span>
</el-upload>
</el-col>
<el-col :offset="2" :span="20">
<test-case-attachment :table-data="tableData"
:read-only="readOnly"
:is-delete="true"
@handleDelete="handleDelete"
/>
</el-col>
</el-row>
</el-form>
</el-form>
<el-row style="float: right; margin-bottom: 20px;margin-top: 20px">
<el-switch v-if="operationType == 'add'"
v-model="isCreateContinue"
:active-text="$t('test_track.case.save_create_continue')">
</el-switch>
<ms-dialog-footer v-if="!readOnly"
@cancel="dialogFormVisible = false"
@confirm="saveCase"/>
</el-row>
</el-card>
</el-col>
<el-col :span="7">
<case-comment :case-id="testCase ? testCase.id : ''" class="comment-card"/>
</el-col>
</div>
</el-row>
</el-dialog>
</div>
</el-card>
</template>
@ -295,12 +314,21 @@ import {buildNodePath} from "../../../api/definition/model/NodeTree";
import CaseComment from "@/business/components/track/case/components/CaseComment";
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
import MsPreviousNextButton from "../../../common/components/MsPreviousNextButton";
import {ELEMENTS} from "@/business/components/api/automation/scenario/Setting";
import TestCaseComment from "@/business/components/track/case/components/TestCaseComment";
import ReviewCommentItem from "@/business/components/track/review/commom/ReviewCommentItem";
import {API_STATUS, REVIEW_STATUS} from "@/business/components/api/definition/model/JsonData";
export default {
name: "TestCaseEdit",
components: {MsPreviousNextButton, MsInputTag, CaseComment, MsDialogFooter, TestCaseAttachment},
components: {
ReviewCommentItem,
TestCaseComment, MsPreviousNextButton, MsInputTag, CaseComment, MsDialogFooter, TestCaseAttachment
},
data() {
return {
options: REVIEW_STATUS,
comments: [],
result: {},
projectId: "",
dialogFormVisible: false,
@ -321,10 +349,14 @@ export default {
}],
remark: '',
tags: [],
demandId: '',
demandName: '',
},
readOnly: false,
moduleOptions: [],
maintainerOptions: [],
testOptions: [],
demandOptions: [],
workspaceId: '',
fileList: [],
tableData: [],
@ -361,19 +393,27 @@ export default {
treeNodes: {
type: Array
},
readOnly: {
type: Boolean,
default: true
currentTestCaseInfo: {},
setModuleOptions: {
type: Array
},
/*readOnly: {
type: Boolean,
default: false
},*/
selectNode: {
type: Object
},
selectCondition: {
type: Object
},
type: String
},
mounted() {
this.getSelectOptions();
if (this.type === 'edit' || this.type === 'copy') {
this.open(this.currentTestCaseInfo)
}
},
watch: {
treeNodes() {
@ -384,9 +424,46 @@ export default {
}
},
methods: {
handleCommand(e) {
if (e === "ADD_AND_CREATE") {
this.$refs['caseFrom'].validate((valid) => {
if (!valid) {
this.saveCase();
} else {
this.saveCase();
let tab={}
tab.name='add'
this.$emit('addTab',tab)}
})
}else {
this.saveCase();
}
},
openComment() {
this.$refs.testCaseComment.open()
},
getComments(testCase) {
let id = '';
if (testCase) {
id = testCase.id;
} else {
id = this.form.id;
}
this.result = this.$get('/test/case/comment/list/' + id, res => {
this.comments = res.data;
})
},
showAll() {
if (!this.customizeVisible) {
this.operatingElements = ELEMENTS.get("ALL");
this.selectedTreeNode = undefined;
}
//this.reload();
},
reload() {
this.isStepTableAlive = false;
this.$nextTick(() => (this.isStepTableAlive = true));
console.log(this.form)
},
open(testCase) {
this.projectId = getCurrentProjectID();
@ -401,7 +478,7 @@ export default {
//
this.operationType = 'edit';
//
if (testCase.name === '') {
if (this.type === 'copy') {
this.operationType = 'add';
this.setFormData(testCase);
this.setTestCaseExtInfo(testCase);
@ -427,7 +504,6 @@ export default {
this.getSelectOptions();
this.reload();
}
this.dialogFormVisible = true;
},
handlePre() {
this.index--;
@ -534,11 +610,17 @@ export default {
this.dialogFormVisible = false;
},
saveCase() {
/*
document.getElementById("inputDelay").focus();
*/
// input
this.$refs['caseFrom'].validate((valid) => {
if (valid) {
let param = this.buildParam();
if (this.validate(param)) {
let option = this.getOption(param);
console.log(option)
this.result = this.$request(option, () => {
this.$success(this.$t('commons.save_success'));
if (this.operationType == 'add' && this.isCreateContinue) {
@ -569,6 +651,7 @@ export default {
},
buildParam() {
let param = {};
Object.assign(param, this.form);
param.steps = JSON.stringify(this.form.steps);
param.nodeId = this.form.module;
@ -581,9 +664,7 @@ export default {
param.projectId = this.projectId;
}
param.name = param.name.trim();
if (param.method != 'auto') {
param.testId = null;
}
if (this.form.tags instanceof Array) {
this.form.tags = JSON.stringify(this.form.tags);
}
@ -591,8 +672,14 @@ export default {
return param;
},
getOption(param) {
console.log(this.type)
console.log("3452")
let formData = new FormData();
let url = '/test/case/' + this.operationType;
let type = this.type
if (this.type === 'copy') {
type = 'add'
}
let url = '/test/case/' + type;
this.uploadList.forEach(f => {
formData.append("file", f);
});
@ -654,21 +741,33 @@ export default {
});
},
getTestOptions() {
this.projectId = getCurrentProjectID()
this.testOptions = [];
if (this.projectId && this.form.type != '' && this.form.type != 'functional') {
this.result = this.$get('/' + this.form.type + '/list/' + this.projectId, response => {
let url = '';
if (this.form.type === 'testcase' || this.form.type === 'automation') {
url = '/api/' + this.form.type + '/list/' + this.projectId
} else if (this.form.type === 'performance' || this.form.type === 'api') {
url = '/' + this.form.type + '/list/' + this.projectId
}
if (this.projectId && this.form.type != '' && this.form.type != 'undefined') {
this.result = this.$get(url, response => {
this.testOptions = response.data;
this.testOptions.unshift({id: 'other', name: this.$t('test_track.case.other')})
});
} else if (this.form.type === 'functional') {
this.testOptions = [{id: 'other', name: this.$t('test_track.case.other')}];
this.form.testId = 'other';
}
},
getDemandOptions() {
this.projectId = getCurrentProjectID()
this.result = this.$get("demand/list/" + this.projectId, response => {
this.demandOptions = response.data;
this.demandOptions.unshift({id: 'other', name: this.$t('test_track.case.other')})
});
},
getSelectOptions() {
this.getModuleOptions();
this.getMaintainerOptions();
this.getTestOptions();
this.getDemandOptions()
},
resetForm() {
@ -826,4 +925,25 @@ export default {
text-align: right;
}
.tip {
padding: 3px 5px;
font-size: 16px;
border-radius: 4px;
border-left: 4px solid #783887;
}
.ms-main-div {
background-color: white;
}
.ms-opt-btn {
position: fixed;
right: 50px;
z-index: 1;
}
.ms-case-input {
width: 100%;
}
</style>

View File

@ -3,40 +3,25 @@
<div class="card-container">
<el-card class="card-content" v-loading="result.loading">
<template v-slot:header>
<ms-table-header :is-tester-permission="true" :condition.sync="condition" @search="initTableData"
:tip="$t('commons.search_by_name_or_id')"
:create-tip="$t('test_track.case.create')" @create="testCaseCreate">
<template v-slot:title>
<node-breadcrumb class="table-title" :nodes="selectParentNodes" @refresh="refresh"/>
</template>
<template v-slot:button>
<ms-table-button :is-tester-permission="true" icon="el-icon-download"
:content="$t('test_track.case.import.import')" @click="importTestCase"/>
<ms-table-button :is-tester-permission="true" icon="el-icon-upload2"
:content="$t('test_track.case.export.export')" @click="handleBatch('export')"/>
</template>
</ms-table-header>
:tip="$t('commons.search_by_name_or_id')" title="" :show-create="false"
/>
</template>
<test-case-import @refreshAll="refreshAll" ref="testCaseImport"/>
<el-table
border
:data="tableData"
@sort-change="sort"
@filter-change="filter"
@select-all="handleSelectAll"
@select="handleSelect"
@header-dragend="headerDragend"
@cell-mouse-enter="showPopover"
row-key="id"
class="test-content adjust-table ms-select-all-fixed"
ref="table" @row-click="handleEdit">
border
:data="tableData"
@sort-change="sort"
@filter-change="filter"
@select-all="handleSelectAll"
@select="handleSelect"
@header-dragend="headerDragend"
@cell-mouse-enter="showPopover"
row-key="id"
class="test-content adjust-table ms-select-all-fixed"
ref="table" @row-click="handleEdit">
<el-table-column
width="50"
type="selection"/>
width="50"
type="selection"/>
<ms-table-header-select-popover v-show="total>0"
:page-size="pageSize > total ? total : pageSize"
@ -52,80 +37,80 @@
<template v-for="(item, index) in tableLabel">
<el-table-column
v-if="item.id == 'num'"
prop="num"
sortable="custom"
:label="$t('commons.id')"
:key="index"
show-overflow-tooltip>
v-if="item.id == 'num'"
prop="num"
sortable="custom"
:label="$t('commons.id')"
:key="index"
show-overflow-tooltip>
</el-table-column>
<el-table-column
v-if="item.id == 'name'"
prop="name"
:label="$t('commons.name')"
show-overflow-tooltip
:key="index"
v-if="item.id == 'name'"
prop="name"
:label="$t('commons.name')"
show-overflow-tooltip
:key="index"
>
<template v-slot:default="scope">
<!--<div @mouseover="showDetail(scope.row)">
<!-- <template v-slot:default="scope">
&lt;!&ndash;<div @mouseover="showDetail(scope.row)">
<p>{{ scope.row.name }}</p>
</div>-->
</div>&ndash;&gt;
<el-popover
placement="right-end"
:title="$t('test_track.case.view_case')"
trigger="hover"
placement="right-end"
:title="$t('test_track.case.view_case')"
trigger="hover"
>
<test-case-detail v-if="currentCaseId === scope.row.id" :test-case-id="currentCaseId"/>
<span slot="reference">{{ scope.row.name }}</span>
</el-popover>
</template>
</template>-->
</el-table-column>
<el-table-column
v-if="item.id == 'priority'"
prop="priority"
:filters="priorityFilters"
column-key="priority"
min-width="100px"
:label="$t('test_track.case.priority')"
show-overflow-tooltip
:key="index">
v-if="item.id == 'priority'"
prop="priority"
:filters="priorityFilters"
column-key="priority"
min-width="100px"
:label="$t('test_track.case.priority')"
show-overflow-tooltip
:key="index">
<template v-slot:default="scope">
<priority-table-item :value="scope.row.priority"/>
</template>
</el-table-column>
<el-table-column
v-if="item.id == 'type'"
prop="type"
:filters="typeFilters"
column-key="type"
:label="$t('test_track.case.type')"
show-overflow-tooltip
:key="index">
<!-- <el-table-column
v-if="item.id == 'type'"
prop="type"
:filters="typeFilters"
column-key="type"
:label="$t('test_track.case.type')"
show-overflow-tooltip
:key="index">
<template v-slot:default="scope">
<type-table-item :value="scope.row.type"/>
</template>
</el-table-column>
<el-table-column
v-if="item.id=='method'"
prop="method"
column-key="method"
:filters="methodFilters"
min-width="100px"
:label="$t('test_track.case.method')"
show-overflow-tooltip
:key="index">
</el-table-column>-->
<!-- <el-table-column
v-if="item.id=='method'"
prop="method"
column-key="method"
:filters="methodFilters"
min-width="100px"
:label="$t('test_track.case.method')"
show-overflow-tooltip
:key="index">
<template v-slot:default="scope">
<method-table-item :value="scope.row.method"/>
</template>
</el-table-column>
</el-table-column>-->
<el-table-column
v-if="item.id=='status'"
:filters="statusFilters"
column-key="status"
min-width="100px"
:label="$t('test_track.case.status')"
:key="index">
v-if="item.id=='status'"
:filters="statusFilters"
column-key="status"
min-width="100px"
:label="$t('test_track.case.status')"
:key="index">
<template v-slot:default="scope">
<span class="el-dropdown-link">
<review-status :value="scope.row.reviewStatus"/>
@ -135,27 +120,28 @@
<el-table-column v-if="item.id=='tags'" prop="tags" :label="$t('commons.tag')" :key="index">
<template v-slot:default="scope">
<ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain" :content="itemName" style="margin-left: 5px"/>
<ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain"
:content="itemName" style="margin-left: 5px"/>
</template>
</el-table-column>
<el-table-column
v-if="item.id=='nodePath'"
prop="nodePath"
:label="$t('test_track.case.module')"
min-width="150px"
show-overflow-tooltip
:key="index">
v-if="item.id=='nodePath'"
prop="nodePath"
:label="$t('test_track.case.module')"
min-width="150px"
show-overflow-tooltip
:key="index">
</el-table-column>
<el-table-column
v-if="item.id=='updateTime'"
prop="updateTime"
sortable="custom"
:label="$t('commons.update_time')"
min-width="150px"
show-overflow-tooltip
:key="index">
v-if="item.id=='updateTime'"
prop="updateTime"
sortable="custom"
:label="$t('commons.update_time')"
min-width="150px"
show-overflow-tooltip
:key="index">
<template v-slot:default="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template>
@ -170,12 +156,12 @@
@deleteClick="handleDelete(scope.row)">
<template v-slot:middle>
<ms-table-operator-button :is-tester-permission="true" :tip="$t('commons.copy')"
icon="el-icon-document-copy"
type="success" @exec="handleCopy(scope.row)"/>
</template>
</ms-table-operator>
</template>
</el-table-column>
icon="el-icon-document-copy"
type="success" @exec="handleCopy(scope.row)"/>
</template>
</ms-table-operator>
</template>
</el-table-column>
<header-custom ref="headerCustom" :initTableData="initTableData" :optionalFields=headerItems
:type=type></header-custom>
</el-table>
@ -415,6 +401,7 @@ export default {
handleCopy(testCase) {
this.$get('test/case/get/' + testCase.id, response => {
let testCase = response.data;
testCase.name='copy_'+testCase.name
this.$emit('testCaseCopy', testCase);
});
},

View File

@ -1,25 +1,57 @@
<template>
<ms-node-tree
v-loading="result.loading"
:tree-nodes="treeNodes"
:type="'edit'"
@add="add"
@edit="edit"
@drag="drag"
@remove="remove"
@nodeSelectEvent="nodeChange"
@refresh="list"
ref="nodeTree"/>
<div>
<slot name="header"></slot>
<ms-node-tree
v-loading="result.loading"
:tree-nodes="treeNodes"
:type="'edit'"
@add="add"
@edit="edit"
@drag="drag"
@remove="remove"
@nodeSelectEvent="nodeChange"
@refresh="list"
ref="nodeTree">
<template v-slot:header>
<el-input :placeholder="$t('test_track.module.search')" v-model="condition.filterText" size="small">
<template v-slot:append>
<el-dropdown size="small" split-button type="primary" class="ms-api-button"
@click="handleCommand('add-api')"
v-tester
@command="handleCommand">
<el-button icon="el-icon-folder-add" @click="addTestCase"></el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="add-testcase">{{ $t('test_track.case.create') }}</el-dropdown-item>
<el-dropdown-item command="import">{{ $t('api_test.api_import.label') }}</el-dropdown-item>
<el-dropdown-item command="export">{{ $t('api_test.export_config') }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-input>
</template>
</ms-node-tree>
<test-case-import @refreshAll="refreshAll" ref="testCaseImport"></test-case-import>
<test-case-create
@saveAsEdit="saveAsEdit"
@refresh="refresh"
ref="testCaseCreate"
></test-case-create>
</div>
</template>
<script>
import NodeEdit from "./NodeEdit";
import {getCurrentProjectID} from "../../../../common/js/utils";
import MsNodeTree from "./NodeTree";
import {buildNodePath} from "@/business/components/api/definition/model/NodeTree";
import TestCaseCreate from "@/business/components/track/case/components/TestCaseCreate";
import TestCaseImport from "@/business/components/track/case/components/TestCaseImport";
export default {
name: "TestCaseNodeTree",
components: {MsNodeTree, NodeEdit},
components: {TestCaseImport, TestCaseCreate, MsNodeTree, NodeEdit},
data() {
return {
defaultProps: {
@ -28,76 +60,114 @@ export default {
},
result: {},
treeNodes: [],
projectId: ""
};
},
props: {
type: {
type: String,
default: "view"
projectId: "",
condition: {
filterText: "",
trashEnable: false
},
};
},
props: {
type: {
type: String,
default: "view"
},
watch: {
treeNodes() {
this.$emit('setTreeNodes', this.treeNodes);
},
watch: {
treeNodes() {
this.$emit('setTreeNodes', this.treeNodes);
}
},
mounted() {
this.projectId = getCurrentProjectID();
this.list();
},
methods: {
addTestCase(){
if (!getCurrentProjectID()) {
this.$warning(this.$t('commons.check_project_tip'));
return;
}
this.$refs.testCaseCreate.open(this.currentModule)
},
saveAsEdit(data) {
this.$emit('saveAsEdit', data);
},
refresh() {
this.$emit("refreshTable");
},
refreshAll() {
this.selectRows.clear();
this.$emit('refreshAll');
},
handleCommand(e) {
switch (e) {
case "add-testcase":
this.addTestCase();
break;
case "import":
if (!getCurrentProjectID()) {
this.$warning(this.$t('commons.check_project_tip'));
return;
}
this.$refs.testCaseImport.open();
break;
case "export":
this.$emit('exportTestCase')
break;
}
},
mounted() {
this.projectId = getCurrentProjectID();
this.list();
list() {
if (this.projectId) {
this.result = this.$get("/case/node/list/" + this.projectId, response => {
this.treeNodes = response.data;
if (this.$refs.nodeTree) {
this.$refs.nodeTree.filter();
}
});
}
},
methods: {
list() {
if (this.projectId) {
this.result = this.$get("/case/node/list/" + this.projectId, response => {
this.treeNodes = response.data;
if (this.$refs.nodeTree) {
this.$refs.nodeTree.filter();
}
});
}
},
edit(param) {
param.projectId = this.projectId;
this.$post("/case/node/edit", param, () => {
this.$success(this.$t('commons.save_success'));
this.list();
this.$emit("refreshTable");
}, (error) => {
this.list();
});
},
add(param) {
param.projectId = this.projectId;
this.$post("/case/node/add", param, () => {
this.$success(this.$t('commons.save_success'));
this.list();
}, (error) => {
this.list();
});
},
remove(nodeIds) {
this.$post("/case/node/delete", nodeIds, () => {
this.list();
this.$emit("refreshTable")
}, (error) => {
this.list();
});
},
drag(param, list) {
this.$post("/case/node/drag", param, () => {
this.$post("/case/node/pos", list);
this.list();
}, (error) => {
this.list();
});
},
nodeChange(node, nodeIds, pNodes) {
this.$emit("nodeSelectEvent", node, nodeIds, pNodes);
},
}
};
edit(param) {
param.projectId = this.projectId;
this.$post("/case/node/edit", param, () => {
this.$success(this.$t('commons.save_success'));
this.list();
this.$emit("refreshTable");
}, (error) => {
this.list();
});
},
add(param) {
param.projectId = this.projectId;
this.$post("/case/node/add", param, () => {
this.$success(this.$t('commons.save_success'));
this.list();
}, (error) => {
this.list();
});
},
remove(nodeIds) {
this.$post("/case/node/delete", nodeIds, () => {
this.list();
this.$emit("refreshTable")
}, (error) => {
this.list();
});
},
drag(param, list) {
this.$post("/case/node/drag", param, () => {
this.$post("/case/node/pos", list);
this.list();
}, (error) => {
this.list();
});
},
nodeChange(node, nodeIds, pNodes) {
this.$emit("nodeSelectEvent", node, nodeIds, pNodes);
},
}
};
</script>
<style scoped>