refactor: 创建项目时默认创建Mock环境等一系列优化

重写接口定义页面的接口列表表格,制作表格统一化;批量菜单选项选中高亮;创建项目时默认创建Mock环境
This commit is contained in:
song-tianyang 2021-04-20 19:13:43 +08:00 committed by 刘瑞斌
parent 195fd95687
commit 79d7c0e01e
11 changed files with 457 additions and 163 deletions

View File

@ -272,8 +272,7 @@ public class ApiDefinitionController {
@GetMapping("/getMockEnvironment/{projectId}") @GetMapping("/getMockEnvironment/{projectId}")
public ApiTestEnvironmentWithBLOBs getMockEnvironment(@PathVariable String projectId, HttpServletRequest request) { public ApiTestEnvironmentWithBLOBs getMockEnvironment(@PathVariable String projectId, HttpServletRequest request) {
System.out.println(request.getRequestURL()); String requestUrl = request.getRequestURL().toString();
String requestUrl = request.getRequestURI();
String baseUrl = ""; String baseUrl = "";
if (requestUrl.contains("/api/definition")) { if (requestUrl.contains("/api/definition")) {
baseUrl = requestUrl.split("/api/definition")[0]; baseUrl = requestUrl.split("/api/definition")[0];

View File

@ -194,7 +194,11 @@ public class ApiDefinitionService {
} }
public void reduction(ApiBatchRequest request) { public void reduction(ApiBatchRequest request) {
extApiDefinitionMapper.reduction(request.getIds()); ServiceUtils.getSelectAllIds(request, request.getCondition(),
(query) -> extApiDefinitionMapper.selectIds(query));
if (request.getIds() != null || !request.getIds().isEmpty()) {
extApiDefinitionMapper.reduction(request.getIds());
}
} }
public void deleteBodyFiles(String apiId) { public void deleteBodyFiles(String apiId) {

View File

@ -94,6 +94,7 @@ public class ApiTestEnvironmentService {
private ApiTestEnvironmentWithBLOBs genHttpApiTestEnvironmentByUrl(String projectId, String name, String url) { private ApiTestEnvironmentWithBLOBs genHttpApiTestEnvironmentByUrl(String projectId, String name, String url) {
String protocol = ""; String protocol = "";
String socket = "";
if (url.startsWith("http://")) { if (url.startsWith("http://")) {
protocol = "http"; protocol = "http";
url = url.substring(7); url = url.substring(7);
@ -101,6 +102,7 @@ public class ApiTestEnvironmentService {
protocol = "https"; protocol = "https";
url = url.substring(8); url = url.substring(8);
} }
socket = url;
String portStr = ""; String portStr = "";
String ipStr = protocol; String ipStr = protocol;
@ -127,13 +129,42 @@ public class ApiTestEnvironmentService {
commonConfigObj.put("hosts", new String[]{}); commonConfigObj.put("hosts", new String[]{});
JSONObject httpConfig = new JSONObject(); JSONObject httpConfig = new JSONObject();
httpConfig.put("socket", url); // httpConfig.put("socket", url);
httpConfig.put("domain", ipStr); // httpConfig.put("domain", ipStr);
httpConfig.put("headers", variablesArr); // httpConfig.put("headers", variablesArr);
httpConfig.put("protocol", protocol); // httpConfig.put("protocol", protocol);
// if (StringUtils.isNotEmpty(portStr)) {
// httpConfig.put("port", portStr);
// }
httpConfig.put("socket", null);
httpConfig.put("domain", null);
httpConfig.put("headers", new JSONArray(variablesArr));
httpConfig.put("protocol", null);
httpConfig.put("port", null);
JSONArray httpItemArr = new JSONArray();
JSONObject httpItem = new JSONObject();
httpItem.put("id", UUID.randomUUID().toString());
httpItem.put("type", "NONE");
httpItem.put("socket", socket);
httpItem.put("protocol", protocol);
httpItem.put("headers", new JSONArray(variablesArr));
httpItem.put("domain", ipStr);
if (StringUtils.isNotEmpty(portStr)) { if (StringUtils.isNotEmpty(portStr)) {
httpConfig.put("port", portStr); httpItem.put("port", portStr);
} else {
httpItem.put("port", "");
} }
JSONArray detailArr = new JSONArray();
JSONObject detailObj = new JSONObject();
detailObj.put("name", "");
detailObj.put("value", "contains");
detailObj.put("enable", true);
detailArr.add(detailObj);
httpItem.put("details", detailArr);
httpItemArr.add(httpItem);
httpConfig.put("conditions", httpItemArr);
httpConfig.put("defaultCondition", "NONE");
JSONArray databaseConfigObj = new JSONArray(); JSONArray databaseConfigObj = new JSONArray();

View File

@ -1,9 +1,9 @@
package io.metersphere.base.domain; package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data; import lombok.Data;
import java.io.Serializable;
@Data @Data
public class MockConfig implements Serializable { public class MockConfig implements Serializable {
private String id; private String id;
@ -23,4 +23,5 @@ public class MockConfig implements Serializable {
private String createUserId; private String createUserId;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
} }

View File

@ -2,6 +2,7 @@ package io.metersphere.controller;
import com.github.pagehelper.Page; import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.FileMetadata; import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.domain.Project; import io.metersphere.base.domain.Project;
import io.metersphere.commons.constants.RoleConstants; import io.metersphere.commons.constants.RoleConstants;
@ -18,6 +19,7 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List; import java.util.List;
@RestController @RestController
@ -27,6 +29,8 @@ public class ProjectController {
private ProjectService projectService; private ProjectService projectService;
@Resource @Resource
private CheckPermissionService checkPermissionService; private CheckPermissionService checkPermissionService;
@Resource
private ApiTestEnvironmentService apiTestEnvironmentService;
@GetMapping("/listAll") @GetMapping("/listAll")
public List<ProjectDTO> listAll() { public List<ProjectDTO> listAll() {
@ -62,8 +66,18 @@ public class ProjectController {
@PostMapping("/add") @PostMapping("/add")
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER,}, logical = Logical.OR) @RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER,}, logical = Logical.OR)
public Project addProject(@RequestBody Project project) { public Project addProject(@RequestBody Project project, HttpServletRequest request) {
return projectService.addProject(project); Project returnModel = projectService.addProject(project);
//创建项目的时候默认增加Mock环境
String requestUrl = request.getRequestURL().toString();
String baseUrl = "";
if (requestUrl.contains("/project/add")) {
baseUrl = requestUrl.split("/project/add")[0];
}
apiTestEnvironmentService.getMockEnvironmentByProjectId(returnModel.getId(), baseUrl);
return returnModel;
} }
@PostMapping("/list/{goPage}/{pageSize}") @PostMapping("/list/{goPage}/{pageSize}")

View File

@ -8,38 +8,20 @@
@keyup.enter.native="search" @keyup.enter.native="search"
v-model="condition.name"/> v-model="condition.name"/>
<el-table v-loading="result.loading" <ms-table :data="tableData" :select-node-ids="selectNodeIds" :condition="condition" :page-size="pageSize"
:total="total" enableSelection
:batch-operators="trashEnable ? trashButtons : buttons" :screenHeight="screenHeight"
:operators="tableOperatorButtons" operator-width="170px"
ref="apiDefinitionTable" ref="apiDefinitionTable"
border >
@sort-change="sort"
@filter-change="filter"
:data="tableData" row-key="id" class="test-content adjust-table ms-select-all-fixed"
@select-all="handleSelectAll"
@header-dragend="headerDragend"
@select="handleSelect" :height="screenHeight">
<el-table-column width="50" type="selection"/>
<ms-table-header-select-popover v-show="total>0"
:page-size="pageSize>total?total:pageSize"
:total="total"
:select-data-counts="selectDataCounts"
@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="trashEnable ? trashButtons : buttons" :size="selectDataCounts" v-tester/>
</template>
</el-table-column>
<template v-for="(item, index) in tableLabel"> <template v-for="(item, index) in tableLabel">
<el-table-column <ms-table-column
v-if="item.id == 'num'" v-if="item.id == 'num'"
prop="num" prop="num"
label="ID" label="ID"
show-overflow-tooltip show-overflow-tooltip
min-width="80px" min-width="80px"
sortable="custom" sortable=true
:key="index"> :key="index">
<template slot-scope="scope"> <template slot-scope="scope">
<!-- 判断为只读用户的话不可点击ID进行编辑操作 --> <!-- 判断为只读用户的话不可点击ID进行编辑操作 -->
@ -48,39 +30,40 @@
<a style="cursor:pointer" @click="editApi(scope.row)"> {{ scope.row.num }} </a> <a style="cursor:pointer" @click="editApi(scope.row)"> {{ scope.row.num }} </a>
</el-tooltip> </el-tooltip>
</template> </template>
</el-table-column> </ms-table-column>
<el-table-column <ms-table-column
v-if="item.id == 'name'" v-if="item.id == 'name'"
prop="name" prop="name"
:label="$t('api_test.definition.api_name')" :label="$t('api_test.definition.api_name')"
show-overflow-tooltip show-overflow-tooltip
sortable="custom" sortable="custom"
min-width="120px" width="120px"
:key="index"/> :key="index"/>
<el-table-column <ms-table-column
v-if="item.id == 'status'" v-if="item.id == 'status'"
prop="status" prop="status"
column-key="status" column-key="status"
sortable="custom" sortable="custom"
:filters="statusFilters" :filters="statusFilters"
:label="$t('api_test.definition.api_status')" :label="$t('api_test.definition.api_status')"
min-width="120px" width="120px"
:key="index"> :key="index">
<template v-slot:default="scope"> <template v-slot:default="scope">
<span class="el-dropdown-link"> <span class="el-dropdown-link">
<api-status :value="scope.row.status"/> <api-status :value="scope.row.status"/>
</span> </span>
</template> </template>
</el-table-column> </ms-table-column>
<el-table-column <ms-table-column
v-if="item.id == 'method'" v-if="item.id == 'method'"
prop="method" prop="method"
sortable="custom" sortable="custom"
column-key="method" column-key="method"
:filters="methodFilters" :filters="methodFilters"
:label="$t('api_test.definition.api_type')" :label="$t('api_test.definition.api_type')"
show-overflow-tooltip min-width="120px" show-overflow-tooltip
width="120px"
:key="index"> :key="index">
<template v-slot:default="scope" class="request-method"> <template v-slot:default="scope" class="request-method">
<el-tag size="mini" <el-tag size="mini"
@ -89,9 +72,9 @@
{{ scope.row.method }} {{ scope.row.method }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </ms-table-column>
<el-table-column <ms-table-column
v-if="item.id == 'userName'" v-if="item.id == 'userName'"
prop="userName" prop="userName"
sortable="custom" sortable="custom"
@ -99,105 +82,260 @@
column-key="user_id" column-key="user_id"
:label="$t('api_test.definition.api_principal')" :label="$t('api_test.definition.api_principal')"
show-overflow-tooltip show-overflow-tooltip
min-width="100px" width="100px"
:key="index"/> :key="index"/>
<el-table-column <ms-table-column
v-if="item.id == 'path'" v-if="item.id == 'path'"
prop="path" prop="path"
min-width="120px" width="120px"
:label="$t('api_test.definition.api_path')" :label="$t('api_test.definition.api_path')"
show-overflow-tooltip show-overflow-tooltip
:key="index"/> :key="index"/>
<el-table-column <ms-table-column
v-if="item.id == 'tags'" v-if="item.id == 'tags'"
prop="tags" prop="tags"
:label="$t('commons.tag')" :label="$t('commons.tag')"
min-width="120px" width="120px"
:key="index"> :key="index">
<template v-slot:default="scope"> <template v-slot:default="scope">
<ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain" :show-tooltip="true" :content="itemName" <ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain"
:show-tooltip="true" :content="itemName"
style="margin-left: 0px; margin-right: 2px"/> style="margin-left: 0px; margin-right: 2px"/>
</template> </template>
</el-table-column> </ms-table-column>
<el-table-column <ms-table-column
v-if="item.id == 'updateTime'" v-if="item.id == 'updateTime'"
width="160" width="160"
:label="$t('api_test.definition.api_last_time')" :label="$t('api_test.definition.api_last_time')"
sortable="custom" sortable="custom"
min-width="160px"
prop="updateTime" prop="updateTime"
:key="index"> :key="index">
<template v-slot:default="scope"> <template v-slot:default="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span> <span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template> </template>
</el-table-column> </ms-table-column>
<el-table-column <ms-table-column
v-if="item.id == 'caseTotal'" v-if="item.id == 'caseTotal'"
prop="caseTotal" prop="caseTotal"
min-width="80px" width="80px"
:label="$t('api_test.definition.api_case_number')" :label="$t('api_test.definition.api_case_number')"
show-overflow-tooltip show-overflow-tooltip
:key="index"/> :key="index"/>
<el-table-column <ms-table-column
v-if="item.id == 'caseStatus'" v-if="item.id == 'caseStatus'"
prop="caseStatus" prop="caseStatus"
min-width="80px" width="80px"
:label="$t('api_test.definition.api_case_status')" :label="$t('api_test.definition.api_case_status')"
show-overflow-tooltip show-overflow-tooltip
:key="index"/> :key="index"/>
<el-table-column <ms-table-column
v-if="item.id == 'casePassingRate'" v-if="item.id == 'casePassingRate'"
width="100px"
prop="casePassingRate" prop="casePassingRate"
:width="100"
min-width="100px"
:label="$t('api_test.definition.api_case_passing_rate')" :label="$t('api_test.definition.api_case_passing_rate')"
show-overflow-tooltip show-overflow-tooltip
:key="index"/> :key="index"/>
</template> </template>
<!-- 操作 -->
<el-table-column fixed="right" v-if="!isReadOnly" min-width="180"
align="center">
<template slot="header">
<header-label-operate @exec="customHeader"/>
</template>
<template v-slot:default="scope"> </ms-table>
<ms-table-operator-button class="run-button" :is-tester-permission="true"
:tip="$t('api_test.automation.execute')" <!-- <el-table v-loading="result.loading"-->
icon="el-icon-video-play" <!-- ref="apiDefinitionTable"-->
@exec="runApi(scope.row)"/> <!-- border-->
<!-- 回收站的恢复按钮 --> <!-- @sort-change="sort"-->
<ms-table-operator-button :tip="$t('commons.reduction')" icon="el-icon-refresh-left" <!-- @filter-change="filter"-->
@exec="reductionApi(scope.row)" v-if="trashEnable" v-tester/> <!-- :data="tableData" row-key="id" class="test-content adjust-table ms-select-all-fixed"-->
<ms-table-operator-button :tip="$t('commons.edit')" icon="el-icon-edit" @exec="editApi(scope.row)" v-else <!-- @select-all="handleSelectAll"-->
v-tester/> <!-- @header-dragend="headerDragend"-->
<el-tooltip :content="$t('test_track.case.case_list')" <!-- @select="handleSelect" :height="screenHeight">-->
placement="bottom" <!-- <el-table-column width="50" type="selection"/>-->
:enterable="false"
effect="dark"> <!-- <ms-table-header-select-popover v-show="total>0"-->
<el-button @click="handleTestCase(scope.row)" <!-- :page-size="pageSize>total?total:pageSize"-->
@keydown.enter.native.prevent <!-- :total="total"-->
type="primary" <!-- :select-data-counts="selectDataCounts"-->
:disabled="isReadOnly" <!-- @selectPageAll="isSelectDataAll(false)"-->
circle <!-- @selectAll="isSelectDataAll(true)"/>-->
style="color:white;padding: 0px 0.1px;font-size: 11px;width: 28px;height: 28px;"
size="mini">case <!-- <el-table-column width="30" :resizable="false" align="center">-->
</el-button> <!-- <template v-slot:default="scope">-->
</el-tooltip> <!-- &lt;!&ndash; 选中记录后浮现的按钮提供对记录的批量操作 &ndash;&gt;-->
<ms-table-operator-button :tip="$t('commons.delete')" icon="el-icon-delete" @exec="handleDelete(scope.row)" <!-- <show-more-btn :is-show="scope.row.showMore" :buttons="trashEnable ? trashButtons : buttons" :size="selectDataCounts" v-tester/>-->
type="danger" v-tester/> <!-- </template>-->
</template> <!-- </el-table-column>-->
</el-table-column> <!-- <template v-for="(item, index) in tableLabel">-->
<header-custom ref="headerCustom" :initTableData="initTable" :optionalFields=headerItems <!-- <el-table-column-->
:type=type></header-custom> <!-- v-if="item.id == 'num'"-->
</el-table> <!-- prop="num"-->
<!-- label="ID"-->
<!-- show-overflow-tooltip-->
<!-- min-width="80px"-->
<!-- sortable="custom"-->
<!-- :key="index">-->
<!-- <template slot-scope="scope">-->
<!-- &lt;!&ndash; 判断为只读用户的话不可点击ID进行编辑操作 &ndash;&gt;-->
<!-- <span style="cursor:pointer" v-if="isReadOnly"> {{ scope.row.num }} </span>-->
<!-- <el-tooltip v-else content="编辑">-->
<!-- <a style="cursor:pointer" @click="editApi(scope.row)"> {{ scope.row.num }} </a>-->
<!-- </el-tooltip>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column-->
<!-- v-if="item.id == 'name'"-->
<!-- prop="name"-->
<!-- :label="$t('api_test.definition.api_name')"-->
<!-- show-overflow-tooltip-->
<!-- sortable="custom"-->
<!-- min-width="120px"-->
<!-- :key="index"/>-->
<!-- <el-table-column-->
<!-- v-if="item.id == 'status'"-->
<!-- prop="status"-->
<!-- column-key="status"-->
<!-- sortable="custom"-->
<!-- :filters="statusFilters"-->
<!-- :label="$t('api_test.definition.api_status')"-->
<!-- min-width="120px"-->
<!-- :key="index">-->
<!-- <template v-slot:default="scope">-->
<!-- <span class="el-dropdown-link">-->
<!-- <api-status :value="scope.row.status"/>-->
<!-- </span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column-->
<!-- v-if="item.id == 'method'"-->
<!-- prop="method"-->
<!-- sortable="custom"-->
<!-- column-key="method"-->
<!-- :filters="methodFilters"-->
<!-- :label="$t('api_test.definition.api_type')"-->
<!-- show-overflow-tooltip min-width="120px"-->
<!-- :key="index">-->
<!-- <template v-slot:default="scope" class="request-method">-->
<!-- <el-tag size="mini"-->
<!-- :style="{'background-color': getColor(true, scope.row.method), border: getColor(true, scope.row.method)}"-->
<!-- class="api-el-tag">-->
<!-- {{ scope.row.method }}-->
<!-- </el-tag>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column-->
<!-- v-if="item.id == 'userName'"-->
<!-- prop="userName"-->
<!-- sortable="custom"-->
<!-- :filters="userFilters"-->
<!-- column-key="user_id"-->
<!-- :label="$t('api_test.definition.api_principal')"-->
<!-- show-overflow-tooltip-->
<!-- min-width="100px"-->
<!-- :key="index"/>-->
<!-- <el-table-column-->
<!-- v-if="item.id == 'path'"-->
<!-- prop="path"-->
<!-- min-width="120px"-->
<!-- :label="$t('api_test.definition.api_path')"-->
<!-- show-overflow-tooltip-->
<!-- :key="index"/>-->
<!-- <el-table-column-->
<!-- v-if="item.id == 'tags'"-->
<!-- prop="tags"-->
<!-- :label="$t('commons.tag')"-->
<!-- min-width="120px"-->
<!-- :key="index">-->
<!-- <template v-slot:default="scope">-->
<!-- <ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain" :show-tooltip="true" :content="itemName"-->
<!-- style="margin-left: 0px; margin-right: 2px"/>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column-->
<!-- v-if="item.id == 'updateTime'"-->
<!-- width="160"-->
<!-- :label="$t('api_test.definition.api_last_time')"-->
<!-- sortable="custom"-->
<!-- min-width="160px"-->
<!-- prop="updateTime"-->
<!-- :key="index">-->
<!-- <template v-slot:default="scope">-->
<!-- <span>{{ scope.row.updateTime | timestampFormatDate }}</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column-->
<!-- v-if="item.id == 'caseTotal'"-->
<!-- prop="caseTotal"-->
<!-- min-width="80px"-->
<!-- :label="$t('api_test.definition.api_case_number')"-->
<!-- show-overflow-tooltip-->
<!-- :key="index"/>-->
<!-- <el-table-column-->
<!-- v-if="item.id == 'caseStatus'"-->
<!-- prop="caseStatus"-->
<!-- min-width="80px"-->
<!-- :label="$t('api_test.definition.api_case_status')"-->
<!-- show-overflow-tooltip-->
<!-- :key="index"/>-->
<!-- <el-table-column-->
<!-- v-if="item.id == 'casePassingRate'"-->
<!-- prop="casePassingRate"-->
<!-- :width="100"-->
<!-- min-width="100px"-->
<!-- :label="$t('api_test.definition.api_case_passing_rate')"-->
<!-- show-overflow-tooltip-->
<!-- :key="index"/>-->
<!-- </template>-->
<!-- &lt;!&ndash; 操作 &ndash;&gt;-->
<!-- <el-table-column fixed="right" v-if="!isReadOnly" min-width="180"-->
<!-- align="center">-->
<!-- <template slot="header">-->
<!-- <header-label-operate @exec="customHeader"/>-->
<!-- </template>-->
<!-- <template v-slot:default="scope">-->
<!-- <ms-table-operator-button class="run-button" :is-tester-permission="true"-->
<!-- :tip="$t('api_test.automation.execute')"-->
<!-- icon="el-icon-video-play"-->
<!-- @exec="runApi(scope.row)"/>-->
<!-- &lt;!&ndash; 回收站的恢复按钮 &ndash;&gt;-->
<!-- <ms-table-operator-button :tip="$t('commons.reduction')" icon="el-icon-refresh-left"-->
<!-- @exec="reductionApi(scope.row)" v-if="trashEnable" v-tester/>-->
<!-- <ms-table-operator-button :tip="$t('commons.edit')" icon="el-icon-edit" @exec="editApi(scope.row)" v-else-->
<!-- v-tester/>-->
<!-- <el-tooltip :content="$t('test_track.case.case_list')"-->
<!-- placement="bottom"-->
<!-- :enterable="false"-->
<!-- effect="dark">-->
<!-- <el-button @click="handleTestCase(scope.row)"-->
<!-- @keydown.enter.native.prevent-->
<!-- type="primary"-->
<!-- :disabled="isReadOnly"-->
<!-- circle-->
<!-- style="color:white;padding: 0px 0.1px;font-size: 11px;width: 28px;height: 28px;"-->
<!-- size="mini">case-->
<!-- </el-button>-->
<!-- </el-tooltip>-->
<!-- <ms-table-operator-button :tip="$t('commons.delete')" icon="el-icon-delete" @exec="handleDelete(scope.row)"-->
<!-- type="danger" v-tester/>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <header-custom ref="headerCustom" :initTableData="initTable" :optionalFields=headerItems-->
<!-- :type=type></header-custom>-->
<!-- </el-table>-->
<ms-table-pagination :change="initTable" :current-page.sync="currentPage" :page-size.sync="pageSize" <ms-table-pagination :change="initTable" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/> :total="total"/>
</div> </div>
@ -218,9 +356,11 @@ import MsTableOperator from "../../../../common/components/MsTableOperator";
import MsTableOperatorButton from "../../../../common/components/MsTableOperatorButton"; import MsTableOperatorButton from "../../../../common/components/MsTableOperatorButton";
import MsTableButton from "../../../../common/components/MsTableButton"; import MsTableButton from "../../../../common/components/MsTableButton";
import MsTablePagination from "../../../../common/pagination/TablePagination"; import MsTablePagination from "../../../../common/pagination/TablePagination";
import MsTable from "@/business/components/common/components/table/MsTable";
import MsTag from "../../../../common/components/MsTag"; import MsTag from "../../../../common/components/MsTag";
import MsApiCaseList from "../case/ApiCaseList"; import MsApiCaseList from "../case/ApiCaseList";
import MsContainer from "../../../../common/components/MsContainer"; import MsContainer from "../../../../common/components/MsContainer";
import MsTableColumn from "@/business/components/common/components/table/Ms-table-column";
import MsBottomContainer from "../BottomContainer"; import MsBottomContainer from "../BottomContainer";
import ShowMoreBtn from "../../../../track/case/components/ShowMoreBtn"; import ShowMoreBtn from "../../../../track/case/components/ShowMoreBtn";
import MsBatchEdit from "../basis/BatchEdit"; import MsBatchEdit from "../basis/BatchEdit";
@ -272,7 +412,9 @@ export default {
ShowMoreBtn, ShowMoreBtn,
MsBatchEdit, MsBatchEdit,
MsTipButton, MsTipButton,
MsTableAdvSearchBar MsTableAdvSearchBar,
MsTable,
MsTableColumn
}, },
data() { data() {
return { return {
@ -301,6 +443,17 @@ export default {
name: "批量恢复", handleClick: this.handleBatchRestore name: "批量恢复", handleClick: this.handleBatchRestore
}, },
], ],
tableOperatorButtons: [],
tableUsualOperatorButtons: [
{tip: this.$t('api_test.automation.execute'), icon: "el-icon-video-play", exec: this.runApi},
{tip: this.$t('commons.edit'), icon: "el-icon-edit", exec: this.editApi},
{tip: "CASE", exec: this.handleTestCase, isDivButton: true, type: "primary"},
{tip: this.$t('commons.delete'), exec: this.handleDelete, icon: "el-icon-delete", type: "danger"},
],
tableTrashOperatorButtons: [
{tip: this.$t('api_test.automation.execute'), icon: "el-icon-video-play", exec: this.runApi},
{tip: this.$t('commons.reduction'), icon: "el-icon-refresh-left", exec: this.reductionApi},
],
typeArr: [ typeArr: [
{id: 'status', name: this.$t('api_test.definition.api_status')}, {id: 'status', name: this.$t('api_test.definition.api_status')},
{id: 'method', name: this.$t('api_test.definition.api_type')}, {id: 'method', name: this.$t('api_test.definition.api_type')},
@ -383,8 +536,10 @@ export default {
}, },
created: function () { created: function () {
if (this.trashEnable) { if (this.trashEnable) {
this.tableOperatorButtons = this.tableTrashOperatorButtons;
this.condition.filters = {status: ["Trash"]}; this.condition.filters = {status: ["Trash"]};
} else { } else {
this.tableOperatorButtons = this.tableUsualOperatorButtons;
this.condition.filters = {status: ["Prepare", "Underway", "Completed"]}; this.condition.filters = {status: ["Prepare", "Underway", "Completed"]};
} }
this.initTable(); this.initTable();
@ -393,6 +548,8 @@ export default {
watch: { watch: {
selectNodeIds() { selectNodeIds() {
initCondition(this.condition, false); initCondition(this.condition, false);
this.condition.moduleIds = [];
this.condition.moduleIds.push(this.selectNodeIds);
this.initTable(); this.initTable();
}, },
currentProtocol() { currentProtocol() {
@ -401,9 +558,11 @@ export default {
}, },
trashEnable() { trashEnable() {
if (this.trashEnable) { if (this.trashEnable) {
this.tableOperatorButtons = this.tableTrashOperatorButtons;
this.condition.filters = {status: ["Trash"]}; this.condition.filters = {status: ["Trash"]};
this.condition.moduleIds = []; this.condition.moduleIds = [];
} else { } else {
this.tableOperatorButtons = this.tableUsualOperatorButtons;
this.condition.filters = {status: ["Prepare", "Underway", "Completed"]}; this.condition.filters = {status: ["Prepare", "Underway", "Completed"]};
} }
initCondition(this.condition, false); initCondition(this.condition, false);
@ -465,37 +624,14 @@ export default {
// nexttick: // nexttick:
this.$nextTick(function () { this.$nextTick(function () {
if (this.$refs.apiDefinitionTable) { if (this.$refs.apiDefinitionTable) {
setTimeout(this.$refs.apiDefinitionTable.doLayout, 200); this.$refs.apiDefinitionTable.checkTableRowIsSelect();
setTimeout(this.$refs.apiDefinitionTable.doLayout(), 200);
} }
this.checkTableRowIsSelect();
}) })
}); });
} }
getLabel(this, API_LIST); getLabel(this, API_LIST);
}, },
checkTableRowIsSelect() {
//
if (this.condition.selectAll) {
let unSelectIds = this.condition.unSelectIds;
this.tableData.forEach(row => {
if (unSelectIds.indexOf(row.id) < 0) {
this.$refs.apiDefinitionTable.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);
}
}
})
}
},
genProtocalFilter(protocalType) { genProtocalFilter(protocalType) {
if (protocalType === "HTTP") { if (protocalType === "HTTP") {
this.methodFilters = [ this.methodFilters = [

View File

@ -1,11 +1,26 @@
<template> <template>
<ms-tip-button <el-tooltip :content="tip" v-if=isDivButton
:disabled="disabled || isReadOnly" placement="bottom"
@click="exec" :enterable="false"
@clickStop="clickStop" effect="dark">
:type="type" <el-button @click="exec"
:tip="tip" @keydown.enter.native.prevent
:icon="icon" size="mini" circle/> type="primary"
:disabled="isReadOnly"
circle
style="color:white;padding: 0px 0.1px;width: 28px;height: 28px;"
size="mini">
<span style=" font-size: 11px; transform: scale(0.8);">{{ tip }}</span>
</el-button>
</el-tooltip>
<ms-tip-button v-else
:disabled="disabled || isReadOnly"
@click="exec"
@clickStop="clickStop"
:type="type"
:tip="tip"
:icon="icon" size="mini" circle/>
</template> </template>
<script> <script>
@ -22,6 +37,10 @@
} }
}, },
props: { props: {
isDivButton: {
type: Boolean,
default: false,
},
icon: { icon: {
type: String, type: String,
default: 'el-icon-question' default: 'el-icon-question'
@ -59,4 +78,5 @@
</script> </script>
<style scoped> <style scoped>
</style> </style>

View File

@ -2,7 +2,7 @@
<span> <span>
<ms-table-operator-button v-for="(btn, index) in buttons" :key="index" :isTesterPermission="isTesterPermission(btn)" <ms-table-operator-button v-for="(btn, index) in buttons" :key="index" :isTesterPermission="isTesterPermission(btn)"
:disabled="isDisable(btn)" :disabled="isDisable(btn)"
:tip="btn.tip" :icon="btn.icon" :type="btn.type" :tip="btn.tip" :icon="btn.icon" :type="btn.type" :isDivButton="btn.isDivButton"
@exec="click(btn)" @click.stop="clickStop(btn)"/> @exec="click(btn)" @click.stop="clickStop(btn)"/>
</span> </span>
</template> </template>

View File

@ -1,14 +1,14 @@
<template> <template>
<el-table-column <el-table-column
v-if="fields.has(prop) || fields.size < 1" v-if="fields.has(prop) || fields.size < 1"
:width="width" :min-width="width"
:fixed="fixed" :fixed="fixed"
:filters="filters" :filters="filters"
:prop="prop" :prop="prop"
:column-key="prop" :column-key="prop"
:label="label" :label="label"
:sortable="sortable" :sortable="sortable"
:show-overflow-tooltip="showOverflowTooltip"> :show-overflow-tooltip="showOverflowTooltip">
<template v-slot:default="scope"> <template v-slot:default="scope">
<slot :row="scope.row" :$index="scope.$index"> <slot :row="scope.row" :$index="scope.$index">
{{scope.row[prop]}} {{scope.row[prop]}}
@ -35,7 +35,7 @@ export default {
}, },
// mapperExtBaseMapper.orders // mapperExtBaseMapper.orders
sortable: { sortable: {
type: Boolean, type: [Boolean, String],
default() { default() {
return false; return false;
} }

View File

@ -12,19 +12,22 @@
@cell-mouse-enter="showPopover" @cell-mouse-enter="showPopover"
row-key="id" row-key="id"
class="test-content adjust-table ms-select-all-fixed" class="test-content adjust-table ms-select-all-fixed"
:height="screenHeight"
ref="table" @row-click="handleRowClick"> ref="table" @row-click="handleRowClick">
<el-table-column v-if="enableSelection" width="50" type="selection"/> <el-table-column v-if="enableSelection" width="50" type="selection"/>
<ms-table-header-select-popover v-if="enableSelection" v-show="total > 0" <ms-table-header-select-popover v-if="enableSelection" ref="selectPopover"
:page-size="pageSize > total ? total : pageSize" :page-size="pageSize > total ? total : pageSize"
:total="total" :total="total"
@selectPageAll="isSelectDataAll(false)" @selectPageAll="isSelectDataAll(false)"
@selectAll="isSelectDataAll(true)"/> @selectAll="isSelectDataAll(true)"/>
<el-table-column v-if="enableSelection && buttons && buttons.length > 0" width="40" :resizable="false" align="center"> <el-table-column v-if="enableSelection && batchOperators && batchOperators.length > 0" width="40"
:resizable="false" align="center">
<template v-slot:default="scope"> <template v-slot:default="scope">
<show-more-btn :is-show="scope.row.showMore" :buttons="buttons" :size="selectDataCounts"/> <!-- 选中记录后浮现的按钮提供对记录的批量操作 -->
<show-more-btn :is-show="scope.row.showMore" :buttons="batchOperators" :size="selectDataCounts" v-tester/>
</template> </template>
</el-table-column> </el-table-column>
@ -55,12 +58,13 @@ import {
_handleSelectAll, _sort, getLabel, _handleSelectAll, _sort, getLabel,
getSelectDataCounts, getSelectDataCounts,
setUnSelectIds, setUnSelectIds,
toggleAllSelection toggleAllSelection,
checkTableRowIsSelect,
} from "@/common/js/tableUtils"; } from "@/common/js/tableUtils";
import MsTableHeaderSelectPopover from "@/business/components/common/components/table/MsTableHeaderSelectPopover"; import MsTableHeaderSelectPopover from "@/business/components/common/components/table/MsTableHeaderSelectPopover";
import {TEST_CASE_LIST} from "@/common/js/constants"; import {TEST_CASE_LIST} from "@/common/js/constants";
import MsTablePagination from "@/business/components/common/pagination/TablePagination"; import MsTablePagination from "@/business/components/common/pagination/TablePagination";
import ShowMoreBtn from "@/business/components/api/automation/scenario/TableMoreBtn"; import ShowMoreBtn from "@/business/components/track/case/components/ShowMoreBtn";
import MsTableColumn from "@/business/components/common/components/table/Ms-table-column"; import MsTableColumn from "@/business/components/common/components/table/Ms-table-column";
import MsTableOperators from "@/business/components/common/components/MsTableOperators"; import MsTableOperators from "@/business/components/common/components/MsTableOperators";
@ -69,12 +73,21 @@ export default {
components: {MsTableOperators, MsTableColumn, ShowMoreBtn, MsTablePagination, MsTableHeaderSelectPopover}, components: {MsTableOperators, MsTableColumn, ShowMoreBtn, MsTablePagination, MsTableHeaderSelectPopover},
data() { data() {
return { return {
buttons: [],
selectDataCounts: 0, selectDataCounts: 0,
selectRows: new Set(), selectRows: new Set(),
}; };
}, },
props: { props: {
screenHeight: {
type: Number,
default: 400,
},
selectNodeIds: {
type: Array,
default() {
return [];
}
},
data: { data: {
type: Array, type: Array,
default() { default() {
@ -106,11 +119,18 @@ export default {
return []; return [];
} }
}, },
//
batchOperators: {
type: Array,
default() {
return [];
}
},
// //
operatorWidth: { operatorWidth: {
type: String, type: String,
default() { default() {
return '150'; return "150px";
} }
}, },
// //
@ -124,6 +144,14 @@ export default {
mounted() { mounted() {
getLabel(this, TEST_CASE_LIST); getLabel(this, TEST_CASE_LIST);
}, },
created() {
},
watch: {
selectNodeIds() {
this.selectDataCounts = 0;
this.$refs.selectPopover.reload();
},
},
computed: { computed: {
selectIds() { selectIds() {
return Array.from(this.selectRows).map(o => o.id); return Array.from(this.selectRows).map(o => o.id);
@ -145,9 +173,14 @@ export default {
}, },
isSelectDataAll(data) { isSelectDataAll(data) {
this.condition.selectAll = data; this.condition.selectAll = data;
setUnSelectIds(this.data, this.condition, this.selectRows); //
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
toggleAllSelection(this.$refs.table, this.data, this.selectRows); toggleAllSelection(this.$refs.table, this.data, this.selectRows);
//
_handleSelectAll(this, this.data, this.data, this.selectRows);
//ID()
this.condition.unSelectIds = [];
//
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
}, },
headerDragend(newWidth, oldWidth, column, event) { headerDragend(newWidth, oldWidth, column, event) {
// let finalWidth = newWidth; // let finalWidth = newWidth;
@ -162,6 +195,9 @@ export default {
this.currentCaseId = row.id; this.currentCaseId = row.id;
} }
}, },
doLayout() {
this.$refs.table.doLayout();
},
filter(filters) { filter(filters) {
_filter(filters, this.condition); _filter(filters, this.condition);
this.handleRefresh(); this.handleRefresh();
@ -182,7 +218,7 @@ export default {
this.$refs.testBatchMove.open(this.treeNodes, Array.from(this.selectRows).map(row => row.id), this.moduleOptions); this.$refs.testBatchMove.open(this.treeNodes, Array.from(this.selectRows).map(row => row.id), this.moduleOptions);
}, },
handleRowClick() { handleRowClick() {
this.$emit("handleRowClick");
}, },
handleRefresh() { handleRefresh() {
this.selectRows.clear(); this.selectRows.clear();
@ -190,6 +226,9 @@ export default {
}, },
handlePageChange() { handlePageChange() {
this.$emit('pageChange'); this.$emit('pageChange');
},
checkTableRowIsSelect() {
checkTableRowIsSelect(this, this.condition, this.data, this.$refs.table, this.selectRows);
} }
} }
}; };

View File

@ -2,18 +2,25 @@
<el-table-column v-if="isShow" width="1" :resizable="false" align="center"> <el-table-column v-if="isShow" width="1" :resizable="false" align="center">
<el-popover slot="header" placement="right" trigger="click" style="margin-right: 0px;"> <el-popover slot="header" placement="right" trigger="click" style="margin-right: 0px;">
<el-link <el-link
:class="{'selected-link': selectDataCounts === this.total}" :class="{'selected-link': selectDataCounts === total}"
@click.native.stop="click('selectAll')" @click.native.stop="click('selectAll')"
:type="selectAllLinkType"
ref="selectAllLink"> ref="selectAllLink">
{{$t('api_test.batch_menus.select_all_data',[total])}} <span>
{{ $t('api_test.batch_menus.select_all_data', [total]) }}
</span>
</el-link> </el-link>
<br/> <br/>
<el-link <el-link
:class="{'selected-link': selectDataCounts === this.pageSize}" :class="{'selected-link': selectDataCounts === this.pageSize}"
@click.native.stop="click('selectPageAll')" @click.native.stop="click('selectPageAll')"
ref="selectPageAllLink"> :type="selectPageLinkType"
{{$t('api_test.batch_menus.select_show_data',[pageSize])}} ref="selectPageAllLink">
<span>
{{ $t('api_test.batch_menus.select_show_data', [pageSize]) }}
</span>
</el-link> </el-link>
<i class="el-icon-arrow-down" slot="reference"></i> <i class="el-icon-arrow-down" slot="reference"></i>
@ -24,23 +31,66 @@
<script> <script>
export default { export default {
name: "MsTableHeaderSelectPopover", name: "MsTableHeaderSelectPopover",
props: ['total', 'pageSize', 'selectDataCounts'], // props: ['total', 'pageSize', 'selectDataCounts'],
props: {
total: {
type: Number,
default() {
return 10;
}
},
pageSize: {
type: Number,
default() {
return 10;
}
},
selectDataCounts: {
type: Number,
default() {
return 0;
}
},
},
data() { data() {
return { return {
isShow: true selectType: "",
isShow: true,
selectAllLinkType: "info",
selectPageLinkType: "info",
}; };
}, },
watch: { watch: {
selectDataCounts() { selectDataCounts() {
this.reload(); this.reload();
},
total() {
this.reload();
} }
}, },
methods: { methods: {
click(even) { click(even) {
if (even === 'selectPageAll') {
this.selectAllLinkType = "info";
this.selectPageLinkType = "primary";
} else if (even === 'selectAll') {
this.selectAllLinkType = "primary";
this.selectPageLinkType = "info";
} else {
this.selectAllLinkType = "info";
this.selectPageLinkType = "info";
}
this.$emit(even); this.$emit(even);
this.isShow = false;
this.$nextTick(() => {
this.isShow = true;
});
}, },
reload() { reload() {
this.isShow = false; this.isShow = false;
this.selectAllLinkType = "info";
this.selectPageLinkType = "info";
this.$nextTick(() => { this.$nextTick(() => {
this.isShow = true; this.isShow = true;
}); });