feat(测试跟踪): 测试用例新增公共用例库

--story=1004196 --user=王孝刚 功能用例增加公共用例库(X-Pack)
https://www.tapd.cn/55049933/s/1080558
This commit is contained in:
wxg0103 2021-12-03 17:26:32 +08:00 committed by 刘瑞斌
parent 0cf3b55d3a
commit f54e7aaaeb
30 changed files with 1446 additions and 418 deletions

View File

@ -45,6 +45,10 @@ public class Project implements Serializable {
private String azureFilterId;
private String apiQuick;
private Boolean casePublic;
private String platform;
private Boolean thirdPartTemplate;

View File

@ -1434,6 +1434,136 @@ public class ProjectExample {
return (Criteria) this;
}
public Criteria andApiQuickIsNull() {
addCriterion("api_quick is null");
return (Criteria) this;
}
public Criteria andApiQuickIsNotNull() {
addCriterion("api_quick is not null");
return (Criteria) this;
}
public Criteria andApiQuickEqualTo(String value) {
addCriterion("api_quick =", value, "apiQuick");
return (Criteria) this;
}
public Criteria andApiQuickNotEqualTo(String value) {
addCriterion("api_quick <>", value, "apiQuick");
return (Criteria) this;
}
public Criteria andApiQuickGreaterThan(String value) {
addCriterion("api_quick >", value, "apiQuick");
return (Criteria) this;
}
public Criteria andApiQuickGreaterThanOrEqualTo(String value) {
addCriterion("api_quick >=", value, "apiQuick");
return (Criteria) this;
}
public Criteria andApiQuickLessThan(String value) {
addCriterion("api_quick <", value, "apiQuick");
return (Criteria) this;
}
public Criteria andApiQuickLessThanOrEqualTo(String value) {
addCriterion("api_quick <=", value, "apiQuick");
return (Criteria) this;
}
public Criteria andApiQuickLike(String value) {
addCriterion("api_quick like", value, "apiQuick");
return (Criteria) this;
}
public Criteria andApiQuickNotLike(String value) {
addCriterion("api_quick not like", value, "apiQuick");
return (Criteria) this;
}
public Criteria andApiQuickIn(List<String> values) {
addCriterion("api_quick in", values, "apiQuick");
return (Criteria) this;
}
public Criteria andApiQuickNotIn(List<String> values) {
addCriterion("api_quick not in", values, "apiQuick");
return (Criteria) this;
}
public Criteria andApiQuickBetween(String value1, String value2) {
addCriterion("api_quick between", value1, value2, "apiQuick");
return (Criteria) this;
}
public Criteria andApiQuickNotBetween(String value1, String value2) {
addCriterion("api_quick not between", value1, value2, "apiQuick");
return (Criteria) this;
}
public Criteria andCasePublicIsNull() {
addCriterion("case_public is null");
return (Criteria) this;
}
public Criteria andCasePublicIsNotNull() {
addCriterion("case_public is not null");
return (Criteria) this;
}
public Criteria andCasePublicEqualTo(Boolean value) {
addCriterion("case_public =", value, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicNotEqualTo(Boolean value) {
addCriterion("case_public <>", value, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicGreaterThan(Boolean value) {
addCriterion("case_public >", value, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicGreaterThanOrEqualTo(Boolean value) {
addCriterion("case_public >=", value, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicLessThan(Boolean value) {
addCriterion("case_public <", value, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicLessThanOrEqualTo(Boolean value) {
addCriterion("case_public <=", value, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicIn(List<Boolean> values) {
addCriterion("case_public in", values, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicNotIn(List<Boolean> values) {
addCriterion("case_public not in", values, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicBetween(Boolean value1, Boolean value2) {
addCriterion("case_public between", value1, value2, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicNotBetween(Boolean value1, Boolean value2) {
addCriterion("case_public not between", value1, value2, "casePublic");
return (Criteria) this;
}
public Criteria andPlatformIsNull() {
addCriterion("platform is null");
return (Criteria) this;

View File

@ -59,5 +59,7 @@ public class TestCase implements Serializable {
private Long order;
private Boolean casePublic;
private static final long serialVersionUID = 1L;
}

View File

@ -1933,6 +1933,66 @@ public class TestCaseExample {
addCriterion("`order` not between", value1, value2, "order");
return (Criteria) this;
}
public Criteria andCasePublicIsNull() {
addCriterion("case_public is null");
return (Criteria) this;
}
public Criteria andCasePublicIsNotNull() {
addCriterion("case_public is not null");
return (Criteria) this;
}
public Criteria andCasePublicEqualTo(Boolean value) {
addCriterion("case_public =", value, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicNotEqualTo(Boolean value) {
addCriterion("case_public <>", value, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicGreaterThan(Boolean value) {
addCriterion("case_public >", value, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicGreaterThanOrEqualTo(Boolean value) {
addCriterion("case_public >=", value, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicLessThan(Boolean value) {
addCriterion("case_public <", value, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicLessThanOrEqualTo(Boolean value) {
addCriterion("case_public <=", value, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicIn(List<Boolean> values) {
addCriterion("case_public in", values, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicNotIn(List<Boolean> values) {
addCriterion("case_public not in", values, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicBetween(Boolean value1, Boolean value2) {
addCriterion("case_public between", value1, value2, "casePublic");
return (Criteria) this;
}
public Criteria andCasePublicNotBetween(Boolean value1, Boolean value2) {
addCriterion("case_public not between", value1, value2, "casePublic");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -22,6 +22,8 @@
<result column="mock_tcp_port" jdbcType="INTEGER" property="mockTcpPort"/>
<result column="is_mock_tcp_open" jdbcType="BIT" property="isMockTcpOpen"/>
<result column="azure_filter_id" jdbcType="VARCHAR" property="azureFilterId"/>
<result column="api_quick" jdbcType="VARCHAR" property="apiQuick"/>
<result column="case_public" jdbcType="BIT" property="casePublic"/>
<result column="platform" jdbcType="VARCHAR" property="platform"/>
<result column="third_part_template" jdbcType="BIT" property="thirdPartTemplate"/>
</resultMap>
@ -84,10 +86,11 @@
</where>
</sql>
<sql id="Base_Column_List">
id, workspace_id, `name`, description, create_time, update_time, tapd_id, jira_key,
id
, workspace_id, `name`, description, create_time, update_time, tapd_id, jira_key,
zentao_id, azure_devops_id, `repeatable`, case_template_id, issue_template_id, custom_num,
scenario_custom_num, create_user, system_id, mock_tcp_port, is_mock_tcp_open, azure_filter_id,
platform, third_part_template
api_quick, case_public, platform, third_part_template
</sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.ProjectExample" resultMap="BaseResultMap">
select
@ -126,16 +129,16 @@
azure_devops_id, `repeatable`, case_template_id,
issue_template_id, custom_num, scenario_custom_num,
create_user, system_id, mock_tcp_port,
is_mock_tcp_open, azure_filter_id, platform,
third_part_template)
is_mock_tcp_open, azure_filter_id, api_quick,
case_public, platform, third_part_template)
values (#{id,jdbcType=VARCHAR}, #{workspaceId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{tapdId,jdbcType=VARCHAR}, #{jiraKey,jdbcType=VARCHAR}, #{zentaoId,jdbcType=VARCHAR},
#{azureDevopsId,jdbcType=VARCHAR}, #{repeatable,jdbcType=BIT}, #{caseTemplateId,jdbcType=VARCHAR},
#{issueTemplateId,jdbcType=VARCHAR}, #{customNum,jdbcType=BIT}, #{scenarioCustomNum,jdbcType=BIT},
#{createUser,jdbcType=VARCHAR}, #{systemId,jdbcType=VARCHAR}, #{mockTcpPort,jdbcType=INTEGER},
#{isMockTcpOpen,jdbcType=BIT}, #{azureFilterId,jdbcType=VARCHAR}, #{platform,jdbcType=VARCHAR},
#{thirdPartTemplate,jdbcType=BIT})
#{isMockTcpOpen,jdbcType=BIT}, #{azureFilterId,jdbcType=VARCHAR}, #{apiQuick,jdbcType=VARCHAR},
#{casePublic,jdbcType=BIT}, #{platform,jdbcType=VARCHAR}, #{thirdPartTemplate,jdbcType=BIT})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.Project">
insert into project
@ -200,6 +203,12 @@
<if test="azureFilterId != null">
azure_filter_id,
</if>
<if test="apiQuick != null">
api_quick,
</if>
<if test="casePublic != null">
case_public,
</if>
<if test="platform != null">
platform,
</if>
@ -268,6 +277,12 @@
<if test="azureFilterId != null">
#{azureFilterId,jdbcType=VARCHAR},
</if>
<if test="apiQuick != null">
#{apiQuick,jdbcType=VARCHAR},
</if>
<if test="casePublic != null">
#{casePublic,jdbcType=BIT},
</if>
<if test="platform != null">
#{platform,jdbcType=VARCHAR},
</if>
@ -345,6 +360,12 @@
<if test="record.azureFilterId != null">
azure_filter_id = #{record.azureFilterId,jdbcType=VARCHAR},
</if>
<if test="record.apiQuick != null">
api_quick = #{record.apiQuick,jdbcType=VARCHAR},
</if>
<if test="record.casePublic != null">
case_public = #{record.casePublic,jdbcType=BIT},
</if>
<if test="record.platform != null">
platform = #{record.platform,jdbcType=VARCHAR},
</if>
@ -378,6 +399,8 @@
mock_tcp_port = #{record.mockTcpPort,jdbcType=INTEGER},
is_mock_tcp_open = #{record.isMockTcpOpen,jdbcType=BIT},
azure_filter_id = #{record.azureFilterId,jdbcType=VARCHAR},
api_quick = #{record.apiQuick,jdbcType=VARCHAR},
case_public = #{record.casePublic,jdbcType=BIT},
platform = #{record.platform,jdbcType=VARCHAR},
third_part_template = #{record.thirdPartTemplate,jdbcType=BIT}
<if test="_parameter != null">
@ -444,6 +467,12 @@
<if test="azureFilterId != null">
azure_filter_id = #{azureFilterId,jdbcType=VARCHAR},
</if>
<if test="apiQuick != null">
api_quick = #{apiQuick,jdbcType=VARCHAR},
</if>
<if test="casePublic != null">
case_public = #{casePublic,jdbcType=BIT},
</if>
<if test="platform != null">
platform = #{platform,jdbcType=VARCHAR},
</if>
@ -474,6 +503,8 @@
mock_tcp_port = #{mockTcpPort,jdbcType=INTEGER},
is_mock_tcp_open = #{isMockTcpOpen,jdbcType=BIT},
azure_filter_id = #{azureFilterId,jdbcType=VARCHAR},
api_quick = #{apiQuick,jdbcType=VARCHAR},
case_public = #{casePublic,jdbcType=BIT},
platform = #{platform,jdbcType=VARCHAR},
third_part_template = #{thirdPartTemplate,jdbcType=BIT}
where id = #{id,jdbcType=VARCHAR}

View File

@ -29,6 +29,7 @@
<result column="delete_time" jdbcType="BIGINT" property="deleteTime" />
<result column="delete_user_id" jdbcType="VARCHAR" property="deleteUserId" />
<result column="order" jdbcType="BIGINT" property="order" />
<result column="case_public" jdbcType="BIT" property="casePublic"/>
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.TestCaseWithBLOBs">
<result column="prerequisite" jdbcType="LONGVARCHAR" property="prerequisite" />
@ -97,10 +98,11 @@
</where>
</sql>
<sql id="Base_Column_List">
id, node_id, node_path, project_id, `name`, `type`, maintainer, priority, `method`,
id
, node_id, node_path, project_id, `name`, `type`, maintainer, priority, `method`,
create_time, update_time, test_id, sort, num, other_test_name, review_status, tags,
demand_id, demand_name, `status`, custom_num, step_model, create_user, original_status,
delete_time, delete_user_id, `order`
delete_time, delete_user_id, `order`, case_public
</sql>
<sql id="Blob_Column_List">
prerequisite, remark, steps, step_description, expected_result, custom_fields
@ -163,8 +165,8 @@
demand_name, `status`, custom_num,
step_model, create_user, original_status,
delete_time, delete_user_id, `order`,
prerequisite, remark, steps,
step_description, expected_result,
case_public, prerequisite, remark,
steps, step_description, expected_result,
custom_fields)
values (#{id,jdbcType=VARCHAR}, #{nodeId,jdbcType=VARCHAR}, #{nodePath,jdbcType=VARCHAR},
#{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR},
@ -175,8 +177,9 @@
#{demandName,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, #{customNum,jdbcType=VARCHAR},
#{stepModel,jdbcType=VARCHAR}, #{createUser,jdbcType=VARCHAR}, #{originalStatus,jdbcType=VARCHAR},
#{deleteTime,jdbcType=BIGINT}, #{deleteUserId,jdbcType=VARCHAR}, #{order,jdbcType=BIGINT},
#{prerequisite,jdbcType=LONGVARCHAR}, #{remark,jdbcType=LONGVARCHAR}, #{steps,jdbcType=LONGVARCHAR},
#{stepDescription,jdbcType=LONGVARCHAR}, #{expectedResult,jdbcType=LONGVARCHAR},
#{casePublic,jdbcType=BIT}, #{prerequisite,jdbcType=LONGVARCHAR}, #{remark,jdbcType=LONGVARCHAR},
#{steps,jdbcType=LONGVARCHAR}, #{stepDescription,jdbcType=LONGVARCHAR},
#{expectedResult,jdbcType=LONGVARCHAR},
#{customFields,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestCaseWithBLOBs">
@ -263,6 +266,9 @@
<if test="order != null">
`order`,
</if>
<if test="casePublic != null">
case_public,
</if>
<if test="prerequisite != null">
prerequisite,
</if>
@ -364,6 +370,9 @@
<if test="order != null">
#{order,jdbcType=BIGINT},
</if>
<if test="casePublic != null">
#{casePublic,jdbcType=BIT},
</if>
<if test="prerequisite != null">
#{prerequisite,jdbcType=LONGVARCHAR},
</if>
@ -474,6 +483,9 @@
<if test="record.order != null">
`order` = #{record.order,jdbcType=BIGINT},
</if>
<if test="record.casePublic != null">
case_public = #{record.casePublic,jdbcType=BIT},
</if>
<if test="record.prerequisite != null">
prerequisite = #{record.prerequisite,jdbcType=LONGVARCHAR},
</if>
@ -526,6 +538,7 @@
delete_time = #{record.deleteTime,jdbcType=BIGINT},
delete_user_id = #{record.deleteUserId,jdbcType=VARCHAR},
`order` = #{record.order,jdbcType=BIGINT},
case_public = #{record.casePublic,jdbcType=BIT},
prerequisite = #{record.prerequisite,jdbcType=LONGVARCHAR},
remark = #{record.remark,jdbcType=LONGVARCHAR},
steps = #{record.steps,jdbcType=LONGVARCHAR},
@ -564,7 +577,8 @@
original_status = #{record.originalStatus,jdbcType=VARCHAR},
delete_time = #{record.deleteTime,jdbcType=BIGINT},
delete_user_id = #{record.deleteUserId,jdbcType=VARCHAR},
`order` = #{record.order,jdbcType=BIGINT}
`order` = #{record.order,jdbcType=BIGINT},
case_public = #{record.casePublic,jdbcType=BIT}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause"/>
</if>
@ -650,6 +664,9 @@
<if test="order != null">
`order` = #{order,jdbcType=BIGINT},
</if>
<if test="casePublic != null">
case_public = #{casePublic,jdbcType=BIT},
</if>
<if test="prerequisite != null">
prerequisite = #{prerequisite,jdbcType=LONGVARCHAR},
</if>
@ -699,6 +716,7 @@
delete_time = #{deleteTime,jdbcType=BIGINT},
delete_user_id = #{deleteUserId,jdbcType=VARCHAR},
`order` = #{order,jdbcType=BIGINT},
case_public = #{casePublic,jdbcType=BIT},
prerequisite = #{prerequisite,jdbcType=LONGVARCHAR},
remark = #{remark,jdbcType=LONGVARCHAR},
steps = #{steps,jdbcType=LONGVARCHAR},
@ -734,7 +752,8 @@
original_status = #{originalStatus,jdbcType=VARCHAR},
delete_time = #{deleteTime,jdbcType=BIGINT},
delete_user_id = #{deleteUserId,jdbcType=VARCHAR},
`order` = #{order,jdbcType=BIGINT}
`order` = #{order,jdbcType=BIGINT},
case_public = #{casePublic,jdbcType=BIT}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -20,6 +20,8 @@ public interface ExtTestCaseMapper {
List<TestCaseDTO> list(@Param("request") QueryTestCaseRequest request);
List<TestCaseDTO> publicList(@Param("request") QueryTestCaseRequest request);
int moduleCount(@Param("request") QueryTestCaseRequest request);
List<TestCaseDTO> listIds(@Param("request") QueryTestCaseRequest request);
@ -104,6 +106,9 @@ public interface ExtTestCaseMapper {
List<TestCaseWithBLOBs> getCustomFieldsByIds(@Param("ids") List<String> ids);
int deleteToGc(@Param("request") TestCase testCase);
int deletePublic(@Param("request") TestCase testCase);
int reduction(@Param("ids") List<String> ids);
void checkOriginalStatusByIds(@Param("ids") List<String> ids);
@ -127,4 +132,6 @@ public interface ExtTestCaseMapper {
int countByIds(@Param("ids") List<String> ids);
String getLastExecStatusById(String id);
int countByWorkSpaceId(String workSpaceId);
}

View File

@ -188,6 +188,85 @@
<include refid="queryWhereCondition"/>
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/>
</select>
<select id="publicList" resultType="io.metersphere.track.dto.TestCaseDTO">
select
deleteUser.name AS delete_user_id,test_case.delete_time,
<if test="request.selectFields != null and request.selectFields.size() > 0">
<foreach collection="request.selectFields" item="field" separator=",">
${field}
</foreach>
</if>
<if test="request.selectFields == null or request.selectFields.size() == 0">
test_case.id, test_case.node_id, test_case.node_path, test_case.project_id, test_case.`name`,
test_case.`type`, test_case.maintainer, test_case.priority, test_case.`method`,
test_case.create_time, test_case.update_time, test_case.test_id, test_case.sort, test_case.num,
test_case.other_test_name, test_case.review_status, test_case.tags,
test_case.demand_id, test_case.demand_name, test_case.`status`,
test_case.custom_num, test_case.step_model, test_case.create_user,u.name as createName,
test_case.custom_fields,test_case.case_public , project.name as projectName
</if>
from test_case left join user u on test_case.create_user=u.id
left join user deleteUser on test_case.delete_user_id=deleteUser.id
left join project on test_case.project_id = project.id
<where>
<include refid="filters"/>
<if test="request.combine != null">
<include refid="combine">
<property name="condition" value="request.combine"/>
<property name="name" value="request.name"/>
<property name="objectKey" value="request.combine.tags"/>
</include>
</if>
<if test="request.statusIsNot != null">
and (test_case.status is null or test_case.status != #{request.statusIsNot})
</if>
<if test="request.notEqStatus != null">
and (test_case.status is null or test_case.status != #{request.notEqStatus})
</if>
<if test="request.name != null">
and (test_case.name like CONCAT('%', #{request.name},'%')
or test_case.num like CONCAT('%', #{request.name},'%')
or test_case.tags like CONCAT('%', #{request.name},'%')
or test_case.custom_num like CONCAT('%', #{request.name},'%'))
</if>
<if test="request.ids != null">
and test_case.id in
<foreach collection="request.ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</if>
<if test="request.relevanceCreateTime >0">
and test_case.id in (select test_case_id from test_case_test where test_case_test.create_time >=
#{request.createTime})
</if>
<if test="request.createTime >0">
and test_case.create_time >= #{request.createTime}
</if>
<if test="request.nodeIds != null and request.nodeIds.size() > 0">
and test_case.node_id in
<foreach collection="request.nodeIds" item="nodeId" separator="," open="(" close=")">
#{nodeId}
</foreach>
</if>
<if test="request.workspaceId != null">
AND test_case.project_id in (select id from project where workspace_id=#{request.workspaceId})
</if>
and test_case.case_public = TRUE
<include refid="filters"/>
<if test="request.caseCoverage == 'uncoverage' ">
and test_case.id not in (select distinct test_case_test.test_case_id from test_case_test)
</if>
<if test="request.caseCoverage == 'coverage' ">
and test_case.id in (select distinct test_case_test.test_case_id from test_case_test)
</if>
</where>
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/>
</select>
<select id="moduleCount" resultType="java.lang.Integer">
select count(test_case.id) from test_case
left join project on test_case.project_id = project.id
@ -594,12 +673,20 @@
</select>
<update id="deleteToGc">
update test_case set original_status=status,
update test_case
set original_status=status,
status = 'Trash',
delete_time = #{request.deleteTime},
delete_user_id = #{request.deleteUserId}
where id = #{request.id}
</update>
<update id="deletePublic">
update test_case
set case_public = false
where id = #{request.id}
</update>
<update id="reduction">
update test_case
set
@ -622,7 +709,21 @@
</update>
<select id="getLastExecStatusById" resultType="java.lang.String">
SELECT `status` FROM test_plan_test_case WHERE case_id = #{0} ORDER BY update_time DESC limit 1 ;
SELECT `status`
FROM test_plan_test_case
WHERE case_id = #{0}
ORDER BY update_time DESC limit 1;
</select>
<select id="countByWorkSpaceId" resultType="java.lang.Integer">
select count(id)
from test_case
where project_id in (
select id
from project
where workspace_id = #{workSpaceId})
and case_public = true
and status != 'Trash'
</select>
</mapper>

View File

@ -65,6 +65,13 @@ public class TestCaseController {
return PageUtils.setPageInfo(page, testCaseService.listTestCase(request));
}
@PostMapping("/publicList/{goPage}/{pageSize}")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_CASE_READ)
public Pager<List<TestCaseDTO>> publicList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestCaseRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, testCaseService.publicListTestCase(request));
}
@GetMapping("/list/{projectId}")
@RequiresPermissions("PROJECT_TRACK_CASE:READ")
public List<TestCaseDTO> list(@PathVariable String projectId) {
@ -238,6 +245,15 @@ public class TestCaseController {
return testCaseService.deleteTestCaseToGc(testCaseId);
}
@PostMapping("/deletePublic/{testCaseId}")
@MsAuditLog(module = "track_test_case", type = OperLogConstants.GC, beforeEvent = "#msClass.getLogDetails(#testCaseId)", msClass = TestCaseService.class)
@SendNotice(taskType = NoticeConstants.TaskType.TRACK_TEST_CASE_TASK, event = NoticeConstants.Event.DELETE, target = "#targetClass.getTestCase(#testCaseId)", targetClass = TestCaseService.class,
mailTemplate = "track/TestCaseDelete", subject = "测试用例通知")
public int deletePublic(@PathVariable String testCaseId) {
checkPermissionService.checkTestCaseOwner(testCaseId);
return testCaseService.deleteTestCasePublic(testCaseId);
}
@PostMapping("/import/{projectId}/{userId}/{importType}")
@MsAuditLog(module = "track_test_case", type = OperLogConstants.IMPORT, project = "#projectId")
@ -285,18 +301,32 @@ public class TestCaseController {
@SendNotice(taskType = NoticeConstants.TaskType.TRACK_TEST_CASE_TASK, target = "#targetClass.findByBatchRequest(#request)", targetClass = TestCaseService.class,
event = NoticeConstants.Event.UPDATE, mailTemplate = "track/TestCaseUpdate", subject = "测试用例通知")
public void editTestCaseBath(@RequestBody TestCaseBatchRequest request) {
List<String> ids = request.getIds();
for (String id : ids) {
checkPermissionService.checkTestCaseOwner(id);
}
testCaseService.editTestCaseBath(request);
}
@PostMapping("/batch/copy")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_CASE_READ_EDIT)
@MsAuditLog(module = "track_test_case", type = OperLogConstants.BATCH_ADD, beforeEvent = "#msClass.getLogDetails(#request.ids)", content = "#msClass.getLogDetails(#request.ids)", msClass = TestCaseService.class)
@MsAuditLog(module = "track_test_case", type = OperLogConstants.BATCH_UPDATE, beforeEvent = "#msClass.getLogDetails(#request.ids)", content = "#msClass.getLogDetails(#request.ids)", msClass = TestCaseService.class)
@SendNotice(taskType = NoticeConstants.TaskType.TRACK_TEST_CASE_TASK, target = "#targetClass.findByBatchRequest(#request)", targetClass = TestCaseService.class,
event = NoticeConstants.Event.CREATE, mailTemplate = "track/TestCaseUpdate", subject = "测试用例通知")
public void copyTestCaseBath(@RequestBody TestCaseBatchRequest request) {
testCaseService.copyTestCaseBath(request);
}
@PostMapping("/batch/copy/public")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_CASE_READ_EDIT)
@MsAuditLog(module = "track_test_case", type = OperLogConstants.BATCH_ADD, beforeEvent = "#msClass.getLogDetails(#request.ids)", content = "#msClass.getLogDetails(#request.ids)", msClass = TestCaseService.class)
@SendNotice(taskType = NoticeConstants.TaskType.TRACK_TEST_CASE_TASK, target = "#targetClass.findByBatchRequest(#request)", targetClass = TestCaseService.class,
event = NoticeConstants.Event.CREATE, mailTemplate = "track/TestCaseUpdate", subject = "测试用例通知")
public void copyTestCaseBathPublic(@RequestBody TestCaseBatchRequest request) {
testCaseService.copyTestCaseBathPublic(request);
}
@PostMapping("/batch/delete")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_CASE_READ_DELETE)
@MsAuditLog(module = "track_test_case", type = OperLogConstants.BATCH_DEL, beforeEvent = "#msClass.getLogDetails(#request.ids)", msClass = TestCaseService.class)

View File

@ -35,6 +35,11 @@ public class TestCaseNodeController {
return testCaseNodeService.trashCount(projectId);
}
@GetMapping("/publicCount/{workSpaceId}")
public long publicCount(@PathVariable String workSpaceId) {
return testCaseNodeService.publicCount(workSpaceId);
}
/*模块列表列表*/
@PostMapping("/list/all/plan")
public List<TestCaseNodeDTO> getAllNodeByPlanId(@RequestBody QueryNodeRequest request) {

View File

@ -57,4 +57,5 @@ public class QueryTestCaseRequest extends BaseQueryRequest {
private String operator;
//操作时间
private Long operationTime;
private boolean casePublic;
}

View File

@ -803,4 +803,9 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
}
}
}
public long publicCount(String workSpaceId) {
return extTestCaseMapper.countByWorkSpaceId(workSpaceId);
}
}

View File

@ -375,6 +375,12 @@ public class TestCaseService {
return extTestCaseMapper.deleteToGc(testCase);
}
public int deleteTestCasePublic(String testCaseId) {
TestCase testCase = new TestCase();
testCase.setId(testCaseId);
return extTestCaseMapper.deletePublic(testCase);
}
public List<TestCaseDTO> listTestCase(QueryTestCaseRequest request) {
this.initRequest(request, true);
setDefaultOrder(request);
@ -385,6 +391,18 @@ public class TestCaseService {
returnList = this.parseStatus(returnList);
return returnList;
}
public List<TestCaseDTO> publicListTestCase(QueryTestCaseRequest request) {
this.initRequest(request, true);
setDefaultOrder(request);
if (request.getFilters() != null && !request.getFilters().containsKey("status")) {
request.getFilters().put("status", new ArrayList<>(0));
}
List<TestCaseDTO> returnList = extTestCaseMapper.publicList(request);
returnList = this.parseStatus(returnList);
return returnList;
}
public void setDefaultOrder(QueryTestCaseRequest request) {
List<OrderRequest> orders = ServiceUtils.getDefaultSortOrder(request.getOrders());
OrderRequest order = new OrderRequest();
@ -1304,6 +1322,40 @@ public class TestCaseService {
}
}
public void copyTestCaseBathPublic(TestCaseBatchRequest request) {
ServiceUtils.getSelectAllIds(request, request.getCondition(),
(query) -> extTestCaseMapper.selectIds(query));
List<String> ids = request.getIds();
if (CollectionUtils.isEmpty(ids)) {
return;
}
TestCaseExample exampleList = new TestCaseExample();
exampleList.createCriteria().andIdIn(request.getIds());
List<TestCaseWithBLOBs> list = testCaseMapper.selectByExampleWithBLOBs(exampleList);
for (TestCaseWithBLOBs item : list) {
TestCaseWithBLOBs batchCopy = new TestCaseWithBLOBs();
BeanUtils.copyBean(batchCopy, item);
checkTestCaseExist(batchCopy);
batchCopy.setId(UUID.randomUUID().toString());
batchCopy.setCreateTime(System.currentTimeMillis());
batchCopy.setUpdateTime(System.currentTimeMillis());
checkTestCustomNum(batchCopy);
batchCopy.setNum(getNextNum(SessionUtils.getCurrentProjectId()));
if (StringUtils.isBlank(batchCopy.getCustomNum())) {
batchCopy.setCustomNum(batchCopy.getNum().toString());
}
batchCopy.setCreateUser(SessionUtils.getUserId());
batchCopy.setMaintainer(SessionUtils.getUserId());
batchCopy.setReviewStatus(TestCaseReviewStatus.Prepare.name());
batchCopy.setStatus(TestCaseReviewStatus.Prepare.name());
batchCopy.setNodePath(request.getNodePath());
batchCopy.setNodeId(request.getNodeId());
batchCopy.setProjectId(SessionUtils.getCurrentProjectId());
batchCopy.setCasePublic(false);
testCaseMapper.insert(batchCopy);
}
}
public void deleteTestCaseBath(TestCaseBatchRequest request) {
TestCaseExample example = this.getBatchExample(request);
deleteTestPlanTestCaseBath(request.getIds());

View File

@ -1,11 +1,28 @@
-- 新增字段
ALTER TABLE `swagger_url_project` ADD COLUMN `config` longtext COMMENT '鉴权配置信息' AFTER `mode_id`;
ALTER TABLE `swagger_url_project`
ADD COLUMN `config` longtext COMMENT '鉴权配置信息' AFTER `mode_id`;
-- 第三方平台模板
ALTER TABLE project ADD platform varchar(20) DEFAULT 'Local' NOT NULL COMMENT '项目使用哪个平台的模板';
ALTER TABLE project ADD third_part_template tinyint(1) DEFAULT 0 NULL COMMENT '是否使用第三方平台缺陷模板';
ALTER TABLE project
ADD platform varchar(20) DEFAULT 'Local' NOT NULL COMMENT '项目使用哪个平台的模板';
ALTER TABLE project
ADD third_part_template tinyint(1) DEFAULT 0 NULL COMMENT '是否使用第三方平台缺陷模板';
-- 处理历史数据
UPDATE issue_template SET platform = 'Local' WHERE platform = 'metersphere';
UPDATE project p JOIN issue_template it on p.issue_template_id = it.id SET p.platform = it.platform;
UPDATE custom_field SET `type` = 'date' WHERE `type` = 'data';
UPDATE issue_template
SET platform = 'Local'
WHERE platform = 'metersphere';
UPDATE project p JOIN issue_template it
on p.issue_template_id = it.id SET p.platform = it.platform;
UPDATE custom_field
SET `type` = 'date'
WHERE `type` = 'data';
-- 公共用例库
ALTER TABLE project
ADD case_public tinyint(1) DEFAULT NULL COMMENT '是否开启用例公共库';
ALTER TABLE project
ADD api_quick varchar(50) DEFAULT NULL COMMENT 'api定义快捷调试按钮',
ALTER TABLE test_case
ADD case_public tinyint(1) DEFAULT NULL COMMENT '是否是公共用例';

View File

@ -71,8 +71,8 @@
<!--<table tableName="test_plan"/>-->
<!--<table tableName="api_scenario_report"/>-->
<!--<table tableName="test_case_review"/>-->
<table tableName="enterprise_test_report"/>
<table tableName="enterprise_test_report_send_record"/>
<table tableName="test_case"/>
<!--<table tableName="enterprise_test_report_send_record"/>-->
<!--<table tableName="test_case_review_api_case"/>
<table tableName="test_case_review_load"/>
<table tableName="test_case_review_scenario"/>
@ -94,7 +94,6 @@
<table tableName="api_definition"></table>-->
<!-- 表名和关键字冲突-->
<!-- <table tableName="group" delimitIdentifiers="true"></table>-->

View File

@ -464,7 +464,15 @@ export default {
},
addTab(tab) {
if (tab.name === 'add') {
this.result = this.$get('/project/get/' + this.projectId, res => {
let projectData = res.data;
if (projectData && projectData.apiQuick === 'api') {
this.handleTabAdd("ADD");
} else {
this.handleTabsEdit(this.$t('api_test.definition.request.fast_debug'), "debug");
}
})
} else if (tab.name === 'trash') {
if (this.$refs.trashApiList) {
this.$refs.trashApiList.initTable();

View File

@ -0,0 +1,66 @@
<template>
<div @click="exe" class="recycle" :class="{'is-active': condition.publicEnable}" v-if="this.isXpack">
<el-row>
<el-col :span="21"><i class="el-icon-reading"> {{ $t('project.case_public') }}</i></el-col>
<el-col :span="3"><span style="color: #6C317C">{{ publicTotal }}</span></el-col>
</el-row>
</div>
</template>
<script>
import {hasLicense} from "@/common/js/utils";
export default {
name: "ModulePublicButton",
props: {
condition: {
type: Object,
default() {
return {};
}
},
exe: {
type: Function
},
publicTotal: Number,
},
data() {
return {
isXPack: false
}
},
created() {
if (hasLicense()) {
this.isXpack = true;
} else {
this.isXpack = false;
}
},
methods: {
// enableTrash() {
//
// }
}
}
</script>
<style scoped>
.recycle {
padding-left: 25px;
margin-top: 15px;
height: 26px;
line-height: 26px;
margin-bottom: -10px;
}
.recycle:hover {
color: #6d317c;
cursor: pointer;
}
.is-active {
background-color: #f3f6f9;
}
</style>

View File

@ -33,7 +33,7 @@
<el-menu-item popper-class="submenu" @click="clickPlanMenu">
{{ $t('project.version_manage') }}
</el-menu-item>
<el-menu-item popper-class="submenu" @click="clickPlanMenu">
<el-menu-item :index="'/project/app'" popper-class="submenu" :disabled="this.isProjectAdmin">
{{ $t('project.app_manage') }}
</el-menu-item>
</el-menu>
@ -48,6 +48,7 @@ import MsShowAll from "@/business/components/common/head/ShowAll";
import MsRecentList from "@/business/components/common/head/RecentList";
import MsCreateButton from "@/business/components/common/head/CreateButton";
import ProjectChange from "@/business/components/common/head/ProjectSwitch";
import {getCurrentProjectID, getCurrentUserId, getCurrentWorkspaceId} from "@/common/js/utils";
export default {
name: "ProjectHeaderMenus",
@ -56,6 +57,7 @@ export default {
return {
currentProject: '',
pathName: '',
isProjectAdmin: true
};
},
watch: {
@ -66,11 +68,25 @@ export default {
}
}
},
created() {
this.$get("/user/group/list/project/" + getCurrentProjectID() + "/" + getCurrentUserId(), res => {
let data = res.data;
if (data) {
data.forEach(row => {
if (row.id === 'project_admin') {
this.isProjectAdmin = false;
}
})
} else {
this.isProjectAdmin = true;
}
})
},
methods: {
clickPlanMenu() {
this.$info(this.$t('commons.function_planning'));
return false;
}
},
}
};

View File

@ -0,0 +1,176 @@
<template>
<ms-container>
<ms-main-container>
<div v-loading="result.loading">
<el-card class="card">
<el-col :span="24" justify="space-around">
<el-tabs v-model="activeName" @tab-click="handleClick" style="height: 600px">
<el-tab-pane :label="$t('commons.my_workstation')" name="my_workstation" :disabled="true">
{{ this.$t('commons.my_workstation') }}
</el-tab-pane>
<el-tab-pane :label="$t('test_track.test_track')" name="test_track">
<div>
<el-col :span="8">
<el-row style="margin-top: 10px">
<span>{{ this.$t('commons.enable_settings') }}</span>
</el-row>
<el-row style="margin-top: 10px">
<fieldset>
<el-form :model="form" ref="form" label-position="left" label-width="200px" size="small">
<el-form-item :label-width="labelWidth" :label="$t('project.public_info')" prop="casePublic"
v-if="this.isXpack">
<el-switch v-model="form.casePublic" style="margin-top:20px"></el-switch>
</el-form-item>
<el-divider v-if="this.isXpack"></el-divider>
<el-form-item :label-width="labelWidth" :label="$t('project.test_case_custom_id_info')"
prop="repeatable">
<el-switch v-model="form.repeatable" style="margin-top:20px"></el-switch>
</el-form-item>
</el-form>
</fieldset>
</el-row>
</el-col>
</div>
</el-tab-pane>
<el-tab-pane :label="$t('commons.api')" name="api">
<el-row :gutter="20">
<el-col :span="8">
<el-row style="margin-top: 10px">
<span>{{ this.$t('commons.enable_settings') }}</span>
</el-row>
<el-row style="margin-top: 10px">
<fieldset>
<el-form :model="form" ref="form" label-position="left" label-width="200px" size="small">
<el-form-item :label-width="labelWidth" :label="$t('project.repeatable_info')"
prop="customNum">
<el-switch v-model="form.customNum" style="margin-top:20px"></el-switch>
</el-form-item>
<el-divider></el-divider>
<el-form-item :label-width="labelWidth" :label="$t('project.scenario_custom_id_info')"
prop="scenarioCustomNum">
<el-switch v-model="form.scenarioCustomNum" style="margin-top:20px"></el-switch>
</el-form-item>
</el-form>
</fieldset>
</el-row>
</el-col>
<el-col :span="8" :offset="4">
<el-row style="margin-top: 10px">
<span>{{ this.$t('commons.view_settings') }}</span>
</el-row>
<el-row style="margin-top: 10px">
<fieldset>
<el-form :model="form" ref="form" label-position="left" label-width="200px" size="small">
<el-form-item label-width="200px" :label="$t('api_test.definition.api_quick_button')"
prop="apiQuick">
<el-radio-group v-model="form.apiQuick">
<el-radio label="debug" value="debug">
{{ this.$t('api_test.definition.request.fast_debug') }}
</el-radio>
<el-radio label="api" value="api">
{{ this.$t('api_test.definition.request.title') }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</fieldset>
</el-row>
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane :label="$t('commons.performance')" name="performance" :disabled="true">{{
this.$t('commons.performance')
}}
</el-tab-pane>
</el-tabs>
</el-col>
</el-card>
</div>
</ms-main-container>
</ms-container>
</template>
<script>
import MsContainer from "@/business/components/common/components/MsContainer";
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
import {
getCurrentProjectID,
getCurrentUser,
getCurrentUserId,
getCurrentWorkspaceId,
getUUID, hasLicense,
hasPermission
} from "@/common/js/utils";
export default {
name: "appManage",
components: {
MsMainContainer,
MsContainer
},
data() {
return {
activeName: 'test_track',
form: {},
labelWidth: '400px',
count: 0,
isXpack: false,
result: {}
};
},
created() {
this.result = this.$get('/project/get/' + this.projectId, res => {
this.form = res.data;
this.count = 0
})
if (hasLicense()) {
this.isXpack = true;
} else {
this.isXpack = false;
}
},
watch: {
form: {
handler(val, oldVal) {
this.count++;
if (this.count > 1) {
this.submitForm();
}
},
deep: true
}
},
computed: {
projectId() {
return getCurrentProjectID();
},
},
methods: {
handleClick() {
},
submitForm() {
this.form.workspaceId = getCurrentWorkspaceId();
this.form.createUser = getCurrentUserId();
this.form.id = getCurrentProjectID();
this.result = this.$post("/project/update", this.form, () => {
this.$success(this.$t('commons.save_success'));
});
},
}
};
</script>
<style scoped>
/deep/ .el-form-item__label {
white-space: pre-line;
}
</style>

View File

@ -6,6 +6,8 @@ const ProjectLog = () => import('@/business/components/project/menu/Log')
const ProjectCodeSegment = () => import('@/business/components/project/menu/function/CustomFunction')
const ProjectFileManage = () => import('@/business/components/project/menu/file/FileManage')
const ProjectUserGroup = () => import('@/business/components/project/menu/UserGroup')
const ProjectAppManage = () => import('@/business/components/project/menu/appmanage/AppManage')
export default {
path: "/project",
@ -47,7 +49,11 @@ export default {
{
path: 'file/manage',
component: ProjectFileManage
}
},
{
path: 'app',
component: ProjectAppManage
},
]
};

View File

@ -12,8 +12,10 @@
@createCase="handleCaseSimpleCreate($event, 'add')"
@refreshAll="refreshAll"
@enableTrash="enableTrash"
@enablePublic="enablePublic"
:type="'edit'"
:total='total'
:public-total="publicTotal"
ref="nodeTree"
/>
</ms-aside-container>
@ -31,12 +33,32 @@
@testCaseCopy="copyTestCase"
@testCaseDetail="showTestCaseDetail"
@getTrashList="getTrashList"
@getPublicList="getPublicList"
@refresh="refresh"
@refreshAll="refreshAll"
@setCondition="setCondition"
ref="testCaseTrashList">
</test-case-list>
</el-tab-pane>
<el-tab-pane name="public" v-if="publicEnable" :label="$t('project.case_public')">
<test-case-list
:checkRedirectID="checkRedirectID"
:isRedirectEdit="isRedirectEdit"
:tree-nodes="treeNodes"
:trash-enable="false"
:public-enable="true"
@refreshTable="refresh"
@testCaseEdit="editTestCase"
@testCaseCopy="copyTestCase"
@testCaseDetail="showTestCaseDetail"
@getTrashList="getTrashList"
@getPublicList="getPublicList"
@refresh="refresh"
@refreshAll="refreshAll"
@setCondition="setCondition"
ref="testCasePublicList">
</test-case-list>
</el-tab-pane>
<el-tab-pane name="default" :label="$t('api_test.definition.case_title')">
<ms-tab-button
:active-dom="activeDom"
@ -57,6 +79,7 @@
@testCaseCopy="copyTestCase"
@testCaseDetail="showTestCaseDetail"
@getTrashList="getTrashList"
@getPublicList="getPublicList"
@refresh="refresh"
@refreshAll="refreshAll"
@setCondition="setCondition"
@ -132,7 +155,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 {getCurrentProjectID, getUUID, hasPermission, setCurTabId} from "@/common/js/utils";
import {getCurrentProjectID, getCurrentWorkspaceId, getUUID, hasPermission, setCurTabId} from "@/common/js/utils";
import TestCaseNodeTree from "../common/TestCaseNodeTree";
import MsTabButton from "@/business/components/common/components/MsTabButton";
@ -158,6 +181,7 @@ export default {
treeNodes: [],
testCaseReadOnly: true,
trashEnable: false,
publicEnable: false,
condition: {},
activeName: 'default',
tabs: [],
@ -167,6 +191,7 @@ export default {
activeDom: 'left',
tmpActiveDom: null,
total: 0,
publicTotal: 0,
tmpPath: null
};
},
@ -216,6 +241,13 @@ export default {
} else {
this.activeName = 'default';
}
},
publicEnable() {
if (this.publicEnable) {
this.activeName = 'public';
} else {
this.activeName = 'default';
}
}
},
computed: {
@ -262,6 +294,11 @@ export default {
this.total = response.data;
});
},
getPublicList() {
this.$get("/case/node/publicCount/" + getCurrentWorkspaceId(), response => {
this.publicTotal = response.data;
});
},
updateActiveDom(activeDom) {
openMinderConfirm(this, activeDom);
},
@ -386,6 +423,8 @@ export default {
nodeChange(node) {
this.condition.trashEnable = false;
this.trashEnable = false;
this.condition.publicEnable = false;
this.publicEnable = false;
this.activeName = "default";
},
refreshTable(data) {
@ -502,6 +541,10 @@ export default {
this.initApiTableOpretion = "trashEnable";
this.trashEnable = data;
},
enablePublic(data) {
this.initApiTableOpretion = "publicEnable";
this.publicEnable = data;
},
}
};
</script>

View File

@ -58,6 +58,12 @@
result: {},
}
},
props: {
publicEnable: {
type: Boolean,
default: false,
},
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
@ -85,7 +91,11 @@
});
}
param.ids = this.selectIds;
if (this.publicEnable) {
this.$emit('copyPublic', param);
} else {
this.$emit('moveSave', param);
}
},
refresh() {
this.$emit("refresh");

View File

@ -52,6 +52,14 @@ import {hasLicense, hasPermissions} from "@/common/js/utils";
}
},
isDisable(item) {
if (item.isDisable) {
if (item.isDisable instanceof Function) {
console.log(item.isDisable());
return item.isDisable();
} else {
return item.isDisable;
}
}
if (item.permissions && item.permissions.length > 0) {
return !hasPermissions(...item.permissions);
}

View File

@ -34,6 +34,10 @@
$t('test_track.case.save_create_continue')
}}
</el-dropdown-item>
<el-dropdown-item command="ADD_AND_PUBLIC" v-if="this.publicEnable && this.isXpack">{{
$t('test_track.case.save_add_public')
}}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
@ -142,7 +146,7 @@ import {
getCurrentProjectID,
getCurrentUser,
getNodePath, getUUID,
handleCtrlSEvent, hasPermission,
handleCtrlSEvent, hasLicense, hasPermission,
listenGoBack,
removeGoBackListener
} from "@/common/js/utils";
@ -194,6 +198,8 @@ export default {
return {
// sysList: [],//
path: "/test/case/add",
publicEnable: false,
isXpack: false,
testCaseTemplate: {},
options: REVIEW_STATUS,
statuOptions: API_STATUS,
@ -391,7 +397,18 @@ export default {
break;
}
}
}),
this.result = this.$get('/project/get/' + this.projectId, res => {
let data = res.data;
if (data.casePublic) {
this.publicEnable = true;
}
})
if (hasLicense()) {
this.isXpack = true;
} else {
this.isXpack = false;
}
},
methods: {
currentUser: () => {
@ -462,6 +479,9 @@ export default {
});
}
})
} else if (e === 'ADD_AND_PUBLIC') {
this.form.casePublic = true;
this.saveCase();
} else {
this.saveCase();
}
@ -562,6 +582,7 @@ export default {
this.getTestCase(this.index);
},
initTestCases(testCase) {
this.selectCondition.workspaceId = null;
this.result = this.$post('/test/case/list/ids', this.selectCondition, response => {
this.testCases = response.data;
for (let i = 0; i < this.testCases.length; i++) {

View File

@ -129,11 +129,21 @@
</template>
</ms-table-column>
<ms-table-column
prop="projectName"
:field="item"
:fields-width="fieldsWidth"
:label="$t('test_track.case.project')"
v-if="publicEnable"
min-width="150px">
</ms-table-column>
<ms-table-column
prop="nodePath"
:field="item"
:fields-width="fieldsWidth"
:label="$t('test_track.case.module')"
v-if="!publicEnable"
min-width="150px">
</ms-table-column>
@ -192,7 +202,8 @@
<batch-edit ref="batchEdit" @batchEdit="batchEdit"
:typeArr="typeArr" :value-arr="valueArr" :dialog-title="$t('test_track.case.batch_edit_case')"/>
<batch-move @refresh="refresh" @moveSave="moveSave" ref="testBatchMove"/>
<batch-move @refresh="refresh" @moveSave="moveSave" ref="testBatchMove" :public-enable="publicEnable"
@copyPublic="copyPublic"/>
<test-case-preview ref="testCasePreview" :loading="rowCaseResult.loading"/>
@ -235,7 +246,7 @@ import {
} from "@/common/js/tableUtils";
import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate";
import PlanStatusTableItem from "@/business/components/track/common/tableItems/plan/PlanStatusTableItem";
import {getCurrentProjectID} from "@/common/js/utils";
import {getCurrentProjectID, getCurrentUserId, getCurrentWorkspaceId} from "@/common/js/utils";
import {getTestTemplate} from "@/network/custom-field-template";
import {getProjectMember} from "@/network/user";
import MsTable from "@/business/components/common/components/table/MsTable";
@ -279,6 +290,7 @@ export default {
},
data() {
return {
addPublic: false,
projectName: "",
type: TEST_CASE_LIST,
tableHeaderKey: "TRACK_TEST_CASE",
@ -340,12 +352,29 @@ export default {
permissions: ['PROJECT_TRACK_CASE:READ+DELETE']
},
{
name: this.$t('生成依赖关系'),
name: this.$t('test_track.case.generate_dependencies'),
isXPack: true,
handleClick: this.generateGraph,
permissions: ['PROJECT_API_DEFINITION:READ+EDIT_API']
},
{
name: this.$t('test_track.case.batch_add_public'),
isXPack: true,
handleClick: this.handleBatchAddPublic,
permissions: ['PROJECT_API_DEFINITION:READ+EDIT_API'],
}
],
publicButtons: [
{
name: this.$t('test_track.case.batch_copy'),
handleClick: this.handleBatchMove,
permissions: ['PROJECT_TRACK_CASE:READ+EDIT']
}, {
name: this.$t('test_track.case.batch_delete_case'),
handleClick: this.handleDeleteBatchToPublic,
permissions: ['PROJECT_TRACK_CASE:READ+DELETE'],
},
],
trashButtons: [
{
name: this.$t('commons.reduction'),
@ -375,6 +404,25 @@ export default {
permissions: ['PROJECT_TRACK_CASE:READ+DELETE']
}
],
publicOperators: [
{
tip: this.$t('commons.edit'), icon: "el-icon-edit",
exec: this.handleEdit,
permissions: ['PROJECT_TRACK_CASE:READ+EDIT'],
isDisable: this.isPublic
},
{
tip: this.$t('commons.copy'), icon: "el-icon-copy-document", type: "success",
exec: this.handleCopyPublic,
permissions: ['PROJECT_TRACK_CASE:READ+COPY']
},
{
tip: this.$t('commons.delete'), icon: "el-icon-delete", type: "danger",
exec: this.handleDeleteToGc,
permissions: ['PROJECT_TRACK_CASE:READ+DELETE'],
isDisable: this.isPublic
}
],
trashOperators: [
{
tip: this.$t('commons.reduction'),
@ -409,6 +457,10 @@ export default {
type: Boolean,
default: false,
},
publicEnable: {
type: Boolean,
default: false,
},
},
computed: {
projectId() {
@ -439,6 +491,9 @@ export default {
if (this.trashEnable) {
this.operators = this.trashOperators;
this.batchButtons = this.trashButtons;
} else if (this.publicEnable) {
this.operators = this.publicOperators;
this.batchButtons = this.publicButtons;
} else {
this.operators = this.simpleOperators;
this.batchButtons = this.simpleButtons;
@ -493,6 +548,21 @@ export default {
this.batchButtons = this.simpleButtons;
this.condition.filters.status = [];
}
},
publicEnable() {
if (this.publicEnable) {
//
this.operators = this.publicOperators;
this.batchButtons = this.publicButtons;
this.condition.moduleIds = [];
initCondition(this.condition, false);
this.initTableData();
} else {
//
this.operators = this.simpleOperators;
this.batchButtons = this.simpleButtons;
this.condition.filters.status = [];
}
}
},
methods: {
@ -580,7 +650,7 @@ export default {
// param.planId = this.planId;
this.condition.planId = this.planId;
}
if (!this.trashEnable) {
if (!this.trashEnable && !this.publicEnable) {
if (this.selectNodeIds && this.selectNodeIds.length > 0) {
// param.nodeIds = this.selectNodeIds;
this.condition.nodeIds = this.selectNodeIds;
@ -625,6 +695,27 @@ export default {
if (this.projectId) {
this.condition.projectId = this.projectId;
this.$emit('setCondition', this.condition);
if (this.publicEnable) {
this.condition.casePublic = true;
this.condition.workspaceId = getCurrentWorkspaceId();
this.page.result = this.$post(this.buildPagePath('/test/case/publicList'), this.condition, response => {
let data = response.data;
this.page.total = data.itemCount;
this.page.data = data.listObject;
this.page.data.forEach(item => {
if (item.customFields) {
item.customFields = JSON.parse(item.customFields);
}
});
this.page.data.forEach((item) => {
try {
item.tags = JSON.parse(item.tags);
} catch (e) {
item.tags = [];
}
});
})
} else {
this.page.result = this.$post(this.buildPagePath('/test/case/list'), this.condition, response => {
let data = response.data;
this.page.total = data.itemCount;
@ -643,7 +734,9 @@ export default {
});
});
}
this.$emit("getTrashList");
this.$emit("getPublicList")
}
},
search() {
@ -664,6 +757,13 @@ export default {
}
},
isPublic(testCase) {
if (testCase.maintainer !== getCurrentUserId() || testCase.createUser !== getCurrentUserId()) {
return true;
} else {
return false;
}
},
getCase(id) {
this.$refs.testCasePreview.open();
this.rowCaseResult.loading = true;
@ -692,6 +792,10 @@ export default {
this.$refs.testCasePreview.setData(this.rowCase);
});
},
handleCopyPublic(testCase) {
this.$refs.table.selectIds.push(testCase.id);
this.$refs.testBatchMove.open(this.treeNodes, this.$refs.table.selectIds, this.moduleOptions);
},
handleCopy(testCase) {
this.$get('test/case/get/' + testCase.id, response => {
let testCase = response.data;
@ -724,9 +828,13 @@ export default {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
if (this.publicEnable) {
this._handleDeletePublic(testCase);
} else {
this._handleDeleteToGc(testCase);
}
}
}
});
},
batchReduction() {
@ -789,6 +897,14 @@ export default {
this.$success(this.$t('commons.delete_success'));
});
},
_handleDeletePublic(testCase) {
let testCaseId = testCase.id;
this.$post('/test/case/deletePublic/' + testCaseId, {}, () => {
this.$emit('refreshTable');
this.initTableData();
this.$success(this.$t('commons.delete_success'));
});
},
refresh() {
this.$refs.table.clear();
this.$emit('refresh');
@ -891,6 +1007,34 @@ export default {
this.getMaintainerOptions();
this.$refs.batchEdit.open(this.$refs.table.selectRows.size);
},
handleBatchAddPublic() {
this.$get('/project/get/' + getCurrentProjectID(), res => {
let data = res.data;
if (data.casePublic) {
let param = {};
param.ids = this.$refs.table.selectIds;
param.casePublic = true;
param.condition = this.condition;
this.page.result = this.$post('/test/case/batch/edit', param, () => {
this.$success(this.$t('commons.save_success'));
this.refresh();
});
} else {
this.$warning(this.$t('test_track.case.public_warning'))
}
})
},
handleDeleteBatchToPublic() {
let param = {};
param.ids = this.$refs.table.selectIds;
param.casePublic = false;
param.condition = this.condition;
this.page.result = this.$post('/test/case/batch/edit', param, () => {
this.$success(this.$t('commons.save_success'));
this.refresh();
});
},
handleBatchMove() {
this.isMoveBatch = true;
this.$refs.testBatchMove.open(this.treeNodes, this.$refs.table.selectIds, this.moduleOptions);
@ -914,6 +1058,14 @@ export default {
this.$refs.testBatchMove.close();
this.refresh();
});
},
copyPublic(param) {
param.condition = this.condition;
this.page.result = this.$post('/test/case/batch/copy/public', param, () => {
this.$success(this.$t('commons.save_success'));
this.$refs.testBatchMove.close();
this.refresh();
});
}
}
};

View File

@ -24,6 +24,7 @@
:condition="condition"
:commands="operators"/>
<module-trash-button :condition="condition" :total="total" :exe="enableTrash"/>
<module-public-button :condition="condition" :public-total="publicTotal" :exe="enablePublic"/>
</template>
</ms-node-tree>
<test-case-import @refreshAll="refreshAll" ref="testCaseImport"/>
@ -49,11 +50,21 @@ import {buildTree} from "../../api/definition/model/NodeTree";
import {buildNodePath} from "@/business/components/api/definition/model/NodeTree";
import {getCurrentProjectID} from "@/common/js/utils";
import ModuleTrashButton from "@/business/components/api/definition/components/module/ModuleTrashButton";
import ModulePublicButton from "@/business/components/api/definition/components/module/ModulePublicButton";
import {getTestCaseNodes} from "@/network/testCase";
export default {
name: "TestCaseNodeTree",
components: {MsSearchBar, TestCaseImport,TestCaseExport, TestCaseCreate, MsNodeTree, NodeEdit,ModuleTrashButton},
components: {
MsSearchBar,
TestCaseImport,
TestCaseExport,
TestCaseCreate,
MsNodeTree,
NodeEdit,
ModuleTrashButton,
ModulePublicButton
},
data() {
return {
defaultProps: {
@ -92,6 +103,7 @@ export default {
},
showOperator: Boolean,
total: Number,
publicTotal: Number,
},
watch: {
treeNodes() {
@ -136,6 +148,10 @@ export default {
this.condition.trashEnable = true;
this.$emit('enableTrash', this.condition.trashEnable);
},
enablePublic() {
this.condition.publicEnable = true;
this.$emit('enablePublic', this.condition.publicEnable);
},
list() {
if (this.projectId) {
this.result = getTestCaseNodes(this.projectId, data => {

View File

@ -184,6 +184,7 @@ export let CUSTOM_TABLE_HEADER = {
{id: 'reviewStatus', key: '3', label: 'test_track.case.status'},
{id: 'tags', key: '4', label: 'commons.tag'},
{id: 'nodePath', key: '5', label: 'test_track.case.module'},
{id: 'projectName', key: 'a', label: 'test_track.review.review_project'},
{id: 'updateTime', key: '6', label: 'commons.update_time'},
{id: 'createUser', key: '7', label: 'commons.create_user'},
{id: 'createTime', key: '8', label: 'commons.create_time'},

View File

@ -98,6 +98,8 @@ export default {
api: 'API',
my_workstation: 'MyWorkstation',
performance: 'Performance',
enable_settings: 'Enable Settings',
view_settings: 'View Settings',
functional: 'Functional test',
input_content: 'Please enter content',
create: 'Create',
@ -647,6 +649,9 @@ export default {
no_data: 'No Data',
select: 'Select',
repeatable: 'Interface definition URL repeatable',
repeatable_info: 'Interface definition URL repeatable \n When enabled, the interface definition repeatability check will not check the URL',
case_public: 'Common use case library',
public_info: 'Start common use case library \n You can use the public use case library data or add your own use cases to the public use case library',
upload_file_again: 'Upload again',
code_segment: {
code_segment: "Custom Code",
@ -690,7 +695,9 @@ export default {
group_desc: 'Add user groups and global configuration',
code_segment_desc: 'Custom code snippet',
test_case_custom_id: 'Test Case Custom ID',
test_case_custom_id_info: 'Test Case Custom ID \n The Case ID defaults to the system self increment ID',
scenario_custom_id: 'Scenario Custom ID',
scenario_custom_id_info: 'Scenario Custom ID \n The scenario Case ID defaults to the system self increment ID',
},
member: {
create: 'Create',
@ -1020,6 +1027,7 @@ export default {
}
},
definition: {
api_quick_button: 'Api definition shortcut add button',
id: 'Api Definition ID',
api_title: "Api test",
case_title: "Test Case",
@ -1720,6 +1728,7 @@ export default {
case_type: "Case Type",
name: "Test case name",
module: "Module",
project: 'Project',
maintainer: "Maintainer",
steps: "Steps",
number: "Number",
@ -1737,12 +1746,13 @@ export default {
delete_confirm: "Confirm delete test case",
delete: "Delete case",
save_create_continue: "Save and create continue",
save_add_public: "Save and add public",
please_create_project: "No project available, please create the project first",
create_module_first: "Please create module first",
relate_test: "Relate test",
relate_issue: "Relate Issue",
demand_name_id: "Demand ID/Name",
please_select_relate_test: "请选择要关联的测试",
please_select_relate_test: "Please select the test to associate",
relate_test_not_find: 'The associated test does not exist, please check the test case',
other_relate_test_not_find: 'Associated test name, please go to the third party platform to execute',
batch_handle: 'Batch processing (select {0} item)',
@ -1754,6 +1764,10 @@ export default {
please_select_attr_value: 'Please select the value corresponding to the attribute',
batch_edit_case: 'Batch editing',
batch_move_case: 'Batch move',
batch_copy: 'Batch copy',
batch_add_public: 'Batch add public',
public_warning: 'The public library configuration is not enabled',
generate_dependencies: 'Generate dependencies',
batch_delete_case: 'Batch delete',
batch_unlink: 'Batch Unlink',
unlink: 'Unlink',

View File

@ -98,6 +98,8 @@ export default {
system_setting: '系统设置',
api: '接口测试',
performance: '性能测试',
enable_settings: '启用设置',
view_settings: '显示设置',
functional: '功能测试',
my_workstation: '我的工作台',
input_content: '请输入内容',
@ -653,6 +655,9 @@ export default {
no_data: '无数据',
select: '选择项目',
repeatable: '接口定义URL可重复',
repeatable_info: '接口定义URL可重复 \n 启用后接口定义重复性校验将不校验URL',
case_public: '公共用例库',
public_info: '启动公共用例库 \n 可以使用公共用例库数据,也可以自行添加用例至公共用例库',
upload_file_again: '重新上传',
code_segment: {
code_segment: "自定义代码片段",
@ -696,7 +701,9 @@ export default {
log_desc: '项目全部操作过程',
code_segment_desc: '自定义代码片段',
test_case_custom_id: '测试用例自定义ID',
test_case_custom_id_info: '测试用例自定义ID \n 用例ID默认为系统自增ID',
scenario_custom_id: '场景自定义ID',
scenario_custom_id_info: '场景自定义ID \n 场景用例ID默认为系统自增ID',
},
member: {
create: '添加成员',
@ -1029,6 +1036,7 @@ export default {
}
},
definition: {
api_quick_button: '接口定义快捷添加按钮',
id: '接口定义ID',
api_title: "接口列表",
case_title: "用例列表",
@ -1726,6 +1734,7 @@ export default {
case_type: "用例类型",
name: "用例名称",
module: "所属模块",
project: '所属项目',
maintainer: "维护人",
steps: "执行步骤",
number: "编号",
@ -1743,6 +1752,7 @@ export default {
delete_confirm: "确认删除测试用例",
delete: "删除用例",
save_create_continue: "保存并继续创建",
save_add_public: "保存并添加到公共用例库",
please_create_project: "暂无项目,请先创建项目",
create_module_first: "请先新建模块",
relate_test: "关联测试",
@ -1761,6 +1771,10 @@ export default {
batch_edit_case: '批量编辑',
batch_move_case: '批量移动',
batch_delete_case: '批量删除',
batch_copy: '批量复制',
batch_add_public: '批量添加到公共用例库',
public_warning: '未开启公共库用例配置',
generate_dependencies: '生成依赖关系',
batch_unlink: '批量取消关联',
unlink: '取消关联',
project_name: '所属项目',

View File

@ -98,6 +98,8 @@ export default {
system_setting: '系統設置',
api: '接口測試',
performance: '性能測試',
enable_settings: '啟用設置',
view_settings: '顯示設置',
functional: '功能測試',
input_content: '請輸入內容',
my_workstation: '我的工作台',
@ -651,6 +653,9 @@ export default {
no_data: '無數據',
select: '選擇項目',
repeatable: '接口定義URL可重復',
repeatable_info: '接口定義URL可重復 \n 啟用後介面定義重複性校驗將不校驗URL',
case_public: '公共用例庫',
public_info: '啟動公共用例庫 \n 可以使用公共用例庫數據,也可以自行添加用例至公共用例庫',
upload_file_again: '重新上傳',
code_segment: {
code_segment: "自定義代碼片段",
@ -694,7 +699,9 @@ export default {
group_desc: '添加用戶組與許可權以及全局配置',
code_segment_desc: '自定義代碼片段',
test_case_custom_id: '測試用例自定義ID',
test_case_custom_id_info: '測試用例自定義ID \n 用例ID默認為系統自增ID',
scenario_custom_id: '場景自定義ID',
scenario_custom_id_info: '場景自定義ID \n 場景用例ID默認為系統自增ID',
},
member: {
create: '添加成員',
@ -1026,6 +1033,7 @@ export default {
}
},
definition: {
api_quick_button: '接口定義快捷添加按鈕',
id: '接口定義ID',
api_title: "接口列表",
case_title: "用例列表",
@ -1729,6 +1737,7 @@ export default {
case_type: "用例類型",
name: "用例名稱",
module: "所屬模塊",
project: '所屬項目',
maintainer: "維護人",
steps: "執行步驟",
number: "編號",
@ -1746,6 +1755,7 @@ export default {
delete_confirm: "確認刪除測試用例",
delete: "刪除用例",
save_create_continue: "保存並繼續創建",
save_add_public: "保存並添加到公共用例庫",
please_create_project: "暫無項目,請先創建項目",
create_module_first: "請先新建模塊",
relate_test: "關聯測試",
@ -1763,6 +1773,10 @@ export default {
please_select_attr_value: '請選擇屬性對應的值',
batch_edit_case: '批量編輯',
batch_move_case: '批量移動',
batch_copy: '批量複製',
generate_dependencies: '生成依賴關係',
batch_add_public: '批量添加到公共用例庫',
public_warning: '未開啟公共用例庫配寘',
batch_delete_case: '批量刪除',
batch_unlink: '批量取消關聯',
unlink: '取消關聯',