diff --git a/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java b/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java index 83f0d324cc..dd272859c1 100644 --- a/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java +++ b/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java @@ -41,6 +41,13 @@ public class ApiDefinitionController { return PageUtils.setPageInfo(page, apiDefinitionService.list(request)); } + @PostMapping("/list/relevance/{goPage}/{pageSize}") + public Pager> listRelevance(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiDefinitionRequest request) { + Page page = PageHelper.startPage(goPage, pageSize, true); + request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId()); + return PageUtils.setPageInfo(page, apiDefinitionService.listRelevance(request)); + } + @PostMapping("/list/all") public List list(@RequestBody ApiDefinitionRequest request) { return apiDefinitionService.list(request); diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionRequest.java b/backend/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionRequest.java index 2a3cb83eea..9c18000c7d 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionRequest.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionRequest.java @@ -20,6 +20,7 @@ public class ApiDefinitionRequest { private String name; private String workspaceId; private String userId; + private String planId; private boolean recent = false; private List orders; private List filters; diff --git a/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java b/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java index 8be3f760f7..4ce1a57eb0 100644 --- a/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java +++ b/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java @@ -283,6 +283,12 @@ public class Swagger2Parser extends ApiImportAbstractParser { } else { jsonObject.put(key, new ArrayList<>()); } + } else if (value instanceof RefProperty) { + RefProperty refProperty = (RefProperty) value; + String simpleRef = refProperty.getSimpleRef(); + refSet.add(simpleRef); + Model model = definitions.get(simpleRef); + jsonObject.put(key, getBodyParameters(model.getProperties(), refSet)); } else { jsonObject.put(key, getDefaultValueByPropertyType(value)); } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java index 3ec55f5d43..07f30a8a03 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java @@ -79,23 +79,7 @@ public class ApiDefinitionService { public List list(ApiDefinitionRequest request) { request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders())); List resList = extApiDefinitionMapper.list(request); - if (!resList.isEmpty()) { - List ids = resList.stream().map(ApiDefinitionResult::getId).collect(Collectors.toList()); - List results = extApiDefinitionMapper.selectByIds(ids); - Map resultMap = results.stream().collect(Collectors.toMap(ApiComputeResult::getApiDefinitionId, Function.identity())); - for (ApiDefinitionResult res : resList) { - ApiComputeResult compRes = resultMap.get(res.getId()); - if (compRes != null) { - res.setCaseTotal(compRes.getCaseTotal()); - res.setCasePassingRate(compRes.getPassRate()); - res.setCaseStatus(compRes.getStatus()); - } else { - res.setCaseTotal("-"); - res.setCasePassingRate("-"); - res.setCaseStatus("-"); - } - } - } + calculateResult(resList); return resList; } @@ -517,4 +501,31 @@ public class ApiDefinitionService { } extApiDefinitionMapper.removeToGc(apiIds); } + + public List listRelevance(ApiDefinitionRequest request) { + request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders())); + List resList = extApiDefinitionMapper.listRelevance(request); + calculateResult(resList); + return resList; + } + + public void calculateResult(List resList) { + if (!resList.isEmpty()) { + List ids = resList.stream().map(ApiDefinitionResult::getId).collect(Collectors.toList()); + List results = extApiDefinitionMapper.selectByIds(ids); + Map resultMap = results.stream().collect(Collectors.toMap(ApiComputeResult::getApiDefinitionId, Function.identity())); + for (ApiDefinitionResult res : resList) { + ApiComputeResult compRes = resultMap.get(res.getId()); + if (compRes != null) { + res.setCaseTotal(compRes.getCaseTotal()); + res.setCasePassingRate(compRes.getPassRate()); + res.setCaseStatus(compRes.getStatus()); + } else { + res.setCaseTotal("-"); + res.setCasePassingRate("-"); + res.setCaseStatus("-"); + } + } + } + } } diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java index 30702b8122..e4576036f1 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java @@ -28,4 +28,6 @@ public interface ExtApiDefinitionMapper { List countApiCoverageByProjectID(String projectId); ApiDefinition getNextNum(@Param("projectId") String projectId); + + List listRelevance(@Param("request")ApiDefinitionRequest request); } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml index c6c91a5300..2ca103606a 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml @@ -295,4 +295,63 @@ + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanApiCaseMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanApiCaseMapper.xml index 55291b8a4d..d126e3372c 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanApiCaseMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanApiCaseMapper.xml @@ -19,7 +19,7 @@ select t.id, t.environment_id, t.create_time, t.update_time, c.id as case_id, c.project_id, c.name, c.api_definition_id, c.priority, c.description, c.create_user_id, c.update_user_id, - a.module_id, a.path, a.protocol, ader.status execResult + a.module_id, a.path, a.protocol, t.status execResult from test_plan_api_case t inner join @@ -32,24 +32,6 @@ api_definition a on c.api_definition_id = a.id - left join ( - select - e.status, e.id, e.resource_id - from - api_definition_exec_result e - left join ( - select - max(start_time) start_time , resource_id - from - api_definition_exec_result - group by - resource_id - ) as b - on e.resource_id = b.resource_id - where - e.start_time = b.start_time and e.type = 'API_PLAN' - ) as ader - on t.id = ader.resource_id and a.protocol = #{request.protocol} diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index c10b11f224..f27d1609d7 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit c10b11f224e4186306e6ae3a3976e29a42af96a5 +Subproject commit f27d1609d77f7d6c988d37d709466e844d350e17 diff --git a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue index a21ea23045..40d8541718 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue @@ -9,7 +9,7 @@ - + @@ -23,6 +23,7 @@ + diff --git a/frontend/src/business/components/api/automation/scenario/ApiScenarioModule.vue b/frontend/src/business/components/api/automation/scenario/ApiScenarioModule.vue index 3305b4d83b..551e1e8532 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiScenarioModule.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiScenarioModule.vue @@ -15,10 +15,9 @@ ref="nodeTree"> @@ -56,15 +46,14 @@ import TestCaseRelevanceBase from "../base/TestCaseRelevanceBase"; import MsApiModule from "../../../../../api/definition/components/module/ApiModule"; - import {getCurrentProjectID} from "../../../../../../../common/js/utils"; - import ApiList from "../../../../../api/definition/components/list/ApiList"; - import ApiCaseSimpleList from "../../../../../api/definition/components/list/ApiCaseSimpleList"; + import RelevanceApiList from "../../../../../api/automation/scenario/api/RelevanceApiList"; + import RelevanceCaseList from "../../../../../api/automation/scenario/api/RelevanceCaseList"; export default { name: "TestCaseApiRelevance", components: { - ApiCaseSimpleList, - ApiList, + RelevanceCaseList, + RelevanceApiList, MsApiModule, TestCaseRelevanceBase, }, @@ -94,8 +83,20 @@ }, methods: { open() { + this.init(); this.$refs.baseRelevance.open(); }, + init() { + if (this.$refs.apiList) { + this.$refs.apiList.initTable(); + } + if (this.$refs.apiCaseList) { + this.$refs.apiCaseList.initTable(); + } + if (this.$refs.nodeTree) { + this.$refs.nodeTree.list(); + } + }, setProject(projectId) { this.projectId = projectId; }, @@ -145,11 +146,6 @@ param.planId = this.planId; param.selectIds = selectIds; param.environmentId = environmentId; - // param.request = this.condition; - // 选择全选则全部加入到评审,无论是否加载完全部 - // if (this.testCases.length === param.testCaseIds.length) { - // param.testCaseIds = ['all']; - // } this.result = this.$post(url, param, () => { this.$success(this.$t('commons.save_success')); diff --git a/frontend/src/business/components/track/plan/view/comonents/api/TestPlanApi.vue b/frontend/src/business/components/track/plan/view/comonents/api/TestPlanApi.vue index ba614bdfc9..7b685cebb9 100644 --- a/frontend/src/business/components/track/plan/view/comonents/api/TestPlanApi.vue +++ b/frontend/src/business/components/track/plan/view/comonents/api/TestPlanApi.vue @@ -162,18 +162,6 @@ this.moduleOptions = data; }, - saveCaseRelevance() { - let url = ''; - let selectIds = []; - let param = {}; - param.planId = this.planId; - param.selectIds = selectIds; - this.result = this.$post(url, param, () => { - this.$success(this.$t('commons.save_success')); - this.refresh(); - this.$refs.baseRelevance.close(); - }); - }, openTestCaseRelevanceDialog(model) { if (model === 'scenario') { this.$refs.scenarioCaseRelevance.open(); @@ -194,4 +182,9 @@ margin: 5px 10px; } + /deep/ .run-button { + background-color: #409EFF; + border-color: #409EFF; + } + diff --git a/frontend/src/business/components/track/plan/view/comonents/api/TestPlanApiCaseList.vue b/frontend/src/business/components/track/plan/view/comonents/api/TestPlanApiCaseList.vue index ab0e32236e..b959694497 100644 --- a/frontend/src/business/components/track/plan/view/comonents/api/TestPlanApiCaseList.vue +++ b/frontend/src/business/components/track/plan/view/comonents/api/TestPlanApiCaseList.vue @@ -81,8 +81,10 @@ @@ -334,7 +336,7 @@ this.selectRows.clear(); this.initTable(); this.$emit('refresh'); - this.$success(this.$t('commons.delete_success')); + this.$success(this.$t('test_track.cancel_relevance_success')); }); } } @@ -414,7 +416,7 @@ }, handleDelete(apiCase) { this.$get('/test/plan/api/case/delete/' + this.planId + '/' + apiCase.id, () => { - this.$success(this.$t('commons.delete_success')); + this.$success(this.$t('test_track.cancel_relevance_success')); this.$emit('refresh'); this.initTable(); }); diff --git a/frontend/src/business/components/track/plan/view/comonents/api/TestPlanApiScenarioList.vue b/frontend/src/business/components/track/plan/view/comonents/api/TestPlanApiScenarioList.vue index 8daa164741..797c67c839 100644 --- a/frontend/src/business/components/track/plan/view/comonents/api/TestPlanApiScenarioList.vue +++ b/frontend/src/business/components/track/plan/view/comonents/api/TestPlanApiScenarioList.vue @@ -51,8 +51,10 @@ show-overflow-tooltip/> @@ -81,10 +83,12 @@ import MsTestPlanList from "../../../../../api/automation/scenario/testplan/TestPlanList"; import TestPlanScenarioListHeader from "./TestPlanScenarioListHeader"; import {_handleSelect, _handleSelectAll} from "../../../../../../../common/js/tableUtils"; + import MsTableOperatorButton from "../../../../../common/components/MsTableOperatorButton"; export default { name: "MsTestPlanApiScenarioList", components: { + MsTableOperatorButton, TestPlanScenarioListHeader, MsTablePagination, MsTableMoreBtn, ShowMoreBtn, MsTableHeader, MsTag, MsApiReportDetail, MsScenarioExtendButtons, MsTestPlanList}, props: { @@ -189,7 +193,7 @@ }, remove(row) { this.$get('/test/plan/scenario/case/delete/' + this.planId + '/' + row.id, () => { - this.$success(this.$t('commons.delete_success')); + this.$success(this.$t('test_track.cancel_relevance_success')); this.$emit('refresh'); this.search(); }); @@ -215,7 +219,7 @@ this.$post('/test/plan/scenario/case/batch/delete', param, () => { this.selectRows.clear(); this.search(); - this.$success(this.$t('commons.delete_success')); + this.$success(this.$t('test_track.cancel_relevance_success')); this.$emit('refresh'); }); } diff --git a/frontend/src/business/components/track/plan/view/comonents/base/RelevanceDialog.vue b/frontend/src/business/components/track/plan/view/comonents/base/RelevanceDialog.vue new file mode 100644 index 0000000000..f0b4137f97 --- /dev/null +++ b/frontend/src/business/components/track/plan/view/comonents/base/RelevanceDialog.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/frontend/src/business/components/track/plan/view/comonents/base/TestCaseRelevanceBase.vue b/frontend/src/business/components/track/plan/view/comonents/base/TestCaseRelevanceBase.vue index 6be80f9c4e..e2a3f23ffc 100644 --- a/frontend/src/business/components/track/plan/view/comonents/base/TestCaseRelevanceBase.vue +++ b/frontend/src/business/components/track/plan/view/comonents/base/TestCaseRelevanceBase.vue @@ -1,55 +1,45 @@ diff --git a/frontend/src/business/main.js b/frontend/src/business/main.js index 5fa89340c7..71bf73823a 100644 --- a/frontend/src/business/main.js +++ b/frontend/src/business/main.js @@ -18,6 +18,7 @@ import '../common/css/menu-header.css'; import '../common/css/main.css'; import CKEditor from '@ckeditor/ckeditor5-vue'; import VueFab from 'vue-float-action-button' +import {horizontalDrag} from "../common/js/directive"; Vue.config.productionTip = false; Vue.use(icon); @@ -43,6 +44,9 @@ Vue.directive('xpack', xpack); Vue.directive('tester', tester); +//支持左右拖拽 +Vue.directive('horizontal-drag', horizontalDrag); + new Vue({ el: '#app', router, diff --git a/frontend/src/common/js/directive.js b/frontend/src/common/js/directive.js new file mode 100644 index 0000000000..b7d78b4d0a --- /dev/null +++ b/frontend/src/common/js/directive.js @@ -0,0 +1,17 @@ +export const horizontalDrag = { + inserted(el, binding) { + el.onmousedown = function (e) { + const init = e.clientX; + const parent = el.parentNode; + const initWidth = parent.offsetWidth; + document.onmousemove = function (e) { + const end = e.clientX; + const newWidth = end - init + initWidth; + parent.style.width = newWidth + "px"; + }; + document.onmouseup = function () { + document.onmousemove = document.onmouseup = null; + }; + }; + } +}; diff --git a/frontend/src/common/js/tableUtils.js b/frontend/src/common/js/tableUtils.js index 44ed9b0cfa..fcd06333bd 100644 --- a/frontend/src/common/js/tableUtils.js +++ b/frontend/src/common/js/tableUtils.js @@ -29,12 +29,7 @@ export function _handleSelect(component, selection, row, selectRows) { selectRows.add(row); } let arr = Array.from(selectRows); - // 选中1个以上的用例时显示更多操作 - if (selectRows.size === 1) { - component.$set(arr[0], "showMore", false); - } else if (selectRows.size === 2) { - arr.forEach(row => { - component.$set(row, "showMore", true); - }) - } + arr.forEach(row => { + component.$set(row, "showMore", true); + }) }