This commit is contained in:
王振 2020-05-09 19:05:02 +08:00
commit c316b279c1
18 changed files with 244 additions and 84 deletions

View File

@ -5,6 +5,7 @@ import io.metersphere.controller.request.ReportRequest;
import io.metersphere.controller.request.testcase.QueryTestCaseRequest;
import io.metersphere.controller.request.testplancase.QueryTestPlanCaseRequest;
import io.metersphere.dto.ReportDTO;
import io.metersphere.dto.TestCaseDTO;
import io.metersphere.dto.TestPlanCaseDTO;
import org.apache.ibatis.annotations.Param;
@ -14,5 +15,5 @@ public interface ExtTestCaseMapper {
List<TestCase> getTestCaseNames(@Param("request") QueryTestCaseRequest request);
List<TestPlanCaseDTO> getTestPlanTestCases(@Param("request") QueryTestPlanCaseRequest request);
List<TestCaseDTO> list(@Param("request") QueryTestCaseRequest request);
}

View File

@ -20,25 +20,37 @@
ORDER BY test_case.update_time DESC
</select>
<select id="getTestPlanTestCases" resultType="io.metersphere.dto.TestPlanCaseDTO">
select t1.id as id, t1.plan_id as planId, t1.executor as executor, t1.status as status, t1.results as results, t1.create_time as createTime, t1.update_time updateTime,
t2.id as caseId, t2.node_id as nodeId, t2.node_path as nodePath, t2.project_id as projectId, t2.name as name, t2.remark remark, t2.steps steps,
t2.type as type, t2.maintainer as maintainer, t2.priority as priority, t2.method as method, t2.prerequisite as prerequisite
from test_plan_test_case as t1
inner join test_case as t2 on
t1.plan_id = #{request.planId}
<if test="request.nodeIds != null and request.nodeIds.size() > 0">
and t2.node_id in
<foreach collection="request.nodeIds" open="(" close=")" separator="," item="nodeId">
#{nodeId}
<select id="list" resultType="io.metersphere.dto.TestCaseDTO">
select test_case.* from test_case
<where>
<if test="request.name != null">
and test_case.name like CONCAT('%', #{request.name},'%')
</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.projectId != null">
and test_case.project_id = #{request.projectId}
</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">
and test_case.${key} in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</if>
</foreach>
</if>
</where>
<if test="request.orders != null and request.orders.size() > 0">
order by
<foreach collection="request.orders" separator="," item="order">
${order.name} ${order.type}
</foreach>
</if>
and t1.case_id = t2.id
<if test="request.name != null">
and t2.name like CONCAT('%', #{request.name},'%')
</if>
<if test="request.executor != null">
and t1.executor = #{request.executor}
</if>
</select>
</mapper>

View File

@ -1,6 +1,8 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.controller.request.testplancase.QueryTestPlanCaseRequest;
import io.metersphere.dto.TestCaseReportStatusResultDTO;
import io.metersphere.dto.TestPlanCaseDTO;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@ -10,4 +12,7 @@ public interface ExtTestPlanTestCaseMapper {
List<TestCaseReportStatusResultDTO> getReportMetric(@Param("planId") String planId);
List<String> getExecutors(@Param("planId") String planId);
List<TestPlanCaseDTO> list(@Param("request") QueryTestPlanCaseRequest request);
}

View File

@ -19,5 +19,41 @@
and plan_id = #{planId};
</select>
<select id="list" resultType="io.metersphere.dto.TestPlanCaseDTO">
select test_plan_test_case.*, test_case.*
from test_plan_test_case
inner join test_case on test_plan_test_case.case_id = test_case.id
<where>
<if test="request.name != null">
and test_plan_test_case.name like CONCAT('%', #{request.name},'%')
</if>
<if test="request.nodeIds != null and request.nodeIds.size() > 0">
and test_plan_test_case.node_id in
<foreach collection="request.nodeIds" item="nodeId" separator="," open="(" close=")">
#{nodeId}
</foreach>
</if>
<if test="request.planId != null">
and test_plan_test_case.plan_id = #{request.planId}
</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">
and ${key} in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</if>
</foreach>
</if>
</where>
<if test="request.orders != null and request.orders.size() > 0">
order by
<foreach collection="request.orders" separator="," item="order">
test_plan_test_case.${order.name} ${order.type}
</foreach>
</if>
</select>
</mapper>

View File

@ -8,6 +8,7 @@ import io.metersphere.commons.utils.Pager;
import io.metersphere.controller.request.testcase.QueryTestCaseRequest;
import io.metersphere.controller.request.testcase.TestCaseBatchRequest;
import io.metersphere.controller.request.testcase.TestPlanCaseBatchRequest;
import io.metersphere.dto.TestCaseDTO;
import io.metersphere.excel.domain.ExcelResponse;
import io.metersphere.service.TestCaseService;
import io.metersphere.user.SessionUtils;
@ -16,6 +17,7 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
@RequestMapping("/test/case")
@ -26,7 +28,7 @@ public class TestCaseController {
TestCaseService testCaseService;
@PostMapping("/list/{goPage}/{pageSize}")
public Pager<List<TestCaseWithBLOBs>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestCaseRequest request) {
public Pager<List<TestCaseDTO>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestCaseRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, testCaseService.listTestCase(request));
}

View File

@ -0,0 +1,9 @@
package io.metersphere.controller.request;
import lombok.Data;
@Data
public class OrderRequest {
private String name;
private String type;
}

View File

@ -1,15 +1,21 @@
package io.metersphere.controller.request.testcase;
import io.metersphere.base.domain.TestCase;
import io.metersphere.controller.request.OrderRequest;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data
public class QueryTestCaseRequest extends TestCase {
private List<String> nodeIds;
private List<OrderRequest> orders;
private Map<String, List<String>> filters;
private String planId;
private String workspaceId;

View File

@ -1,16 +1,21 @@
package io.metersphere.controller.request.testplancase;
import io.metersphere.base.domain.TestCase;
import io.metersphere.base.domain.TestPlanTestCase;
import io.metersphere.controller.request.OrderRequest;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data
public class QueryTestPlanCaseRequest extends TestPlanTestCase {
private List<String> nodeIds;
private List<OrderRequest> orders;
private Map<String, List<String>> filters;
private String workspaceId;
private String name;

View File

@ -0,0 +1,18 @@
package io.metersphere.dto;
import io.metersphere.base.domain.TestCaseWithBLOBs;
import lombok.Data;
@Data
public class TestCaseDTO extends TestCaseWithBLOBs{
private String maintainerName;
public String getMaintainerName() {
return maintainerName;
}
public void setMaintainerName(String maintainerName) {
this.maintainerName = maintainerName;
}
}

View File

@ -2,34 +2,12 @@ package io.metersphere.dto;
import io.metersphere.base.domain.TestCase;
import io.metersphere.base.domain.TestCaseWithBLOBs;
import lombok.Data;
@Data
public class TestPlanCaseDTO extends TestCaseWithBLOBs {
private String executor;
private String status;
private String results;
public String getExecutor() {
return executor;
}
public void setExecutor(String executor) {
this.executor = executor;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getResults() {
return results;
}
public void setResults(String results) {
this.results = results;
}
}

View File

@ -112,7 +112,7 @@ public class TestCaseReportService {
QueryTestPlanCaseRequest request = new QueryTestPlanCaseRequest();
request.setPlanId(planId);
List<TestPlanCaseDTO> testPlanTestCases = extTestCaseMapper.getTestPlanTestCases(request);
List<TestPlanCaseDTO> testPlanTestCases = extTestPlanTestCaseMapper.list(request);
Map<String, TestCaseReportModuleResultDTO> moduleResultMap = new HashMap<>();

View File

@ -12,6 +12,7 @@ import io.metersphere.commons.utils.LogUtil;
import io.metersphere.controller.request.testcase.QueryTestCaseRequest;
import io.metersphere.controller.request.testcase.TestCaseBatchRequest;
import io.metersphere.controller.request.testcase.TestPlanCaseBatchRequest;
import io.metersphere.dto.TestCaseDTO;
import io.metersphere.excel.domain.ExcelErrData;
import io.metersphere.excel.domain.ExcelResponse;
import io.metersphere.excel.domain.TestCaseExcelData;
@ -101,19 +102,8 @@ public class TestCaseService {
return testCaseMapper.deleteByPrimaryKey(testCaseId);
}
public List<TestCaseWithBLOBs> listTestCase(QueryTestCaseRequest request) {
TestCaseExample testCaseExample = new TestCaseExample();
TestCaseExample.Criteria criteria = testCaseExample.createCriteria();
if ( StringUtils.isNotBlank(request.getName()) ) {
criteria.andNameLike("%" + request.getName() + "%");
}
if ( StringUtils.isNotBlank(request.getProjectId()) ) {
criteria.andProjectIdEqualTo(request.getProjectId());
}
if ( request.getNodeIds() != null && request.getNodeIds().size() > 0) {
criteria.andNodeIdIn(request.getNodeIds());
}
return testCaseMapper.selectByExampleWithBLOBs(testCaseExample);
public List<TestCaseDTO> listTestCase(QueryTestCaseRequest request) {
return extTestCaseMapper.list(request);
}
/**

View File

@ -4,6 +4,7 @@ import io.metersphere.base.domain.TestPlanTestCase;
import io.metersphere.base.domain.TestPlanTestCaseExample;
import io.metersphere.base.mapper.TestPlanTestCaseMapper;
import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper;
import io.metersphere.commons.constants.TestPlanTestCaseStatus;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.controller.request.testcase.TestPlanCaseBatchRequest;
@ -24,10 +25,10 @@ public class TestPlanTestCaseService {
TestPlanTestCaseMapper testPlanTestCaseMapper;
@Resource
ExtTestCaseMapper extTestCaseMapper;
ExtTestPlanTestCaseMapper extTestPlanTestCaseMapper;
public List<TestPlanCaseDTO> getTestPlanCases(QueryTestPlanCaseRequest request) {
return extTestCaseMapper.getTestPlanTestCases(request);
return extTestPlanTestCaseMapper.list(request);
}
public void editTestCase(TestPlanTestCase testPlanTestCase) {

View File

@ -21,6 +21,7 @@ mybatis.configuration.multiple-result-sets-enabled=true
mybatis.configuration.use-column-label=true
mybatis.configuration.auto-mapping-behavior=full
mybatis.configuration.default-statement-timeout=25000
mybatis.configuration.map-underscore-to-camel-case=true
logging.file.path=/opt/metersphere/logs/${spring.application.name}

View File

@ -2,9 +2,10 @@
<div>
<el-dialog :title="operationType == 'edit' ? ( readOnly ? $t('test_track.case.view_case') : $t('test_track.case.edit_case')) : $t('test_track.case.create')" :visible.sync="dialogFormVisible" width="65%">
<el-dialog :title="operationType == 'edit' ? ( readOnly ? $t('test_track.case.view_case') : $t('test_track.case.edit_case')) : $t('test_track.case.create')"
:visible.sync="dialogFormVisible" width="65%">
<el-form :model="form" :rules="rules" ref="caseFrom">
<el-form :model="form" :rules="rules" ref="caseFrom" v-loading="result.loading">
<el-row>
<el-col :span="8" :offset="1">
@ -13,13 +14,12 @@
:label="$t('test_track.case.name')"
:label-width="formLabelWidth"
prop="name">
<el-input :disabled="readOnly" v-model="form.name"></el-input>
<el-input class="case-name" :disabled="readOnly" v-model="form.name"></el-input>
</el-form-item>
</el-col>
<el-col :span="11" :offset="2">
<el-form-item :label="$t('test_track.case.module')" :label-width="formLabelWidth" prop="module">
<el-select
v-model="form.module"
:disabled="readOnly"
@ -43,7 +43,7 @@
<el-option
v-for="item in maintainerOptions"
:key="item.id"
:label="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
@ -173,6 +173,10 @@
</el-form>
<template v-slot:footer>
<el-switch
v-model="isCreateContinue"
active-text="保存并继续创建">
</el-switch>
<ms-dialog-footer v-if="!readOnly"
@cancel="dialogFormVisible = false"
@confirm="saveCase"/>
@ -196,6 +200,7 @@
components: {MsDialogFooter},
data() {
return {
result: {},
dialogFormVisible: false,
form: {
name: '',
@ -227,7 +232,8 @@
method :[{required: true, message: this.$t('test_track.case.input_method'), trigger: 'change'}]
},
formLabelWidth: "120px",
operationType: ''
operationType: '',
isCreateContinue: false
};
},
props: {
@ -318,8 +324,12 @@
this.$warning(this.$t('test_track.case.input_name'));
return;
}
this.$post('/test/case/' + this.operationType, param, () => {
this.result = this.$post('/test/case/' + this.operationType, param, () => {
this.$success(this.$t('commons.save_success'));
if (this.operationType == 'add' && this.isCreateContinue) {
this.form.name = '';
return;
}
this.dialogFormVisible = false;
this.$emit("refresh");
});
@ -394,4 +404,12 @@
display: none;
}
.el-switch {
margin-bottom: 10px;
}
.case-name {
width: 194px;
}
</style>

View File

@ -22,6 +22,8 @@
<el-table
:data="tableData"
@sort-change="sort"
@filter-change="filter"
@select-all="handleSelectAll"
@select="handleSelectionChange"
@row-click="showDetail"
@ -37,7 +39,7 @@
<el-table-column
prop="priority"
:filters="priorityFilters"
:filter-method="filter"
column-key="priority"
:label="$t('test_track.case.priority')"
show-overflow-tooltip>
<template v-slot:default="scope">
@ -47,7 +49,7 @@
<el-table-column
prop="type"
:filters="typeFilters"
:filter-method="filter"
column-key="type"
:label="$t('test_track.case.type')"
show-overflow-tooltip>
<template v-slot:default="scope">
@ -56,8 +58,8 @@
</el-table-column>
<el-table-column
prop="method"
column-key="method"
:filters="methodFilters"
:filter-method="filter"
:label="$t('test_track.case.method')"
show-overflow-tooltip>
<template v-slot:default="scope">
@ -72,7 +74,7 @@
<el-table-column
prop="updateTime"
sortable
sortable="custom"
:label="$t('commons.update_time')"
show-overflow-tooltip>
<template v-slot:default="scope">
@ -113,6 +115,7 @@
import MsTableOperator from "../../../common/components/MsTableOperator";
import MsTableOperatorButton from "../../../common/components/MsTableOperatorButton";
import MsTableButton from "../../../common/components/MsTableButton";
import {humpToLine} from "../../../../../common/js/utils";
export default {
name: "TestCaseList",
@ -222,9 +225,18 @@
this.selectIds.clear();
this.$emit('refresh');
},
filter(value, row, column) {
const property = column['property'];
return row[property] === value;
filter(filters) {
if (!this.condition.filters) {
this.condition.filters = {};
}
for(let filter in filters) {
if (filters[filter] && filters[filter].length > 0) {
this.condition.filters[filter] = filters[filter];
} else {
this.condition.filters[filter] = null;
}
}
this.initTableData();
},
showDetail(row, event, column) {
this.$emit('testCaseDetail', row);
@ -250,6 +262,29 @@
},
moveToNode() {
this.$emit('moveToNode', this.selectIds);
},
sort(column) {
column.prop = humpToLine(column.prop);
if (column.order == 'descending') {
column.order = 'desc';
} else {
column.order = 'asc';
}
if (!this.condition.orders) {
this.condition.orders = [];
}
let hasProp = false;
this.condition.orders.forEach(order => {
if (order.name == column.prop) {
order.type = column.order;
hasProp = true;
return;
}
});
if (!hasProp) {
this.condition.orders.push({name: column.prop, type: column.order});
}
this.initTableData();
}
}
}

View File

@ -22,6 +22,8 @@
<el-table
@select-all="handleSelectAll"
@filter-change="filter"
@sort-change="sort"
@select="handleSelectionChange"
row-key="id"
:data="tableData">
@ -37,7 +39,7 @@
<el-table-column
prop="priority"
:filters="priorityFilters"
:filter-method="filter"
column-key="priority"
:label="$t('test_track.case.priority')">
<template v-slot:default="scope">
<priority-table-item :value="scope.row.priority" ref="priority"/>
@ -47,7 +49,7 @@
<el-table-column
prop="type"
:filters="typeFilters"
:filter-method="filter"
column-key="type"
:label="$t('test_track.case.type')"
show-overflow-tooltip>
<template v-slot:default="scope">
@ -58,7 +60,7 @@
<el-table-column
prop="method"
:filters="methodFilters"
:filter-method="filter"
column-key="method"
:label="$t('test_track.case.method')"
show-overflow-tooltip>
<template v-slot:default="scope">
@ -74,7 +76,7 @@
<el-table-column
prop="status"
:filters="statusFilters"
:filter-method="filter"
column-key="status"
:label="$t('test_track.plan_view.execute_result')">
<template v-slot:default="scope">
<status-table-item :value="scope.row.status"/>
@ -125,7 +127,7 @@
import NodeBreadcrumb from '../../../common/NodeBreadcrumb';
import {TokenKey} from '../../../../../../common/js/constants';
import {tableFilter} from '../../../../../../common/js/utils';
import {humpToLine, tableFilter} from '../../../../../../common/js/utils';
import PriorityTableItem from "../../../common/tableItems/planview/PriorityTableItem";
import StatusTableItem from "../../../common/tableItems/planview/StatusTableItem";
import TypeTableItem from "../../../common/tableItems/planview/TypeTableItem";
@ -295,10 +297,10 @@
}
this.initTableData();
},
filter(value, row, column) {
const property = column['property'];
return row[property] === value;
},
// filter(value, row, column) {
// const property = column['property'];
// return row[property] === value;
// },
openTestReport() {
this.$refs.testReporTtemplateList.open();
},
@ -316,6 +318,42 @@
id = this.testPlan.reportId;
}
this.$refs.testCaseReportView.open(id);
},
filter(filters) {
if (!this.condition.filters) {
this.condition.filters = {};
}
for(let filter in filters) {
if (filters[filter] && filters[filter].length > 0) {
this.condition.filters[filter] = filters[filter];
} else {
this.condition.filters[filter] = null;
}
}
this.initTableData();
},
sort(column) {
column.prop = humpToLine(column.prop);
if (column.order == 'descending') {
column.order = 'desc';
} else {
column.order = 'asc';
}
if (!this.condition.orders) {
this.condition.orders = [];
}
let hasProp = false;
this.condition.orders.forEach(order => {
if (order.name == column.prop) {
order.type = column.order;
hasProp = true;
return;
}
});
if (!hasProp) {
this.condition.orders.push({name: column.prop, type: column.order});
}
this.initTableData();
}
}
}

View File

@ -55,3 +55,8 @@ export function mapToJson(strMap){
}
return JSON.stringify(obj);
}
// 驼峰转换下划线
export function humpToLine(name) {
return name.replace(/([A-Z])/g,"_$1").toLowerCase();
}