refactor(测试跟踪): 公共用例库列表不展示自定义字段

--bug=1016140 --user=陈建星 【测试跟踪】新建用例并保存到公共用例库,用例中有自定义字段,公共用例库列表不显示自定义字段的内容 https://www.tapd.cn/55049933/s/1233942
This commit is contained in:
chenjianxing 2022-08-29 15:49:25 +08:00 committed by f2c-ci-robot[bot]
parent e2766007a0
commit e86d09e7eb
15 changed files with 641 additions and 274 deletions

View File

@ -15,4 +15,6 @@ public interface ExtCustomFieldMapper {
List<String> listIds(@Param("request") QueryCustomFieldRequest request);
void batchInsert(@Param("customFields") List<CustomField> customFields);
List<CustomField> getWorkspaceIdSystemFields(@Param("workspaceId") String workspaceId, @Param("scene") String scene);
}

View File

@ -40,8 +40,15 @@
<include refid="queryWhereCondition"/>
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/>
</select>
<select id="getWorkspaceIdSystemFields" resultType="io.metersphere.base.domain.CustomField">
select cf.*
from custom_field cf
left join project p
on cf.project_id = p.id
where p.workspace_id = #{workspaceId} and cf.scene = #{scene}
</select>
<!-- 如果创建了工作空间的字段,就去除全局的该字段-->
<!-- 如果创建了工作空间的字段,就去除全局的该字段-->
<sql id="queryWhereCondition">
<where>
<if test="request.name != null">

View File

@ -0,0 +1,5 @@
package io.metersphere.commons.constants;
public enum CustomFieldScene {
TEST_CASE, ISSUE
}

View File

