fix: 测试计划用例自定义字段展示

This commit is contained in:
chenjianxing 2021-06-10 10:08:39 +08:00 committed by jianxing
parent 2541f784be
commit cf8b11d29f
10 changed files with 309 additions and 540 deletions

View File

@ -1,5 +1,6 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.controller.request.BaseQueryRequest;
import io.metersphere.track.dto.TestCaseReportStatusResultDTO;
import io.metersphere.track.dto.TestCaseTestDTO;
import io.metersphere.track.dto.TestPlanCaseDTO;
@ -53,4 +54,6 @@ public interface ExtTestPlanTestCaseMapper {
List<TestCaseTestDTO> listTestCaseTest(@Param("caseId") String caseId);
List<String> selectIds(@Param("request") TestPlanFuncCaseConditions conditions);
List<String> selectIdsByQuery(@Param("request") BaseQueryRequest query);
}

View File

@ -135,16 +135,7 @@
and plan_id = #{planId};
</select>
<select id="list" resultType="io.metersphere.track.dto.TestPlanCaseDTO">
select test_plan_test_case.id as id, test_case.id as caseId, test_case.name, test_case.priority,
test_case.type,test_case.test_id as testId,test_case.node_id, test_case.tags, test_case.maintainer,
test_case.node_path, test_case.method, if(project.custom_num = 0, cast(test_case.num as char), test_case.custom_num) as customNum, test_plan_test_case.executor, test_plan_test_case.status, test_plan_test_case.actual_result,
test_plan_test_case.update_time, test_case_node.name as model, project.name as projectName,
test_plan_test_case.plan_id as planId
from test_plan_test_case
inner join test_case on test_plan_test_case.case_id = test_case.id
left join test_case_node on test_case_node.id = test_case.node_id
inner join project on project.id = test_case.project_id
<sql id="queryWhereCondition">
<where>
<if test="request.combine != null">
<include refid="combine">
@ -155,9 +146,9 @@
</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.custom_num like CONCAT('%',#{request.name},'%')
or test_case.tags like CONCAT('%', #{request.name},'%'))
or test_case.num like CONCAT('%',#{request.name},'%')
or test_case.custom_num like CONCAT('%',#{request.name},'%')
or test_case.tags like CONCAT('%', #{request.name},'%'))
</if>
<if test="request.id != null">
and test_case.id = #{request.id}
@ -180,70 +171,69 @@
<if test="request.method != null">
and test_case.method = #{request.method}
</if>
<if test="request.filters != null and request.filters.size() > 0">
<foreach collection="request.filters.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key=='priority'">
and test_case.priority in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='type'">
and test_case.type in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='method'">
and test_case.method in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='maintainer'">
and test_case.maintainer in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='executor'">
and test_plan_test_case.executor in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<otherwise>
and test_plan_test_case.status in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</otherwise>
</choose>
</if>
</foreach>
</if>
<include refid="filter"/>
</where>
<if test="request.orders != null and request.orders.size() > 0">
order by
<foreach collection="request.orders" separator="," item="order">
<choose>
<!-- <when test="order.name == 'num'">-->
<!-- test_case.num ${order.type}-->
<!-- </when>-->
<when test="order.name == 'custom_num'">
test_case.num ${order.type}, test_case.custom_num ${order.type}
</when>
<when test="order.name == 'priority'">
test_case.priority ${order.type}
</when>
<otherwise>
test_plan_test_case.${order.name} ${order.type}
</otherwise>
</choose>
</sql>
<sql id="filter">
<if test="request.filters != null and request.filters.size() > 0">
<foreach collection="request.filters.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key=='priority'">
and test_case.priority in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='type'">
and test_case.type in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='method'">
and test_case.method in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='maintainer'">
and test_case.maintainer in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='executor'">
and test_plan_test_case.executor in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<otherwise>
and test_plan_test_case.status in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</otherwise>
</choose>
</if>
</foreach>
</if>
</sql>
<select id="list" resultType="io.metersphere.track.dto.TestPlanCaseDTO">
select test_plan_test_case.id as id, test_case.id as caseId, test_case.name, test_case.priority,
test_case.type,test_case.test_id as testId,test_case.node_id, test_case.tags, test_case.maintainer, test_case.custom_fields,
test_case.node_path, test_case.method, if(project.custom_num = 0, cast(test_case.num as char), test_case.custom_num) as customNum, test_plan_test_case.executor, test_plan_test_case.status, test_plan_test_case.actual_result,
test_plan_test_case.update_time, test_case_node.name as model, project.name as projectName,
test_plan_test_case.plan_id as planId
from test_plan_test_case
inner join test_case on test_plan_test_case.case_id = test_case.id
left join test_case_node on test_case_node.id = test_case.node_id
inner join project on project.id = test_case.project_id
<include refid="queryWhereCondition"/>
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/>
</select>
<select id="selectIds" resultType="java.lang.String">
select distinct test_plan_test_case.id as id
@ -251,97 +241,8 @@
inner join test_case on test_plan_test_case.case_id = test_case.id
left join test_case_node on test_case_node.id = test_case.node_id
inner join project on project.id = test_case.project_id
<where>
<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.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},'%'))
</if>
<if test="request.id != null">
and test_case.id = #{request.id}
</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.status != null">
and test_plan_test_case.status = #{request.status}
</if>
<if test="request.executor != null">
and test_plan_test_case.executor = #{request.executor}
</if>
<if test="request.planId != null">
and test_plan_test_case.plan_id = #{request.planId}
</if>
<if test="request.method != null">
and test_case.method = #{request.method}
</if>
<if test="request.filters != null and request.filters.size() > 0">
<foreach collection="request.filters.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key=='priority'">
and test_case.priority in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='type'">
and test_case.type in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='method'">
and test_case.method in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='maintainer'">
and test_case.maintainer in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='executor'">
and test_plan_test_case.executor in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<otherwise>
and test_plan_test_case.status in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</otherwise>
</choose>
</if>
</foreach>
</if>
</where>
<if test="request.orders != null and request.orders.size() > 0">
order by
<foreach collection="request.orders" separator="," item="order">
<choose>
<when test="order.name == 'num'">
test_case.num ${order.type}
</when>
<otherwise>
test_plan_test_case.${order.name} ${order.type}
</otherwise>
</choose>
</foreach>
</if>
<include refid="queryWhereCondition"/>
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/>
</select>
<select id="listTestCaseByProjectIds" resultType="io.metersphere.track.dto.TestPlanCaseDTO">
@ -539,7 +440,13 @@
<select id="listTestCaseTest" resultType="io.metersphere.track.dto.TestCaseTestDTO">
select * from test_case_test where test_case_id = #{caseId};
</select>
<select id="selectIdsByQuery" resultType="java.lang.String">
select test_plan_test_case.id
from test_plan_test_case
inner join test_case on test_plan_test_case.case_id = test_case.id
<include refid="queryWhereCondition"/>
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/>
</select>
<update id="updateTestCaseStates" parameterType="java.lang.String">
update test_plan_test_case
<set>

View File

@ -1,6 +1,7 @@
package io.metersphere.track.request.testplancase;
import io.metersphere.base.domain.TestPlanTestCase;
import io.metersphere.controller.request.BaseQueryRequest;
import io.metersphere.controller.request.OrderRequest;
import lombok.Getter;
import lombok.Setter;
@ -10,26 +11,16 @@ import java.util.Map;
@Getter
@Setter
public class QueryTestPlanCaseRequest extends TestPlanTestCase {
private List<String> nodeIds;
public class QueryTestPlanCaseRequest extends BaseQueryRequest {
private List<String> nodePaths;
private List<OrderRequest> orders;
private Map<String, List<String>> filters;
private List<String> planIds;
private List<String> projectIds;
private String workspaceId;
private String projectId;
private String name;
private String status;
private String node;
@ -38,5 +29,11 @@ public class QueryTestPlanCaseRequest extends TestPlanTestCase {
private String nodeId;
private String planId;
private String executor;
private String id;
private Map<String, Object> combine;
}

View File

@ -101,16 +101,7 @@ public class TestPlanTestCaseService {
}
public void editTestCaseBath(TestPlanCaseBatchRequest request) {
List<String> ids = request.getIds();
if (request.getCondition() != null && request.getCondition().isSelectAll()) {
ids = extTestPlanTestCaseMapper.selectIds(request.getCondition());
if (request.getCondition().getUnSelectIds() != null) {
ids.removeAll(request.getCondition().getUnSelectIds());
}
}
TestPlanTestCaseExample testPlanTestCaseExample = new TestPlanTestCaseExample();
testPlanTestCaseExample.createCriteria().andIdIn(ids);
TestPlanTestCaseExample testPlanTestCaseExample = getBatchExample(request);
TestPlanTestCaseWithBLOBs testPlanTestCase = new TestPlanTestCaseWithBLOBs();
BeanUtils.copyBean(testPlanTestCase, request);
testPlanTestCase.setUpdateTime(System.currentTimeMillis());
@ -119,6 +110,14 @@ public class TestPlanTestCaseService {
testPlanTestCaseExample);
}
public TestPlanTestCaseExample getBatchExample(TestPlanCaseBatchRequest request) {
ServiceUtils.getSelectAllIds(request, request.getCondition(),
(query) -> extTestPlanTestCaseMapper.selectIdsByQuery(query));
TestPlanTestCaseExample testPlanTestCaseExample = new TestPlanTestCaseExample();
testPlanTestCaseExample.createCriteria().andIdIn(request.getIds());
return testPlanTestCaseExample;
}
public List<TestPlanCaseDTO> getRecentTestCases(QueryTestPlanCaseRequest request, int count) {
buildQueryRequest(request, count);
if (request.getPlanIds().isEmpty()) {
@ -195,8 +194,7 @@ public class TestPlanTestCaseService {
}
public void deleteTestCaseBath(TestPlanCaseBatchRequest request) {
TestPlanTestCaseExample example = new TestPlanTestCaseExample();
example.createCriteria().andIdIn(request.getIds());
TestPlanTestCaseExample example = getBatchExample(request);
testPlanTestCaseMapper.deleteByExample(example);
}

View File

@ -16,7 +16,7 @@
:fields.sync="fields"
:table-is-loading="this.result.loading"
field-key="API_DEFINITION"
ref="apiDefinitionTable">
ref="table">
<span v-for="(item) in fields" :key="item.key">
<ms-table-column
@ -177,7 +177,7 @@ import MsTipButton from "@/business/components/common/components/MsTipButton";
import CaseBatchMove from "@/business/components/api/definition/components/basis/BatchMove";
import {
initCondition,
getCustomTableHeader, getCustomTableWidth, buildBatchParam
getCustomTableHeader, getCustomTableWidth, buildBatchParam, checkTableRowIsSelected
} from "@/common/js/tableUtils";
import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate";
import {Body} from "@/business/components/api/definition/model/ApiTestModel";
@ -390,9 +390,6 @@ export default {
projectId() {
return getCurrentProjectID();
},
selectRows() {
return this.$refs.apiDefinitionTable.getSelectRows();
},
getApiRequestTypeName(){
if(this.currentProtocol === 'TCP'){
return this.$t('api_test.definition.api_agreement');
@ -452,8 +449,8 @@ export default {
}
},
initTable() {
if (this.$refs.apiDefinitionTable) {
this.$refs.apiDefinitionTable.clearSelectRows();
if (this.$refs.table) {
this.$refs.table.clear();
}
initCondition(this.condition, this.condition.selectAll);
@ -499,13 +496,7 @@ export default {
}
});
// nexttick:
this.$nextTick(function () {
if (this.$refs.apiDefinitionTable) {
this.$refs.apiDefinitionTable.checkTableRowIsSelect();
this.$refs.apiDefinitionTable.doLayout();
}
});
checkTableRowIsSelected(this, this.$refs.table);
});
}
if(this.needRefreshModule()){
@ -620,7 +611,7 @@ export default {
});
},
handleBatchRestore() {
this.$post('/api/definition/reduction/', buildBatchParam(this), () => {
this.$post('/api/definition/reduction/', buildBatchParam(this, this.$refs.table.selectIds), () => {
this.$success(this.$t('commons.save_success'));
this.search();
});
@ -631,8 +622,8 @@ export default {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this.$post('/api/definition/deleteBatchByParams/', buildBatchParam(this), () => {
this.$refs.apiDefinitionTable.clearSelectRows();
this.$post('/api/definition/deleteBatchByParams/', buildBatchParam(this, this.$refs.table.selectIds), () => {
this.$refs.table.clear();
this.initTable();
this.$success(this.$t('commons.delete_success'));
});
@ -644,8 +635,8 @@ export default {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this.$post('/api/definition/removeToGcByParams/', buildBatchParam(this), () => {
this.$refs.apiDefinitionTable.clearSelectRows();
this.$post('/api/definition/removeToGcByParams/', buildBatchParam(this, this.$refs.table.selectIds), () => {
this.$refs.table.clear();
this.initTable();
this.$success(this.$t('commons.delete_success'));
this.$refs.caseList.apiCaseClose();
@ -668,7 +659,7 @@ export default {
this.$refs.batchEdit.open();
},
batchEdit(form) {
let param = buildBatchParam(this);
let param = buildBatchParam(this, this.$refs.table.selectIds);
param[form.type] = form.value;
this.$post('/api/definition/batch/editByParams', param, () => {
this.$success(this.$t('commons.save_success'));
@ -676,15 +667,10 @@ export default {
});
},
moveSave(param) {
let arr = Array.from(this.selectRows);
let ids = arr.map(row => row.id);
let ids = this.$refs.table.selectIds;
param.ids = ids;
param.projectId = this.projectId;
param.moduleId = param.nodeId;
param.condition = this.condition;
param.selectAllDate = this.isSelectAllDate;
param.unSelectIds = this.unSelection;
param = Object.assign(param, this.condition);
param.moduleId = param.nodeId;
this.$post('/api/definition/batch/editByParams', param, () => {
this.$success(this.$t('commons.save_success'));
@ -756,7 +742,7 @@ export default {
return ids;
},
exportApi(type) {
let param = buildBatchParam(this);
let param = buildBatchParam(this, this.$refs.table.selectIds);
param.protocol = this.currentProtocol;
if (param.ids === undefined || param.ids.length < 1) {
this.$warning(this.$t("api_test.definition.check_select"));

View File

@ -161,12 +161,16 @@ import TestCaseDetail from "./TestCaseDetail";
import ReviewStatus from "@/business/components/track/case/components/ReviewStatus";
import MsTag from "@/business/components/common/components/MsTag";
import {
buildBatchParam, deepClone, getCustomFieldBatchEditOption, getCustomFieldValue, getCustomTableWidth,
buildBatchParam,
checkTableRowIsSelected,
deepClone,
getCustomFieldBatchEditOption,
getCustomFieldValue,
getCustomTableWidth,
getPageInfo,
getTableHeaderWithCustomFields,
initCondition,
} from "@/common/js/tableUtils";
import {Track_Test_Case} from "@/business/components/common/model/JsonData";
import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate";
import PlanStatusTableItem from "@/business/components/track/common/tableItems/plan/PlanStatusTableItem";
import {getCurrentProjectID} from "@/common/js/utils";
@ -207,7 +211,6 @@ export default {
return {
type: TEST_CASE_LIST,
screenHeight: 'calc(100vh - 310px)',
headerItems: Track_Test_Case,
tableLabel: [],
deletePath: "/test/case/delete",
condition: {
@ -424,6 +427,7 @@ export default {
this.page.data.forEach((item) => {
item.tags = JSON.parse(item.tags);
});
checkTableRowIsSelected(this, this.$refs.table);
});
}
},
@ -464,7 +468,7 @@ export default {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let param = buildBatchParam(this);
let param = buildBatchParam(this, this.$refs.table.selectIds);
this.$post('/test/case/batch/delete', param, () => {
this.$refs.table.clear();
this.$emit("refresh");
@ -510,7 +514,7 @@ export default {
url: '/test/case/export/testcase',
method: 'post',
responseType: 'blob',
data: buildBatchParam(this)
data: buildBatchParam(this, this.$refs.table.selectIds)
};
if (config.data.ids === undefined || config.data.ids.length < 1) {

View File

@ -19,111 +19,91 @@
</template>
</ms-table-header>
<executor-edit ref="executorEdit" :select-ids="new Set(Array.from(this.selectRows).map(row => row.id))"
@refresh="initTableData"/>
<status-edit ref="statusEdit" :plan-id="planId"
:select-ids="new Set(Array.from(this.selectRows).map(row => row.id))" @refresh="initTableData"/>
<ms-table
v-loading="result.loading"
field-key="TEST_PLAN_FUNCTION_TEST_CASE"
:data="tableData"
:condition="condition"
:total="total"
:page-size.sync="pageSize"
:operators="operators"
:screen-height="screenHeight"
:batch-operators="buttons"
@handlePageChange="initTableData"
@handleRowClick="handleEdit"
:fields.sync="fields"
@refresh="initTableData"
ref="table">
<el-table
:key="updata"
ref="table"
class="test-content adjust-table ms-select-all-fixed"
border
@select-all="handleSelectAll"
@filter-change="filter"
@sort-change="sort"
@select="handleSelectionChange"
:height="screenHeight"
row-key="id"
@row-click="showDetail"
style="margin-top: 5px"
@header-dragend="headerDragend"
:data="tableData">
<el-table-column width="50" type="selection"/>
<ms-table-header-select-popover v-show="total>0"
:page-size="pageSize > total ? total : pageSize"
:total="total"
:table-data-count-in-page="tableData.length"
@selectPageAll="isSelectDataAll(false)"
@selectAll="isSelectDataAll(true)"/>
<el-table-column width="30" :resizable="false" align="center">
<template v-slot:default="scope">
<show-more-btn :is-show="scope.row.showMore" :buttons="buttons" :size="selectDataCounts"/>
</template>
</el-table-column>
<template v-for="(item, index) in tableLabel">
<el-table-column
<span v-for="item in fields" :key="item.key">
<ms-table-column
v-if="item.id == 'num'"
prop="customNum"
sortable="custom"
:fields-width="fieldsWidth"
:label="$t('commons.id')"
min-width="120px"
show-overflow-tooltip
:key="index">
</el-table-column>
<el-table-column
v-if="item.id=='name'"
min-width="120px"/>
<ms-table-column
prop="name"
:field="item"
:fields-width="fieldsWidth"
:label="$t('commons.name')"
min-width="120px"
:key="index"
show-overflow-tooltip>
</el-table-column>
<el-table-column
v-if="item.id=='priority'"
min-width="120px"/>
<ms-table-column
prop="priority"
:field="item"
:fields-width="fieldsWidth"
:filters="priorityFilters"
column-key="priority"
sortable="custom"
min-width="120px"
:key="index"
:label="$t('test_track.case.priority')">
<template v-slot:default="scope">
<priority-table-item :value="scope.row.priority" ref="priority"/>
</template>
</el-table-column>
</ms-table-column>
<el-table-column v-if="item.id=='tags'" prop="tags" :label="$t('commons.tag')" min-width="120px"
:key="index">
<ms-table-column
prop="tags"
:field="item"
:fields-width="fieldsWidth"
:label="$t('commons.tag')"
min-width="120px">
<template v-slot:default="scope">
<ms-tag v-for="(tag, index) in scope.row.showTags" :key="tag + '_' + index" type="success" effect="plain"
:content="tag" style="margin-left: 0px; margin-right: 2px"/>
</template>
</el-table-column>
</ms-table-column>
<el-table-column
v-if="item.id=='nodePath'"
<ms-table-column
prop="nodePath"
:field="item"
:fields-width="fieldsWidth"
:label="$t('test_track.case.module')"
min-width="120px"
:key="index"
show-overflow-tooltip>
</el-table-column>
min-width="120px"/>
<el-table-column
v-if="item.id=='projectName'"
<ms-table-column
prop="projectName"
:field="item"
:fields-width="fieldsWidth"
:label="$t('test_track.plan.plan_project')"
min-width="120px"
:key="index"
show-overflow-tooltip>
</el-table-column>
min-width="120px"/>
<el-table-column
v-if="item.id=='issuesContent'"
<ms-table-column
prop="issuesContent"
:field="item"
:fields-width="fieldsWidth"
:label="$t('test_track.issue.issue')"
min-width="80px"
show-overflow-tooltip
:key="index">
min-width="80px">
<template v-slot:default="scope">
<el-popover
placement="right"
width="400"
trigger="hover">
<el-table border class="adjust-table" :data="scope.row.issuesContent" style="width: 100%">
<el-table-column prop="title" :label="$t('test_track.issue.title')" show-overflow-tooltip/>
<el-table-column prop="description" :label="$t('test_track.issue.description')">
<ms-table-column prop="title" :label="$t('test_track.issue.title')" show-overflow-tooltip/>
<ms-table-column prop="description" :label="$t('test_track.issue.description')">
<template v-slot:default="scope">
<el-popover
placement="left"
@ -135,42 +115,37 @@
<el-button slot="reference" type="text">{{ $t('test_track.issue.preview') }}</el-button>
</el-popover>
</template>
</el-table-column>
<el-table-column prop="platform" :label="$t('test_track.issue.platform')"/>
</ms-table-column>
<ms-table-column prop="platform" :label="$t('test_track.issue.platform')"/>
</el-table>
<el-button slot="reference" type="text">{{ scope.row.issuesSize }}</el-button>
</el-popover>
</template>
</el-table-column>
</ms-table-column>
<el-table-column
v-if="item.id == 'executorName'"
<ms-table-column
prop="executorName"
:filters="executorFilters"
min-width="100px"
:key="index"
column-key="executor"
:label="$t('test_track.plan_view.executor')">
</el-table-column>
:field="item"
:fields-width="fieldsWidth"
:label="$t('test_track.plan_view.executor')"/>
<!-- 责任人(创建该用例时所关联的责任人) -->
<el-table-column
v-if="item.id == 'maintainer'"
<ms-table-column
prop="maintainerName"
:filters="maintainerFilters"
min-width="100px"
:key="index"
column-key="maintainerName"
:label="$t('api_test.definition.request.responsible')">
</el-table-column>
:field="item"
:fields-width="fieldsWidth"
:label="$t('api_test.definition.request.responsible')"/>
<el-table-column
v-if="item.id == 'status'"
<ms-table-column
prop="status"
:filters="statusFilters"
column-key="status"
min-width="100px"
:key="index"
:field="item"
:fields-width="fieldsWidth"
:label="$t('test_track.plan_view.execute_result')">
<template v-slot:default="scope">
<span @click.stop="clickt = 'stop'">
@ -197,43 +172,40 @@
</el-dropdown>
</span>
</template>
</el-table-column>
<el-table-column
v-if="item.id == 'updateTime'"
</ms-table-column>
<ms-table-column
sortable
prop="updateTime"
:field="item"
:fields-width="fieldsWidth"
:label="$t('commons.update_time')"
min-width="120px"
:key="index"
show-overflow-tooltip>
min-width="120px">
<template v-slot:default="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template>
</el-table-column>
</template>
<el-table-column
fixed="right"
min-width="100"
:label="$t('commons.operating')">
<template slot="header">
<header-label-operate @exec="customHeader"/>
</template>
<template v-slot:default="scope">
<div>
<ms-table-operator-button v-permission="['PROJECT_TRACK_CASE:READ+EDIT']" :tip="$t('commons.edit')"
icon="el-icon-edit"
@exec="handleEdit(scope.row)"/>
<ms-table-operator-button v-permission="['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL']"
:tip="$t('test_track.plan_view.cancel_relevance')"
icon="el-icon-unlock" type="danger" @exec="handleDelete(scope.row)"/>
</div>
</template>
</el-table-column>
</el-table>
<header-custom ref="headerCustom" :initTableData="initTableData" :optionalFields=headerItems
:type=type></header-custom>
</ms-table-column>
<ms-table-column v-for="field in testCaseTemplate.customFields" :key="field.id"
:filters="field.name === '用例等级' ? priorityFilters : null"
:field="item"
:fields-width="fieldsWidth"
:label="field.name"
:min-width="90"
:prop="field.name">
<template v-slot="scope">
<span v-if="field.name === '用例等级'">
<priority-table-item :value="getCustomFieldValue(scope.row, field) ? getCustomFieldValue(scope.row, field) : scope.row.priority"/>
</span>
<span v-else>
{{getCustomFieldValue(scope.row, field)}}
</span>
</template>
</ms-table-column>
</span>
</ms-table>
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/>
@ -244,7 +216,6 @@
:is-read-only="isReadOnly"
@refreshTable="search"/>
<!-- </el-card>-->
<batch-edit ref="batchEdit" @batchEdit="batchEdit"
:type-arr="typeArr" :value-arr="valueArr" :dialog-title="$t('test_track.case.batch_edit_case')"/>
</div>
@ -261,11 +232,8 @@ import MsTableButton from '../../../../../common/components/MsTableButton';
import NodeBreadcrumb from '../../../../common/NodeBreadcrumb';
import {
ROLE_TEST_MANAGER,
ROLE_TEST_USER,
TEST_PLAN_FUNCTION_TEST_CASE,
TokenKey,
WORKSPACE_ID
} from "@/common/js/constants";
import {getCurrentProjectID, hasPermission} from "@/common/js/utils";
import PriorityTableItem from "../../../../common/tableItems/planview/PriorityTableItem";
@ -275,34 +243,26 @@ import MethodTableItem from "../../../../common/tableItems/planview/MethodTableI
import MsTableOperator from "../../../../../common/components/MsTableOperator";
import MsTableOperatorButton from "../../../../../common/components/MsTableOperatorButton";
import {TEST_CASE_CONFIGS} from "../../../../../common/components/search/search-components";
import ShowMoreBtn from "../../../../case/components/ShowMoreBtn";
import BatchEdit from "../../../../case/components/BatchEdit";
import ClassicEditor from "@ckeditor/ckeditor5-build-classic";
import {hub} from "@/business/components/track/plan/event-bus";
import MsTag from "@/business/components/common/components/MsTag";
import {
_filter,
_handleSelect,
_handleSelectAll,
_sort,
buildBatchParam,
deepClone,
getLabel,
getSelectDataCounts,
buildBatchParam, checkTableRowIsSelected,
getCustomFieldValue, getCustomTableWidth,
getTableHeaderWithCustomFields,
initCondition,
setUnSelectIds,
toggleAllSelection
} from "@/common/js/tableUtils";
import HeaderCustom from "@/business/components/common/head/HeaderCustom";
import {Test_Plan_Function_Test_Case} from "@/business/components/common/model/JsonData";
import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate";
import MsTableHeaderSelectPopover from "@/business/components/common/components/table/MsTableHeaderSelectPopover";
import MsTable from "@/business/components/common/components/table/MsTable";
import MsTableColumn from "@/business/components/common/components/table/Ms-table-column";
import {getProjectMember} from "@/network/user";
import {getTestTemplate} from "@/network/custom-field-template";
export default {
name: "FunctionalTestCaseList",
components: {
HeaderLabelOperate,
HeaderCustom,
MsTableColumn,
MsTable,
FunctionalTestCaseEdit,
MsTableOperatorButton,
MsTableOperator,
@ -310,14 +270,15 @@ export default {
TypeTableItem,
StatusTableItem,
PriorityTableItem, StatusEdit, ExecutorEdit, MsTipButton, MsTablePagination,
MsTableHeader, NodeBreadcrumb, MsTableButton, ShowMoreBtn,
BatchEdit, MsTag, MsTableHeaderSelectPopover
MsTableHeader, NodeBreadcrumb, MsTableButton,
BatchEdit, MsTag
},
data() {
return {
updata: false,
// updata: false,
type: TEST_PLAN_FUNCTION_TEST_CASE,
headerItems: Test_Plan_Function_Test_Case,
fields: [],
fieldsWidth: getCustomTableWidth('TRACK_TEST_CASE'),
screenHeight: 'calc(100vh - 330px)',
tableLabel: [],
result: {},
@ -331,7 +292,6 @@ export default {
pageSize: 10,
total: 0,
status: 'default',
selectRows: new Set(),
testPlan: {},
isReadOnly: false,
hasEditPermission: false,
@ -345,11 +305,6 @@ export default {
{text: this.$t('test_track.case.manual'), value: 'manual'},
{text: this.$t('test_track.case.auto'), value: 'auto'}
],
typeFilters: [
{text: this.$t('commons.functional'), value: 'functional'},
{text: this.$t('commons.performance'), value: 'performance'},
{text: this.$t('commons.api'), value: 'api'}
],
statusFilters: [
{text: this.$t('test_track.plan.plan_status_prepare'), value: 'Prepare'},
{text: this.$t('test_track.plan_view.pass'), value: 'Pass'},
@ -371,6 +326,18 @@ export default {
permissions: ['PROJECT_TRACK_PLAN:READ+CASE_BATCH_DELETE']
}
],
operators: [
{
tip: this.$t('commons.edit'), icon: "el-icon-edit",
exec: this.handleEdit,
permissions: ['PROJECT_TRACK_CASE:READ+EDIT']
},
{
tip: this.$t('test_track.plan_view.cancel_relevance'), icon: "el-icon-unlock", type: "danger",
exec: this.handleDelete,
permissions: ['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL']
}
],
typeArr: [
{id: 'status', name: this.$t('test_track.plan_view.execute_result')},
{id: 'executor', name: this.$t('test_track.plan_view.executor')},
@ -389,8 +356,9 @@ export default {
// 'increaseIndent','decreaseIndent'
toolbar: [],
},
selectDataCounts: 0,
selectDataRange: "all"
selectDataRange: "all",
testCaseTemplate: {},
};
},
props: {
@ -426,16 +394,30 @@ export default {
this.refreshTableAndPlan();
this.hasEditPermission = hasPermission('PROJECT_TRACK_PLAN:READ+EDIT');
this.getMaintainerOptions();
this.getTemplateField();
},
beforeDestroy() {
hub.$off("openFailureTestCase");
},
methods: {
customHeader() {
const list = deepClone(this.tableLabel);
this.$refs.headerCustom.open(list);
getTemplateField() {
this.result.loading = true;
let p1 = getProjectMember((data) => {
this.members = data;
});
let p2 = getTestTemplate();
Promise.all([p1, p2]).then((data) => {
let template = data[1];
this.result.loading = true;
this.testCaseTemplate = template;
this.fields = getTableHeaderWithCustomFields('TEST_PLAN_FUNCTION_TEST_CASE', this.testCaseTemplate.customFields);
this.result.loading = false;
this.$refs.table.reloadTable();
});
},
getCustomFieldValue(row, field) {
return getCustomFieldValue(row, field, this.members);
},
initTableData() {
initCondition(this.condition, this.condition.selectAll);
this.autoCheckStatus();
@ -463,6 +445,9 @@ export default {
this.tableData = data.listObject;
for (let i = 0; i < this.tableData.length; i++) {
if (this.tableData[i]) {
if (this.tableData[i].customFields) {
this.tableData[i].customFields = JSON.parse(this.tableData[i].customFields);
}
this.$set(this.tableData[i], "showTags", JSON.parse(this.tableData[i].tags));
this.$set(this.tableData[i], "issuesSize", 0);
this.$get("/issues/get/" + this.tableData[i].caseId).then(response => {
@ -480,17 +465,10 @@ export default {
});
}
}
this.selectRows.clear();
if (this.$refs.table) {
setTimeout(this.$refs.table.doLayout, 200);
}
this.$nextTick(() => {
this.checkTableRowIsSelect();
});
this.$refs.table.clear();
checkTableRowIsSelected(this, this.$refs.table);
});
}
getLabel(this, TEST_PLAN_FUNCTION_TEST_CASE);
},
autoCheckStatus() {
if (!this.planId) {
@ -505,7 +483,7 @@ export default {
},
refresh() {
this.condition = {components: TEST_CASE_CONFIGS};
this.selectRows.clear();
this.$refs.table.clear();
this.$emit('refresh');
},
breadcrumbRefresh() {
@ -551,42 +529,16 @@ export default {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
if (this.selectRows.size > 0) {
if (this.condition.selectAll) {
let param = buildBatchParam(this);
this.$post('/test/plan/case/idList/all', param, res => {
let ids = res.data;
this._handleBatchDelete(ids);
});
} else {
let ids = Array.from(this.selectRows).map(row => row.id);
this._handleBatchDelete(ids);
}
} else {
if (this.planId) {
this.condition.planId = this.planId;
}
if (this.selectNodeIds && this.selectNodeIds.length > 0) {
this.condition.nodeIds = this.selectNodeIds;
}
//
this.$post('/test/plan/case/list/all', this.condition, res => {
let data = res.data;
let ids = data.map(d => d.id);
this._handleBatchDelete(ids);
});
}
let param = buildBatchParam(this, this.$refs.table.selectIds);
this.$post('/test/plan/case/batch/delete', param, () => {
this.$refs.table.clear();
this.$emit("refresh");
this.$success(this.$t('test_track.cancel_relevance_success'));
});
}
}
});
},
_handleBatchDelete(ids) {
this.result = this.$post('/test/plan/case/batch/delete', {ids: ids}, () => {
this.selectRows.clear();
this.$emit("refresh");
this.$success(this.$t('test_track.cancel_relevance_success'));
});
},
_handleDelete(testCase) {
let testCaseId = testCase.id;
this.result = this.$post('/test/plan/case/delete/' + testCaseId, {}, () => {
@ -594,29 +546,6 @@ export default {
this.$success(this.$t('test_track.cancel_relevance_success'));
});
},
handleSelectAll(selection) {
_handleSelectAll(this, selection, this.tableData, this.selectRows);
setUnSelectIds(this.tableData, this.condition, this.selectRows);
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
},
handleSelectionChange(selection, row) {
_handleSelect(this, selection, row, this.selectRows);
setUnSelectIds(this.tableData, this.condition, this.selectRows);
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
},
handleBatch(type) {
if (this.selectRows.size < 1) {
this.$warning(this.$t('test_track.plan_view.select_manipulate'));
return;
}
if (type === 'executor') {
this.$refs.executorEdit.openExecutorEdit();
} else if (type === 'status') {
this.$refs.statusEdit.openStatusEdit();
} else if (type === 'delete') {
this.handleDeleteBatch();
}
},
searchMyTestCase() {
this.showMyTestCase = !this.showMyTestCase;
if (this.showMyTestCase) {
@ -645,33 +574,12 @@ export default {
});
}
},
filter(filters) {
_filter(filters, this.condition);
this.initTableData();
},
sort(column) {
//
if (this.condition.orders) {
this.condition.orders = [];
}
_sort(column, this.condition);
this.initTableData();
},
headerDragend(newWidth, oldWidth, column, event) {
let finalWidth = newWidth;
if (column.minWidth > finalWidth) {
finalWidth = column.minWidth;
}
column.width = finalWidth;
column.realWidth = finalWidth;
},
batchEdit(form) {
let param = buildBatchParam(this);
let param = buildBatchParam(this, this.$refs.table.selectIds);
param[form.type] = form.value;
param.ids = Array.from(this.selectRows).map(row => row.id);
param.ids = this.$refs.table.selectIds;
this.$post('/test/plan/case/batch/edit', param, () => {
this.selectRows.clear();
this.$refs.table.clear();
this.status = '';
this.$post('/test/plan/edit/status/' + this.planId);
this.$success(this.$t('commons.save_success'));
@ -693,40 +601,6 @@ export default {
});
});
},
checkTableRowIsSelect() {
//
if (this.condition.selectAll) {
let unSelectIds = this.condition.unSelectIds;
this.tableData.forEach(row => {
if (unSelectIds.indexOf(row.id) < 0) {
this.$refs.table.toggleRowSelection(row, true);
//selectRows
if (!this.selectRows.has(row)) {
this.$set(row, "showMore", true);
this.selectRows.add(row);
}
} else {
//selectRow
if (this.selectRows.has(row)) {
this.$set(row, "showMore", false);
this.selectRows.delete(row);
}
}
});
}
},
isSelectDataAll(data) {
this.condition.selectAll = data;
//
toggleAllSelection(this.$refs.table, this.tableData, this.selectRows);
//
_handleSelectAll(this, this.tableData, this.tableData, this.selectRows);
//ID()
this.condition.unSelectIds = [];
//
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
},
}
};
</script>
@ -746,11 +620,15 @@ export default {
margin-left: 10px;
}
.ms-table-header >>> .table-title {
height: 0px;
}
/*.ms-table-header >>> .table-title {*/
/* height: 0px;*/
/*}*/
/deep/ .el-table__fixed-body-wrapper {
top: 59px !important;
/*/deep/ .el-table__fixed-body-wrapper {*/
/* top: 59px !important;*/
/*}*/
.ms-table-header {
margin-bottom: 10px;
}
</style>

View File

@ -57,7 +57,7 @@ export function parseCustomField(data, template, customFieldForm, rules, oldFiel
if (data.customFields instanceof Array) {
for (let i = 0; i < data.customFields.length; i++) {
let customField = data.customFields[i];
if (customField.id === item.id) {
if (customField.name === item.name) {
setDefaultValue(item, customField.value);
break;
}
@ -97,13 +97,12 @@ export function buildCustomFields(data, param, template) {
}
nameSet.add(name);
}
}
template.customFields.forEach(item => {
let hasField = false;
for (const index in customFields) {
if (customFields[index].id === item.id) {
if (customFields[index].name === item.name) {
hasField = true;
customFields[index].name = item.name;
customFields[index].value = item.defaultValue;

View File

@ -12,13 +12,6 @@ export const CUSTOM_FIELD_LIST = new Set([
'updateTime'
]);
export const TEST_CASE_TEMPLATE_LIST = new Set([
'name',
'type',
'description',
'createTime',
'updateTime'
]);
export const ISSUE_TEMPLATE_LIST = new Set([
'name',
@ -100,7 +93,7 @@ export const CUSTOM_TABLE_HEADER = {
{id: 'reviewerName', key: '7', label: i18n.t('test_track.review.reviewer')},
{id: 'reviewStatus', key: '8', label: i18n.t('test_track.case.status')},
{id: 'updateTime', key: '9', label: i18n.t('commons.update_time')},
{id: 'maintainer', key: '10', label: i18n.t('custom_field.case_maintainer')},
{id: 'maintainer', key: 'a', label: i18n.t('custom_field.case_maintainer')},
],
//测试计划
TEST_PLAN_LIST: [
@ -113,26 +106,23 @@ export const CUSTOM_TABLE_HEADER = {
{id: 'plannedStartTime', key: '7', label: i18n.t('test_track.plan.planned_start_time')},
{id: 'plannedEndTime', key: '8', label: i18n.t('test_track.plan.planned_end_time')},
{id: 'actualStartTime', key: '9', label: i18n.t('test_track.plan.actual_start_time')},
{id: 'actualEndTime', key: '10', label: i18n.t('test_track.plan.actual_end_time')},
{id: 'tags', key: '11', label: i18n.t('commons.tag')},
{id: 'executionTimes', key: '12', label: i18n.t('commons.execution_times')},
{id: 'passRate', key: '13', label: i18n.t('commons.pass_rate')},
{id: 'createUser', key: '14', label: i18n.t('commons.create_user')},
{id: 'actualEndTime', key: 'a', label: i18n.t('test_track.plan.actual_end_time')},
{id: 'tags', key: 'b', label: i18n.t('commons.tag')},
{id: 'executionTimes', key: 'c', label: i18n.t('commons.execution_times')},
{id: 'passRate', key: 'd', label: i18n.t('commons.pass_rate')},
{id: 'createUser', key: 'e', label: i18n.t('commons.create_user')},
],
//测试计划-功能用例
TEST_PLAN_FUNCTION_TEST_CASE: [
{id: 'num', key: '1', label: i18n.t('commons.id')},
{id: 'name', key: ' 2', label: i18n.t('commons.name')},
{id: 'priority', key: '3', label: i18n.t('test_track.case.priority')},
{id: 'type', key: '4', label: i18n.t('test_track.case.type')},
{id: 'tags', key: '5', label: i18n.t('commons.tag')},
{id: 'nodePath', key: '6', label: i18n.t('test_track.case.module')},
{id: 'projectName', key: '7', label: i18n.t('test_track.review.review_project')},
{id: 'issuesContent', key: '8', label: i18n.t('test_track.issue.issue')},
{id: 'executorName', key: '9', label: i18n.t('test_track.plan_view.executor')},
{id: 'status', key: '10', label: i18n.t('test_track.plan_view.execute_result')},
{id: 'updateTime', key: '11', label: i18n.t('commons.update_time')},
{id: 'maintainer', key: '12', label: i18n.t('api_test.definition.request.responsible')}
{id: 'name', key: '2', label: i18n.t('commons.name')},
{id: 'tags', key: '3', label: i18n.t('commons.tag')},
{id: 'nodePath', key: '4', label: i18n.t('test_track.case.module')},
{id: 'projectName', key: '5', label: i18n.t('test_track.review.review_project')},
{id: 'issuesContent', key: '6', label: i18n.t('test_track.issue.issue')},
{id: 'executorName', key: '7', label: i18n.t('test_track.plan_view.executor')},
{id: 'status', key: '8', label: i18n.t('test_track.plan_view.execute_result')},
{id: 'updateTime', key: '9', label: i18n.t('commons.update_time')},
],
//测试计划-api用例
TEST_PLAN_API_CASE: [
@ -169,7 +159,7 @@ export const CUSTOM_TABLE_HEADER = {
{id: 'stepTotal', key: '7', label: i18n.t('api_test.automation.success')},
{id: 'lastResult', key: '8', label: i18n.t('api_test.automation.fail')},
{id: 'passRate', key: '9', label: i18n.t('api_test.automation.passing_rate')},
{id: 'maintainer', key: '10', label: i18n.t('api_test.definition.request.responsible')}
{id: 'maintainer', key: 'a', label: i18n.t('api_test.definition.request.responsible')}
],
//测试用例
TRACK_TEST_CASE: [

View File

@ -9,6 +9,7 @@ export function _handleSelectAll(component, selection, tableData, selectRows, co
selection.hashTree = [];
tableData.forEach(item => {
component.$set(item, "showMore", true);
selectRows.add(item);
});
} else {
tableData.forEach(item => {
@ -26,9 +27,6 @@ export function _handleSelectAll(component, selection, tableData, selectRows, co
condition.selectAll = false;
}
}
if (selectRows.size < 1 && condition) {
condition.selectAll = false;
}
}
export function _handleSelect(component, selection, row, selectRows) {
@ -109,6 +107,15 @@ export function checkTableRowIsSelect(component, condition, tableData, table, se
}
}
// nexttick:表格加载完成之后触发。判断是否需要勾选行
export function checkTableRowIsSelected(veuObj, table) {
veuObj.$nextTick(function () {
if (table) {
table.checkTableRowIsSelect();
table.doLayout();
}
});
}
//表格数据过滤
export function _filter(filters, condition) {
@ -179,9 +186,9 @@ export function getLabel(vueObj, type) {
}
export function buildBatchParam(vueObj) {
export function buildBatchParam(vueObj, selectIds) {
let param = {};
param.ids = Array.from(vueObj.selectRows).map(row => row.id);
param.ids = selectIds ? selectIds: Array.from(vueObj.selectRows).map(row => row.id);
param.projectId = getCurrentProjectID();
param.condition = vueObj.condition;
return param;