@ -9,7 +9,6 @@ import io.metersphere.base.domain.*;
import io.metersphere.base.domain.ext.CustomFieldResource;
import io.metersphere.base.mapper.CustomFieldIssuesMapper;
import io.metersphere.base.mapper.CustomFieldMapper;
import io.metersphere.base.mapper.CustomFieldTemplateMapper;
import io.metersphere.base.mapper.ProjectMapper;
import io.metersphere.base.mapper.ext.ExtCustomFieldMapper;
import io.metersphere.commons.constants.CustomFieldType;
@ -235,6 +234,10 @@ public class CustomFieldService {
return new ArrayList<>();
}
public List<CustomField> getWorkspaceIdSystemFields(String workspaceId, String scene) {
return extCustomFieldMapper.getWorkspaceIdSystemFields(workspaceId, scene);
}
public List<CustomFieldResource> getCustomFieldResource(String customFieldsStr) {
List<CustomFieldResource> list = new ArrayList<>();
if (StringUtils.isNotBlank(customFieldsStr)) {

View File

@ -66,7 +66,7 @@ public class TestCaseController {
return PageUtils.setPageInfo(page, testCaseService.listTestCase(request));
}
@PostMapping("/publicList/{goPage}/{pageSize}")
@PostMapping("/public/list/{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);

View File

@ -195,6 +195,8 @@ public class TestCaseService {
@Resource
@Lazy
private TestCaseTemplateService testCaseTemplateService;
@Resource
private CustomFieldService customFieldService;
private ThreadLocal<Integer> importCreateNum = new ThreadLocal<>();
@ -788,10 +790,51 @@ public class TestCaseService {
ServiceUtils.buildVersionInfo(returnList);
ServiceUtils.buildProjectInfo(returnList);
buildUserInfo(returnList);
buildCustomField(returnList);
buildPublicCustomField(request, returnList);
return returnList;
}
private void buildPublicCustomField(QueryTestCaseRequest request, List<TestCaseDTO> returnList) {
Map<String, List<CustomField>> projectFieldMap = customFieldService.getWorkspaceIdSystemFields(request.getWorkspaceId(), CustomFieldScene.TEST_CASE.name())
.stream().collect(Collectors.groupingBy(CustomField::getProjectId));
Map<String, Map<String, String>> projectStatusOptionMap = new HashMap<>();
Map<String, Map<String, String>> projectPriorityOptionMap = new HashMap<>();
projectFieldMap.forEach((projectId, fields) -> {
Map<String, String> statusOptionMap = Optional.ofNullable(projectStatusOptionMap.get(projectId)).orElse(new HashMap<>());
Map<String, String> priorityOptionMap = Optional.ofNullable(projectPriorityOptionMap.get(projectId)).orElse(new HashMap<>());
for (CustomField field : fields) {
if (field.getName().equals(TestCaseImportFiled.STATUS.getFiledLangMap().get(Locale.SIMPLIFIED_CHINESE))) {
if (StringUtils.isNotBlank(field.getOptions())) {
statusOptionMap = JSONArray.parseArray(field.getOptions(), CustomFieldOption.class)
.stream()
.collect(Collectors.toMap(CustomFieldOption::getValue, CustomFieldOption::getText));
}
}
if (field.getName().equals(TestCaseImportFiled.PRIORITY.getFiledLangMap().get(Locale.SIMPLIFIED_CHINESE))) {
if (StringUtils.isNotBlank(field.getOptions())) {
priorityOptionMap = JSONArray.parseArray(field.getOptions(), CustomFieldOption.class)
.stream()
.collect(Collectors.toMap(CustomFieldOption::getValue, CustomFieldOption::getText));
}
}
}
projectStatusOptionMap.put(projectId, statusOptionMap);
projectPriorityOptionMap.put(projectId, priorityOptionMap);
});
returnList.forEach(testCase -> {
String status = projectStatusOptionMap.get(testCase.getProjectId()).get(testCase.getStatus());
String priority = projectPriorityOptionMap.get(testCase.getProjectId()).get(testCase.getStatus());
if (StringUtils.isNotBlank(status)) {
testCase.setStatus(status);
}
if (StringUtils.isNotBlank(priority)) {
testCase.setPriority(priority);
}
});
}
public void setDefaultOrder(QueryTestCaseRequest request) {
List<OrderRequest> orders = ServiceUtils.getDefaultSortOrder(request.getOrders());

View File

@ -155,6 +155,9 @@ export default {
}
}
}
if (this.data.type.indexOf("member") < 0) {
return;
}
getProjectMemberOption((data) => {
this.memberOptions = data;
if (this.data.name === '责任人' && this.data.system && this.isTemplateEdit) {

View File

@ -55,8 +55,6 @@
:version-enable="versionEnable"
@testCaseEdit="editTestCase"
@testCaseCopy="copyTestCase"
@getTrashList="getTrashList"
@getPublicList="getPublicList"
@refresh="refreshTrashNode"
@refreshAll="refreshAll"
@setCondition="setCondition"
@ -67,26 +65,20 @@
</el-tab-pane>
<el-tab-pane name="public" v-if="publicEnable" :label="$t('project.case_public')">
<div style="height: 6px;"></div>
<test-case-list
:checkRedirectID="checkRedirectID"
:isRedirectEdit="isRedirectEdit"
<public-test-case-list
:tree-nodes="treeNodes"
:trash-enable="false"
:public-enable="true"
:version-enable="versionEnable"
@refreshTable="refresh"
@testCaseEdit="editTestCase"
@testCaseEditShow="editTestCaseShow"
@testCaseCopy="copyTestCase"
@getTrashList="getTrashList"
@getPublicList="getPublicList"
@refresh="refresh"
@refreshAll="refreshAll"
@refreshPublic="refreshPublic"
@setCondition="setCondition"
@search="refreshTreeByCaseFilter"
ref="testCasePublicList">
</test-case-list>
</public-test-case-list>
</el-tab-pane>
<el-tab-pane name="default" :label="$t('api_test.definition.case_title')">
<ms-tab-button
@ -233,6 +225,7 @@ import TestCaseEditShow from "@/business/components/track/case/components/TestCa
import {PROJECT_ID} from "@/common/js/constants";
import TestCasePublicNodeTree from "@/business/components/track/module/TestCasePublicNodeTree";
import TestCaseTrashNodeTree from "@/business/components/track/module/TestCaseTrashNodeTree";
import PublicTestCaseList from "@/business/components/track/case/components/public/PublicTestCaseList";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const VersionSelect = requireComponent.keys().length > 0 ? requireComponent("./version/VersionSelect.vue") : {};
@ -240,6 +233,7 @@ const VersionSelect = requireComponent.keys().length > 0 ? requireComponent("./v
export default {
name: "TestCase",
components: {
PublicTestCaseList,
TestCaseTrashNodeTree,
TestCasePublicNodeTree,
IsChangeConfirm,

View File

@ -50,14 +50,6 @@
<span v-for="(item, index) in fields" :key="index">
<ms-table-column
prop="projectName"
:fields-width="fieldsWidth"
:label="$t('test_track.case.project')"
v-if="publicEnable && item.id === 'projectName'"
min-width="150px">
</ms-table-column>
<ms-table-column
v-if="!customNum"
:field="item"
@ -144,7 +136,7 @@
:label="$t('project.version.name')"
:field="item"
:fields-width="fieldsWidth"
:filters="!publicEnable ? versionFilters : null"
:filters="versionFilters"
min-width="100px"
prop="versionId">
<template v-slot:default="scope">
@ -157,31 +149,14 @@
:field="item"
:fields-width="fieldsWidth"
:label="$t('test_track.case.module')"
v-if="!publicEnable"
min-width="150px">
</ms-table-column>
<ms-table-column
prop="updateTime"
sortable
:field="item"
:fields-width="fieldsWidth"
:label="$t('commons.update_time')"
min-width="150px">
<template v-slot:default="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template>
</ms-table-column>
<ms-table-column prop="createTime"
:field="item"
:fields-width="fieldsWidth"
:label="$t('commons.create_time')"
sortable
min-width="150px">
<template v-slot:default="scope">
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
</template>
</ms-table-column>
<ms-update-time-column :field="item"
:fields-width="fieldsWidth"/>
<ms-create-time-column :field="item"
:fields-width="fieldsWidth"/>
<ms-table-column v-for="field in testCaseTemplate.customFields" :key="field.id"
:filters="getCustomFieldFilter(field)"
@ -215,8 +190,7 @@
<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" :public-enable="publicEnable"
@copyPublic="copyPublic"/>
<batch-move @refresh="refresh" @moveSave="moveSave" ref="testBatchMove"/>
<relate-demand ref="relateDemand" @batchRelate="_batchRelateDemand"/>
@ -232,17 +206,10 @@
<script>
import MsTableHeaderSelectPopover from "@/business/components/common/components/table/MsTableHeaderSelectPopover";
import TestCaseImport from './import/TestCaseImport';
import MsTablePagination from '../../../../components/common/pagination/TablePagination';
import NodeBreadcrumb from '../../common/NodeBreadcrumb';
import MsTableHeader from '../../../../components/common/components/MsTableHeader';
import PriorityTableItem from "../../common/tableItems/planview/PriorityTableItem";
import TypeTableItem from "../../common/tableItems/planview/TypeTableItem";
import MethodTableItem from "../../common/tableItems/planview/MethodTableItem";
import MsTableOperator from "../../../common/components/MsTableOperator";
import MsTableOperatorButton from "../../../common/components/MsTableOperatorButton";
import MsTableButton from "../../../common/components/MsTableButton";
import {TEST_CASE_CONFIGS} from "../../../common/components/search/search-components";
import BatchEdit from "./BatchEdit";
import {TEST_CASE_LIST} from "@/common/js/constants";
@ -265,11 +232,9 @@ import {
initCondition,
parseCustomFilesForList,
} from "@/common/js/tableUtils";
import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate";
import PlanStatusTableItem from "@/business/components/track/common/tableItems/plan/PlanStatusTableItem";
import {
getCurrentProjectID,
getCurrentUserId,
getCurrentWorkspaceId,
getUUID,
hasLicense, operationConfirm,
@ -284,7 +249,6 @@ import {SYSTEM_FIELD_NAME_MAP} from "@/common/js/table-constants";
import TestCasePreview from "@/business/components/track/case/components/TestCasePreview";
import {editTestCaseOrder} from "@/network/testCase";
import {getGraphByCondition} from "@/network/graph";
import MsTableAdvSearchBar from "@/business/components/common/components/search/MsTableAdvSearchBar";
import ListItemDeleteConfirm from "@/business/components/common/components/ListItemDeleteConfirm";
import {
generateColumnKey,
@ -294,6 +258,8 @@ import MsSearch from "@/business/components/common/components/search/MsSearch";
import RelateDemand from "@/business/components/track/case/components/RelateDemand";
import TestCaseReviewStatusTableItem from "@/business/components/track/common/tableItems/TestCaseReviewStatusTableItem";
import TestPlanCaseStatusTableItem from "@/business/components/track/common/tableItems/TestPlanCaseStatusTableItem";
import MsUpdateTimeColumn from "@/business/components/common/components/table/MsUpdateTimeColumn";
import MsCreateTimeColumn from "@/business/components/common/components/table/MsCreateTimeColumn";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const relationshipGraphDrawer = requireComponent.keys().length > 0 ? requireComponent("./graph/RelationshipGraphDrawer.vue") : {};
@ -301,29 +267,22 @@ const relationshipGraphDrawer = requireComponent.keys().length > 0 ? requireComp
export default {
name: "TestCaseList",
components: {
MsCreateTimeColumn,
MsUpdateTimeColumn,
TestPlanCaseStatusTableItem,
TestCaseReviewStatusTableItem,
RelateDemand,
MsSearch,
ListItemDeleteConfirm,
MsTableAdvSearchBar,
TestCasePreview,
BatchMove,
MsTableColumn,
MsTable,
PlanStatusTableItem,
HeaderLabelOperate,
MsTableHeaderSelectPopover,
MsTableButton,
MsTableOperatorButton,
MsTableOperator,
MethodTableItem,
TypeTableItem,
PriorityTableItem,
TestCaseImport,
MsTablePagination,
NodeBreadcrumb,
MsTableHeader,
BatchEdit,
StatusTableItem,
ReviewStatus,
@ -337,8 +296,6 @@ export default {
type: TEST_CASE_LIST,
tableHeaderKey: "TRACK_TEST_CASE",
screenHeight: 'calc(100vh - 185px)',
tableLabel: [],
deletePath: "/test/case/delete",
enableOrderDrag: true,
isMoveBatch: true,
condition: {
@ -348,31 +305,6 @@ export default {
},
versionFilters: [],
graphData: {},
priorityFilters: [
{text: 'P0', value: 'P0'},
{text: 'P1', value: 'P1'},
{text: 'P2', value: 'P2'},
{text: 'P3', value: 'P3'}
],
methodFilters: [
{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'}
],
reviewStatusFilters: [
{text: this.$t('test_track.review.prepare'), value: 'Prepare'},
{text: this.$t('test_track.review.pass'), value: 'Pass'},
{text: this.$t('test_track.review.un_pass'), value: 'UnPass'},
],
statusFilters: [
{text: this.$t('test_track.case.status_prepare'), value: 'Prepare'},
{text: this.$t('test_track.case.status_running'), value: 'Underway'},
{text: this.$t('test_track.case.status_finished'), value: 'Completed'},
],
batchButtons: [],
simpleButtons: [
{
@ -413,17 +345,6 @@ export default {
permissions: ['PROJECT_TRACK_CASE:READ+BATCH_ADD_PUBLIC'],
}
],
publicButtons: [
{
name: this.$t('test_track.case.batch_copy'),
handleClick: this.handleBatchMove,
permissions: ['PROJECT_TRACK_CASE:READ+BATCH_COPY']
}, {
name: this.$t('test_track.case.batch_delete_case'),
handleClick: this.handleDeleteBatchToPublic,
permissions: ['PROJECT_TRACK_CASE:READ+BATCH_DELETE'],
},
],
trashButtons: [
{
name: this.$t('commons.reduction'),
@ -453,30 +374,6 @@ export default {
permissions: ['PROJECT_TRACK_CASE:READ+DELETE']
}
],
publicOperators: [
{
tip: this.$t('commons.view'), icon: "el-icon-view",
exec: this.handleEditShow,
permissions: ['PROJECT_TRACK_CASE:READ'],
},
{
tip: this.$t('commons.edit'), icon: "el-icon-edit",
exec: this.handleEditPublic,
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'),
@ -512,10 +409,6 @@ export default {
type: Boolean,
default: false,
},
publicEnable: {
type: Boolean,
default: false,
},
currentVersion: String,
versionEnable: {
type: Boolean,
@ -546,10 +439,6 @@ export default {
}
},
created: function () {
if (this.publicEnable) {
this.tableHeaderKey = 'TRACK_PUBLIC_TEST_CASE';
this.fields = getCustomTableHeader(this.tableHeaderKey);
}
this.getTemplateField();
this.$emit('setCondition', this.condition);
this.initTableData();
@ -564,9 +453,6 @@ 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;
@ -623,21 +509,6 @@ export default {
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 = [];
}
},
currentVersion() {
this.condition.versionId = this.currentVersion;
this.initTableData();
@ -761,10 +632,6 @@ export default {
}
});
},
customHeader() {
const list = deepClone(this.tableLabel);
this.$refs.headerCustom.open(list);
},
getSelectDataRange() {
let routeParamObj = this.$route.params.paramObj;
this.selectDataRange = 'all';
@ -785,7 +652,7 @@ export default {
this.condition.planId = this.planId;
}
if (!this.trashEnable && !this.publicEnable) {
if (!this.trashEnable) {
if (this.selectNodeIds && this.selectNodeIds.length > 0) {
if (!this.selectNode || this.selectNode.data.id !== 'root') {
// root
@ -841,11 +708,6 @@ export default {
this.condition.projectId = this.projectId;
this.$emit('setCondition', this.condition);
let url = '/test/case/list';
if (this.publicEnable) {
url = '/test/case/publicList';
this.condition.casePublic = true;
this.condition.workspaceId = getCurrentWorkspaceId();
}
this.page.result = this.$post(this.buildPagePath(url), this.condition, response => {
let data = response.data;
this.page.total = data.itemCount;
@ -879,38 +741,11 @@ export default {
this.$emit('testCaseEdit');
},
handleEdit(testCase) {
if (this.publicEnable) {
return;
} else {
this.$get('test/case/get/' + testCase.id, response => {
let testCase = response.data;
testCase.trashEnable = this.trashEnable;
this.$emit('testCaseEdit', testCase);
});
}
},
handleEditPublic(testCase, column) {
if (column.label !== this.$t('test_track.case.case_desc')) {
this.$get('test/case/get/' + testCase.id, response => {
let testCase = response.data;
this.$emit('testCaseEdit', testCase);
});
}
},
handleEditShow(testCase, column) {
if (column.label !== this.$t('test_track.case.case_desc')) {
this.$get('test/case/get/' + testCase.id, response => {
let testCase = response.data;
this.$emit('testCaseEditShow', testCase);
});
}
},
isPublic(testCase) {
if ((testCase.maintainer && testCase.maintainer === getCurrentUserId()) || (testCase.createUser && testCase.createUser === getCurrentUserId())) {
return false;
}
return true;
this.$get('test/case/get/' + testCase.id, response => {
let testCase = response.data;
testCase.trashEnable = this.trashEnable;
this.$emit('testCaseEdit', testCase);
});
},
getCase(id) {
this.$refs.testCasePreview.open();
@ -932,10 +767,6 @@ 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;
@ -1173,16 +1004,6 @@ export default {
this.refresh();
});
},
handleDeleteBatchToPublic() {
operationConfirm(this, this.$t('test_track.case.delete_confirm'), () => {
let param = buildBatchParam(this, this.$refs.table.selectIds);
this.$post('/test/case/batch/movePublic/deleteToGc', param, () => {
this.$refs.table.clear();
this.$emit("refreshPublic");
this.$success(this.$t('commons.delete_success'));
});
});
},
handleBatchMove() {
this.isMoveBatch = true;
this.$refs.testBatchMove.open(this.treeNodes, this.$refs.table.selectIds, this.moduleOptions);
@ -1194,35 +1015,15 @@ export default {
_handleDeleteVersion(testCase, deleteCurrentVersion) {
//
if (deleteCurrentVersion) {
if (this.publicEnable) {
this.$get('/test/case/deletePublic/' + testCase.versionId + '/' + testCase.refId, () => {
this.$success(this.$t('commons.delete_success'));
this.$refs.apiDeleteConfirm.close();
this.$emit("refreshPublic");
});
} else {
this.$get('/test/case/delete/' + testCase.versionId + '/' + testCase.refId, () => {
this.$success(this.$t('commons.delete_success'));
this.$refs.apiDeleteConfirm.close();
this.$emit("refreshAll");
});
}
}
//
else {
if (this.publicEnable) {
let param = buildBatchParam(this, this.$refs.table.selectIds);
param.ids.push(testCase.id);
this.$post('/test/case/batch/movePublic/deleteToGc', param, () => {
this.$success(this.$t('commons.delete_success'));
this.$refs.apiDeleteConfirm.close();
this.$emit("refreshPublic");
});
} else {
this._handleDeleteToGc(testCase);
this.$get('/test/case/delete/' + testCase.versionId + '/' + testCase.refId, () => {
this.$success(this.$t('commons.delete_success'));
this.$refs.apiDeleteConfirm.close();
}
this.$emit("refreshAll");
});
} else {
//
this._handleDeleteToGc(testCase);
this.$refs.apiDeleteConfirm.close();
}
},
checkSelected() {
@ -1250,17 +1051,6 @@ export default {
this.refresh();
});
},
copyPublic(param) {
param.condition = this.condition;
param.projectId = this.projectId;
param.condition.projectId = null;
param.condition.ids = null;
this.page.result = this.$post('/test/case/batch/copy/public', param, () => {
this.$success(this.$t('commons.save_success'));
this.$refs.testBatchMove.close();
this.refresh();
});
},
getVersionOptions() {
if (hasLicense()) {
this.$get('/project/version/get-project-versions/' + getCurrentProjectID(), response => {
@ -1277,31 +1067,6 @@ export default {
<style scoped>
.table-page {
padding-top: 10px;
margin-right: -9px;
float: right;
}
.operate-button {
float: right;
}
.operate-button > div {
display: inline-block;
margin-left: 10px;
}
.search-input {
float: right;
width: 300px;
}
.search {
margin-left: 10px;
width: 240px;
}
.el-table {
cursor: pointer;
}

View File

@ -0,0 +1,533 @@
<template>
<span>
<ms-search
:condition.sync="condition"
@search="search">
</ms-search>
<ms-table
v-loading="page.result.loading"
operator-width="170px"
row-key="id"
:data="page.data"
:condition="condition"
:total="page.total"
:page-size.sync="page.pageSize"
:operators="operators"
:screen-height="screenHeight"
:batch-operators="batchButtons"
:remember-order="true"
:row-order-group-id="projectId"
:row-order-func="editTestCaseOrder"
:fields.sync="fields"
:field-key="tableHeaderKey"
@handlePageChange="initTableData"
@order="initTableData"
@filter="search"
ref="table">
<span v-for="(item, index) in fields" :key="index">
<ms-table-column
prop="projectName"
:fields-width="fieldsWidth"
:label="$t('test_track.case.project')"
v-if="item.id === 'projectName'"
min-width="150px">
</ms-table-column>
<ms-table-column
v-if="!customNum"
:field="item"
:fields-width="fieldsWidth"
prop="num"
sortable
:label="$t('commons.id')"
min-width="80">
<template v-slot:default="scope">
<el-tooltip :content="$t('commons.edit')">
<a style="cursor:pointer" @click="handleEdit(scope.row)"> {{ scope.row.num }} </a>
</el-tooltip>
</template>
</ms-table-column>
<ms-table-column
v-if="item.id === 'num' && customNum"
:field="item"
:fields-width="fieldsWidth"
prop="customNum"
sortable
:label="$t('commons.id')"
min-width="80">
<template v-slot:default="scope">
<el-tooltip :content="$t('commons.edit')">
<a style="cursor:pointer" @click="handleEdit(scope.row)"> {{ scope.row.num }} </a>
</el-tooltip>
</template>
</ms-table-column>
<ms-table-column
prop="name"
sortable
:field="item"
:fields-width="fieldsWidth"
:label="$t('commons.name')"
min-width="120"
/>
<ms-table-column :label="$t('test_track.case.case_desc')" prop="desc" :field="item" min-width="100px">
<template v-slot:default="scope">
<el-link @click.stop="getCase(scope.row.id)" style="color:#783887;">{{ $t('commons.preview') }}</el-link>
</template>
</ms-table-column>
<ms-table-column
prop="createUser"
min-width="120"
:field="item"
:fields-width="fieldsWidth"
:label="$t('commons.create_user')"
:filters="userFilter">
<template v-slot:default="scope">
{{ scope.row.createName }}
</template>
</ms-table-column>
<ms-table-column
prop="status"
min-width="120"
:field="item"
:fields-width="fieldsWidth"
:label="$t('test_track.case.case_status')">
<template v-slot:default="scope">
{{ statusMap[scope.row.status] ? statusMap[scope.row.status] : $t(scope.row.status) }}
</template>
</ms-table-column>
<ms-table-column
sortable
prop="priority"
min-width="120"
:field="item"
:fields-width="fieldsWidth"
:label="$t('test_track.case.priority')"/>
<test-case-review-status-table-item
:field="item"
:fields-width="fieldsWidth"/>
<test-plan-case-status-table-item
prop="lastExecuteResult"
:field="item"
:fields-width="fieldsWidth"/>
<ms-table-column
prop="tags"
:field="item"
:fields-width="fieldsWidth"
:label="$t('commons.tag')"
min-width="80">
<template v-slot:default="scope">
<ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain"
:show-tooltip="scope.row.tags.length===1&&itemName.length*12<=80"
:content="itemName" style="margin-left: 0px; margin-right: 2px"/>
<span/>
</template>
</ms-table-column>
<ms-table-column
v-if="versionEnable"
:label="$t('project.version.name')"
:field="item"
:fields-width="fieldsWidth"
min-width="100px"
prop="versionId">
<template v-slot:default="scope">
<span>{{ scope.row.versionName }}</span>
</template>
</ms-table-column>
<ms-update-time-column :field="item"
:fields-width="fieldsWidth"/>
<ms-create-time-column :field="item"
:fields-width="fieldsWidth"/>
</span>
</ms-table>
<ms-table-pagination :change="initTableData" :current-page.sync="page.currentPage" :page-size.sync="page.pageSize"
:total="page.total"/>
<test-case-preview ref="testCasePreview" :loading="rowCaseResult.loading"/>
<list-item-delete-confirm
@handleDelete="_handleDeleteVersion"
ref="apiDeleteConfirm"/>
<batch-move :public-enable="true"
@refresh="refresh"
@copyPublic="copyPublic"
ref="testBatchMove"/>
</span>
</template>
<script>
import MsTablePagination from '@/business/components/common/pagination/TablePagination';
import TypeTableItem from "@/business/components/track/common/tableItems/planview/TypeTableItem";
import {TEST_CASE_CONFIGS} from "@/business/components/common/components/search/search-components";
import {TEST_CASE_LIST} from "@/common/js/constants";
import StatusTableItem from "@/business/components/track/common/tableItems/planview/StatusTableItem";
import ReviewStatus from "@/business/components/track/case/components/ReviewStatus";
import MsTag from "@/business/components/common/components/MsTag";
import {
buildBatchParam,
deepClone,
getCustomTableHeader,
getCustomTableWidth,
getLastTableSortField,
getPageInfo,
initCondition,
} from "@/common/js/tableUtils";
import PlanStatusTableItem from "@/business/components/track/common/tableItems/plan/PlanStatusTableItem";
import {
getCurrentProjectID,
getCurrentUserId,
getCurrentWorkspaceId, getUUID, hasLicense,
operationConfirm,
parseTag
} from "@/common/js/utils";
import {getProjectMemberUserFilter} from "@/network/user";
import MsTable from "@/business/components/common/components/table/MsTable";
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
import {TEST_CASE_STATUS_MAP} from "@/common/js/table-constants";
import TestCasePreview from "@/business/components/track/case/components/TestCasePreview";
import {editTestCaseOrder} from "@/network/testCase";
import MsSearch from "@/business/components/common/components/search/MsSearch";
import TestCaseReviewStatusTableItem from "@/business/components/track/common/tableItems/TestCaseReviewStatusTableItem";
import TestPlanCaseStatusTableItem from "@/business/components/track/common/tableItems/TestPlanCaseStatusTableItem";
import MsCreateTimeColumn from "@/business/components/common/components/table/MsCreateTimeColumn";
import MsUpdateTimeColumn from "@/business/components/common/components/table/MsUpdateTimeColumn";
import ListItemDeleteConfirm from "@/business/components/common/components/ListItemDeleteConfirm";
import BatchMove from "@/business/components/track/case/components/BatchMove";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const relationshipGraphDrawer = requireComponent.keys().length > 0 ? requireComponent("./graph/RelationshipGraphDrawer.vue") : {};
export default {
name: "PublicTestCaseList",
components: {
BatchMove,
ListItemDeleteConfirm,
MsUpdateTimeColumn,
MsCreateTimeColumn,
MsTag,
TestPlanCaseStatusTableItem,
TestCaseReviewStatusTableItem,
MsSearch,
TestCasePreview,
MsTableColumn,
MsTable,
PlanStatusTableItem,
TypeTableItem,
MsTablePagination,
StatusTableItem,
ReviewStatus,
},
data() {
return {
addPublic: false,
type: TEST_CASE_LIST,
tableHeaderKey: "TRACK_PUBLIC_TEST_CASE",
screenHeight: 'calc(100vh - 185px)',
condition: {
components: TEST_CASE_CONFIGS,
filters: {},
custom: false,
},
batchButtons: [
{
name: this.$t('test_track.case.batch_copy'),
handleClick: this.handleBatchCopy,
permissions: ['PROJECT_TRACK_CASE:READ+BATCH_COPY']
},
{
name: this.$t('test_track.case.batch_delete_case'),
handleClick: this.handleDeleteBatchToPublic,
permissions: ['PROJECT_TRACK_CASE:READ+BATCH_DELETE'],
},
],
operators: [
{
tip: this.$t('commons.view'), icon: "el-icon-view",
exec: this.handleEditShow,
permissions: ['PROJECT_TRACK_CASE:READ'],
},
{
tip: this.$t('commons.edit'), icon: "el-icon-edit",
exec: this.handleEdit,
permissions: ['PROJECT_TRACK_CASE:READ+EDIT'],
isDisable: !this.isOwner
},
{
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.remove'), icon: "el-icon-delete", type: "danger",
exec: this.handleDeleteToGc,
permissions: ['PROJECT_TRACK_CASE:READ+DELETE'],
isDisable: !this.isOwner
}
],
page: getPageInfo(),
fields: getCustomTableHeader('TRACK_PUBLIC_TEST_CASE'),
fieldsWidth: getCustomTableWidth('TRACK_PUBLIC_TEST_CASE'),
rowCase: {},
rowCaseResult: {},
userFilter: []
};
},
props: {
treeNodes: {
type: Array
},
publicEnable: {
type: Boolean,
default: false,
},
currentVersion: String,
versionEnable: {
type: Boolean,
default: false
}
},
computed: {
projectId() {
return getCurrentProjectID();
},
selectNodeIds() {
return this.$store.state.testCaseSelectNodeIds;
},
selectNode() {
return this.$store.state.testCaseSelectNode;
},
moduleOptions() {
return this.$store.state.testCaseModuleOptions;
},
customNum() {
return this.$store.state.currentProjectIsCustomNum;
},
statusMap() {
return TEST_CASE_STATUS_MAP;
},
editTestCaseOrder() {
return editTestCaseOrder;
},
currentUser() {
return getCurrentUserId();
}
},
created: function () {
this.$emit('setCondition', this.condition);
this.initTableData();
getProjectMemberUserFilter((data) => {
this.userFilter = data;
});
// tab
this.condition.versionId = this.currentVersion;
},
watch: {
selectNodeIds() {
this.page.currentPage = 1;
initCondition(this.condition, false);
this.initTableData();
},
condition() {
this.$emit('setCondition', this.condition);
},
currentVersion() {
this.condition.versionId = this.currentVersion;
this.initTableData();
},
},
methods: {
initTableData(nodeIds) {
this.condition.nodeIds = [];
initCondition(this.condition, this.condition.selectAll);
this.condition.orders = getLastTableSortField(this.tableHeaderKey);
this.condition.versionId = this.currentVersion || null;
this.condition.filters.reviewStatus = ["Prepare", "Pass", "UnPass"];
if (nodeIds && Array.isArray(nodeIds) && nodeIds.length > 0) {
this.condition.nodeIds = nodeIds;
this.condition.workspaceId = getCurrentWorkspaceId();
}
this.getData();
},
getData() {
if (this.projectId) {
this.condition.projectId = this.projectId;
this.$emit('setCondition', this.condition);
let url = '/test/case/public/list';
this.condition.casePublic = true;
this.condition.workspaceId = getCurrentWorkspaceId();
this.page.result = this.$post(this.buildPagePath(url), this.condition, response => {
let data = response.data;
this.page.total = data.itemCount;
this.page.data = data.listObject;
parseTag(this.page.data);
});
}
},
search() {
//
this.page.currentPage = 1;
this.initTableData();
this.$emit('search');
},
buildPagePath(path) {
return path + "/" + this.page.currentPage + "/" + this.page.pageSize;
},
handleEdit(testCase) {
let TestCaseData = this.$router.resolve({
path: '/track/case/all',
query: {
redirectID: getUUID(),
dataType: "testCase",
dataSelectRange: testCase.id,
projectId: testCase.projectId
}
});
window.open(TestCaseData.href, '_blank');
},
handleEditShow(testCase, column) {
if (column.label !== this.$t('test_track.case.case_desc')) {
this.$get('test/case/get/' + testCase.id, response => {
let testCase = response.data;
this.$emit('testCaseEditShow', testCase);
});
}
},
handleDeleteToGc(testCase) {
this.$get('/test/case/versions/' + testCase.id, response => {
if (hasLicense() && this.versionEnable && response.data.length > 1) {
//
this.$refs.apiDeleteConfirm.open(testCase, this.$t('test_track.case.delete_confirm'));
} else {
operationConfirm(this, this.$t('test_track.case.delete_confirm') + '\'' + testCase.name + '\'', () => {
this._handleDeleteVersion(testCase, false);
});
}
});
},
_handleDeleteVersion(testCase, deleteCurrentVersion) {
if (deleteCurrentVersion) {
//
this.$get('/test/case/deletePublic/' + testCase.versionId + '/' + testCase.refId, () => {
this.$success(this.$t('commons.delete_success'));
this.$refs.apiDeleteConfirm.close();
this.$emit("refreshPublic");
});
} else {
//
let param = buildBatchParam(this, this.$refs.table.selectIds);
param.ids.push(testCase.id);
this.$post('/test/case/batch/movePublic/deleteToGc', param, () => {
this.$success(this.$t('commons.delete_success'));
this.$refs.apiDeleteConfirm.close();
this.$emit("refreshPublic");
});
}
},
isOwner(testCase) {
return testCase.maintainer === this.currentUser || testCase.createUser === this.currentUser;
},
getCase(id) {
this.$refs.testCasePreview.open();
this.rowCaseResult.loading = true;
this.rowCaseResult = this.$get('test/case/get/step/' + id, response => {
this.rowCase = response.data;
this.rowCase.steps = JSON.parse(this.rowCase.steps);
if (!this.rowCase.steps || this.rowCase.length < 1) {
this.rowCase.steps = [{
num: 1,
desc: '',
result: ''
}];
}
if (!this.rowCase.stepModel) {
this.rowCase.stepModel = "STEP";
}
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);
},
refresh() {
this.$refs.table.clear();
this.$emit('refreshAll');
},
refreshAll() {
this.$refs.table.clear();
this.$emit('refreshAll');
},
handleDeleteBatchToPublic() {
operationConfirm(this, this.$t('test_track.case.delete_confirm'), () => {
let param = buildBatchParam(this, this.$refs.table.selectIds);
this.$post('/test/case/batch/movePublic/deleteToGc', param, () => {
this.$refs.table.clear();
this.$emit("refreshPublic");
this.$success(this.$t('commons.delete_success'));
});
});
},
handleBatchCopy() {
this.$refs.testBatchMove.open(this.treeNodes, this.$refs.table.selectIds, this.moduleOptions);
},
bathCopySave(param) {
param.condition = this.condition;
param.projectId = this.projectId;
this.page.result = this.$post('/test/case/batch/copy', param, () => {
this.$success(this.$t('commons.save_success'));
this.$refs.testBatchMove.close();
this.refresh();
});
},
copyPublic(param) {
param.condition = this.condition;
param.projectId = this.projectId;
param.condition.projectId = null;
param.condition.ids = null;
this.page.result = this.$post('/test/case/batch/copy/public', param, () => {
this.$success(this.$t('commons.save_success'));
this.$refs.testBatchMove.close();
this.refresh();
});
},
}
};
</script>
<style scoped>
.el-table {
cursor: pointer;
}
.el-tag {
margin-left: 10px;
}
/deep/ .el-table {
overflow: auto;
}
</style>

View File

@ -233,6 +233,8 @@ export let CUSTOM_TABLE_HEADER = {
TRACK_PUBLIC_TEST_CASE: [
{id: 'num', key: '1', label: 'commons.id'},
{id: 'name', key: '2', label: 'commons.name'},
{id: 'status', key: 'c', label: 'test_track.case.case_status'},
{id: 'priority', key: 'd', label: 'test_track.case.priority'},
{id: 'reviewStatus', key: '3', label: 'test_track.case.status'},
{id: 'tags', key: '4', label: 'commons.tag'},
{id: 'versionId', key: 'b', label: 'project.version.name', xpack: true},

View File

@ -186,3 +186,10 @@ export const PROJECT_GROUP_SCOPE = {
'PERFORMANCE': 'permission.other.performance',
'REPORT': 'permission.other.report'
}
export const TEST_CASE_STATUS_MAP = {
'Prepare': i18n.t('test_track.plan.plan_status_prepare'),
'Underway': i18n.t('test_track.plan.plan_status_running'),
'Completed': i18n.t('test_track.plan.plan_status_completed'),
'Trash': i18n.t('test_track.plan.plan_status_trash')
}

View File

@ -72,6 +72,7 @@ export default {
edit_case: "Edit case",
view_case: "Test case",
no_project: "There is no project in this workspace, please create the project first",
case_status: "Status",
priority: "Priority",
type: "Type",
method: "Method",

View File

@ -64,6 +64,7 @@ export default {
edit_case: "编辑用例",
view_case: "查看用例",
no_project: "该工作空间下无项目,请先创建项目",
case_status: "用例状态",
priority: "用例等级",
type: "类型",
method: "测试方式",

View File

@ -64,6 +64,7 @@ export default {
edit_case: "編輯用例",
view_case: "查看用例",
no_project: "該工作空間下無項目,請先創建項目",
case_status: "用例狀態",
priority: "用例等級",
type: "類型",
method: "測試方式",