Merge branch 'v1.3' into master

This commit is contained in:
Captain.B 2020-09-27 13:19:46 +08:00
commit 8d6d4c373e
10 changed files with 482 additions and 416 deletions

View File

@ -7,6 +7,7 @@ import io.metersphere.base.domain.TestResource;
import io.metersphere.commons.utils.CompressUtils; import io.metersphere.commons.utils.CompressUtils;
import io.metersphere.commons.utils.MybatisInterceptorConfig; import io.metersphere.commons.utils.MybatisInterceptorConfig;
import io.metersphere.interceptor.MybatisInterceptor; import io.metersphere.interceptor.MybatisInterceptor;
import io.metersphere.interceptor.UserDesensitizationInterceptor;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -47,4 +48,9 @@ public class MybatisConfig {
interceptor.setInterceptorConfigList(configList); interceptor.setInterceptorConfigList(configList);
return interceptor; return interceptor;
} }
@Bean
public UserDesensitizationInterceptor userDesensitizationInterceptor() {
return new UserDesensitizationInterceptor();
}
} }

View File

@ -0,0 +1,59 @@
package io.metersphere.interceptor;
import io.metersphere.base.domain.User;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
/**
* 用户 password 字段脱敏
*/
@Intercepts({
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
})
public class UserDesensitizationInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object returnValue = invocation.proceed();
Object result = returnValue;
if (returnValue instanceof ArrayList<?>) {
List<Object> list = new ArrayList<>();
boolean isDecrypted = false;
for (Object val : (ArrayList<?>) returnValue) {
if (val instanceof User) {
isDecrypted = true;
((User) val).setPassword(null);
list.add(val);
}
}
if (isDecrypted) {
result = list;
}
} else {
if (result instanceof User) {
((User) result).setPassword(null);
}
}
return result;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}

@ -1 +1 @@
Subproject commit cf6b06526324326a563d933e07118fac014a63b4 Subproject commit c2dacf960cdb1ed35664bdd3432120b1203b73d8

View File

@ -5,24 +5,24 @@ export default {
name: "api", name: "api",
redirect: "/api/home", redirect: "/api/home",
components: { components: {
content: () => import(/* webpackChunkName: "api" */ '@/business/components/api/ApiTest') content: () => import('@/business/components/api/ApiTest')
}, },
children: [ children: [
{ {
path: 'home', path: 'home',
name: 'fucHome', name: 'fucHome',
component: () => import(/* webpackChunkName: "api" */ '@/business/components/api/home/ApiTestHome'), component: () => import('@/business/components/api/home/ApiTestHome'),
}, },
{ {
path: "test/:type", path: "test/:type",
name: "ApiTestConfig", name: "ApiTestConfig",
component: () => import(/* webpackChunkName: "api" */ '@/business/components/api/test/ApiTestConfig'), component: () => import('@/business/components/api/test/ApiTestConfig'),
props: (route) => ({id: route.query.id}) props: (route) => ({id: route.query.id})
}, },
{ {
path: "test/list/:projectId", path: "test/list/:projectId",
name: "ApiTestList", name: "ApiTestList",
component: () => import(/* webpackChunkName: "api" */ '@/business/components/api/test/ApiTestList'), component: () => import('@/business/components/api/test/ApiTestList'),
}, },
{ {
path: "project/:type", path: "project/:type",
@ -32,12 +32,12 @@ export default {
{ {
path: "report/list/:testId", path: "report/list/:testId",
name: "ApiReportList", name: "ApiReportList",
component: () => import(/* webpackChunkName: "api" */ '@/business/components/api/report/ApiReportList'), component: () => import('@/business/components/api/report/ApiReportList'),
}, },
{ {
path: "report/view/:reportId", path: "report/view/:reportId",
name: "ApiReportView", name: "ApiReportView",
component: () => import(/* webpackChunkName: "api" */ '@/business/components/api/report/ApiReportView'), component: () => import('@/business/components/api/report/ApiReportView'),
} }
] ]
} }

View File

@ -1,12 +1,12 @@
import MsProject from "@/business/components/project/MsProject"; import MsProject from "@/business/components/project/MsProject";
const PerformanceTest = () => import(/* webpackChunkName: "performance" */ '@/business/components/performance/PerformanceTest') const PerformanceTest = () => import('@/business/components/performance/PerformanceTest')
const PerformanceTestHome = () => import(/* webpackChunkName: "performance" */ '@/business/components/performance/home/PerformanceTestHome') const PerformanceTestHome = () => import('@/business/components/performance/home/PerformanceTestHome')
const EditPerformanceTestPlan = () => import(/* webpackChunkName: "performance" */ '@/business/components/performance/test/EditPerformanceTestPlan') const EditPerformanceTestPlan = () => import('@/business/components/performance/test/EditPerformanceTestPlan')
const PerformanceTestPlan = () => import(/* webpackChunkName: "performance" */ '@/business/components/performance/test/PerformanceTestPlan') const PerformanceTestPlan = () => import('@/business/components/performance/test/PerformanceTestPlan')
const PerformanceTestReport = () => import(/* webpackChunkName: "performance" */ '@/business/components/performance/report/PerformanceTestReport') const PerformanceTestReport = () => import('@/business/components/performance/report/PerformanceTestReport')
const PerformanceChart = () => import(/* webpackChunkName: "performance" */ '@/business/components/performance/report/components/PerformanceChart') const PerformanceChart = () => import('@/business/components/performance/report/components/PerformanceChart')
const PerformanceReportView = () => import(/* webpackChunkName: "performance" */ '@/business/components/performance/report/PerformanceReportView') const PerformanceReportView = () => import('@/business/components/performance/report/PerformanceReportView')
export default { export default {
path: "/performance", path: "/performance",

View File

@ -4,69 +4,69 @@ export default {
path: "/setting", path: "/setting",
name: "Setting", name: "Setting",
components: { components: {
content: () => import(/* webpackChunkName: "setting" */ '@/business/components/settings/Setting') content: () => import('@/business/components/settings/Setting')
}, },
children: [ children: [
{ {
path: 'user', path: 'user',
component: () => import(/* webpackChunkName: "setting" */ '@/business/components/settings/system/User'), component: () => import('@/business/components/settings/system/User'),
meta: {system: true, title: 'commons.user'} meta: {system: true, title: 'commons.user'}
}, },
{ {
path: 'organization', path: 'organization',
component: () => import(/* webpackChunkName: "setting" */ '@/business/components/settings/system/Organization'), component: () => import('@/business/components/settings/system/Organization'),
meta: {system: true, title: 'commons.organization'} meta: {system: true, title: 'commons.organization'}
}, },
{ {
path: 'systemworkspace', path: 'systemworkspace',
component: () => import(/* webpackChunkName: "setting" */ '@/business/components/settings/system/SystemWorkspace'), component: () => import('@/business/components/settings/system/SystemWorkspace'),
meta: {system: true, title: 'commons.workspace'} meta: {system: true, title: 'commons.workspace'}
}, },
{ {
path: 'testresourcepool', path: 'testresourcepool',
component: () => import(/* webpackChunkName: "setting" */ '@/business/components/settings/system/TestResourcePool'), component: () => import('@/business/components/settings/system/TestResourcePool'),
meta: {system: true, title: 'commons.test_resource_pool'} meta: {system: true, title: 'commons.test_resource_pool'}
}, },
{ {
path: 'systemparametersetting', path: 'systemparametersetting',
component: () => import(/* webpackChunkName: "setting" */ '@/business/components/settings/system/SystemParameterSetting'), component: () => import('@/business/components/settings/system/SystemParameterSetting'),
meta: {system: true, title: 'commons.system_parameter_setting'} meta: {system: true, title: 'commons.system_parameter_setting'}
}, },
...requireContext.keys().map(key => requireContext(key).system),...requireContext.keys().map(key => requireContext(key).license), ...requireContext.keys().map(key => requireContext(key).system),...requireContext.keys().map(key => requireContext(key).license),
{ {
path: 'organizationmember', path: 'organizationmember',
component: () => import(/* webpackChunkName: "setting" */ '@/business/components/settings/organization/OrganizationMember'), component: () => import('@/business/components/settings/organization/OrganizationMember'),
meta: {organization: true, title: 'commons.member'} meta: {organization: true, title: 'commons.member'}
}, },
{ {
path: 'organizationworkspace', path: 'organizationworkspace',
component: () => import(/* webpackChunkName: "setting" */ '@/business/components/settings/organization/OrganizationWorkspace'), component: () => import('@/business/components/settings/organization/OrganizationWorkspace'),
meta: {organization: true, title: 'commons.workspace'} meta: {organization: true, title: 'commons.workspace'}
}, },
{ {
path: 'serviceintegration', path: 'serviceintegration',
component: () => import(/* webpackChunkName: "setting" */ '@/business/components/settings/organization/ServiceIntegration'), component: () => import('@/business/components/settings/organization/ServiceIntegration'),
meta: {organization: true, title: 'organization.service_integration'} meta: {organization: true, title: 'organization.service_integration'}
}, },
{ {
path: 'member', path: 'member',
component: () => import(/* webpackChunkName: "setting" */ '@/business/components/settings/workspace/WorkspaceMember'), component: () => import('@/business/components/settings/workspace/WorkspaceMember'),
meta: {workspace: true, title: 'commons.member'} meta: {workspace: true, title: 'commons.member'}
}, },
{ {
path: 'testcase/report/template', path: 'testcase/report/template',
name: 'testCaseReportTemplate', name: 'testCaseReportTemplate',
component: () => import(/* webpackChunkName: "setting" */ '@/business/components/settings/workspace/TestCaseReportTemplate'), component: () => import('@/business/components/settings/workspace/TestCaseReportTemplate'),
meta: {workspace: true, title: 'test_track.plan_view.report_template'} meta: {workspace: true, title: 'test_track.plan_view.report_template'}
}, },
{ {
path: 'personsetting', path: 'personsetting',
component: () => import(/* webpackChunkName: "setting" */ '@/business/components/settings/personal/PersonSetting'), component: () => import('@/business/components/settings/personal/PersonSetting'),
meta: {person: true, title: 'commons.personal_setting'} meta: {person: true, title: 'commons.personal_setting'}
}, },
{ {
path: 'apikeys', path: 'apikeys',
component: () => import(/* webpackChunkName: "setting" */ '@/business/components/settings/personal/ApiKeys'), component: () => import('@/business/components/settings/personal/ApiKeys'),
meta: { meta: {
person: true, person: true,
title: 'commons.api_keys', title: 'commons.api_keys',

View File

@ -4,7 +4,8 @@
<el-card class="card-content" v-loading="result.loading"> <el-card class="card-content" v-loading="result.loading">
<template v-slot:header> <template v-slot:header>
<ms-table-header :is-tester-permission="true" :condition.sync="condition" @search="initTableData" :tip="$t('commons.search_by_name_or_id')" <ms-table-header :is-tester-permission="true" :condition.sync="condition" @search="initTableData"
:tip="$t('commons.search_by_name_or_id')"
:create-tip="$t('test_track.case.create')" @create="testCaseCreate"> :create-tip="$t('test_track.case.create')" @create="testCaseCreate">
<template v-slot:title> <template v-slot:title>
<node-breadcrumb class="table-title" :nodes="selectParentNodes" @refresh="refresh"/> <node-breadcrumb class="table-title" :nodes="selectParentNodes" @refresh="refresh"/>
@ -14,10 +15,10 @@
:content="$t('test_track.case.import.import')" @click="importTestCase"/> :content="$t('test_track.case.import.import')" @click="importTestCase"/>
<ms-table-button :is-tester-permission="true" icon="el-icon-upload2" <ms-table-button :is-tester-permission="true" icon="el-icon-upload2"
:content="$t('test_track.case.export.export')" @click="handleBatch('export')"/> :content="$t('test_track.case.export.export')" @click="handleBatch('export')"/>
<!-- <ms-table-button :is-tester-permission="true" icon="el-icon-right" :content="$t('test_track.case.move')"--> <!-- <ms-table-button :is-tester-permission="true" icon="el-icon-right" :content="$t('test_track.case.move')"-->
<!-- @click="handleBatch('move')"/>--> <!-- @click="handleBatch('move')"/>-->
<!-- <ms-table-button :is-tester-permission="true" icon="el-icon-delete" :content="$t('test_track.case.delete')"--> <!-- <ms-table-button :is-tester-permission="true" icon="el-icon-delete" :content="$t('test_track.case.delete')"-->
<!-- @click="handleBatch('delete')"/>--> <!-- @click="handleBatch('delete')"/>-->
<!--<test-case-export/>--> <!--<test-case-export/>-->
</template> </template>
</ms-table-header> </ms-table-header>
@ -127,392 +128,393 @@
<script> <script>
import MsCreateBox from '../../../settings/CreateBox'; import MsCreateBox from '../../../settings/CreateBox';
import TestCaseImport from '../components/TestCaseImport'; import TestCaseImport from '../components/TestCaseImport';
import TestCaseExport from '../components/TestCaseExport'; import TestCaseExport from '../components/TestCaseExport';
import MsTablePagination from '../../../../components/common/pagination/TablePagination'; import MsTablePagination from '../../../../components/common/pagination/TablePagination';
import NodeBreadcrumb from '../../common/NodeBreadcrumb'; import NodeBreadcrumb from '../../common/NodeBreadcrumb';
import MsTableHeader from '../../../../components/common/components/MsTableHeader'; import MsTableHeader from '../../../../components/common/components/MsTableHeader';
import PriorityTableItem from "../../common/tableItems/planview/PriorityTableItem"; import PriorityTableItem from "../../common/tableItems/planview/PriorityTableItem";
import TypeTableItem from "../../common/tableItems/planview/TypeTableItem"; import TypeTableItem from "../../common/tableItems/planview/TypeTableItem";
import MethodTableItem from "../../common/tableItems/planview/MethodTableItem"; import MethodTableItem from "../../common/tableItems/planview/MethodTableItem";
import MsTableOperator from "../../../common/components/MsTableOperator"; 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 {_filter, _sort} from "../../../../../common/js/utils"; import {_filter, _sort} from "../../../../../common/js/utils";
import {TEST_CASE_CONFIGS} from "../../../common/components/search/search-components"; import {TEST_CASE_CONFIGS} from "../../../common/components/search/search-components";
import ShowMoreBtn from "./ShowMoreBtn"; import ShowMoreBtn from "./ShowMoreBtn";
import BatchEdit from "./BatchEdit"; import BatchEdit from "./BatchEdit";
import {WORKSPACE_ID} from "../../../../../common/js/constants"; import {WORKSPACE_ID} from "../../../../../common/js/constants";
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent"; import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
export default { export default {
name: "TestCaseList", name: "TestCaseList",
components: { components: {
MsTableButton, MsTableButton,
MsTableOperatorButton, MsTableOperatorButton,
MsTableOperator, MsTableOperator,
MethodTableItem, MethodTableItem,
TypeTableItem, TypeTableItem,
PriorityTableItem, PriorityTableItem,
MsCreateBox, MsCreateBox,
TestCaseImport, TestCaseImport,
TestCaseExport, TestCaseExport,
MsTablePagination, MsTablePagination,
NodeBreadcrumb, NodeBreadcrumb,
MsTableHeader, MsTableHeader,
ShowMoreBtn, ShowMoreBtn,
BatchEdit BatchEdit
}, },
data() { data() {
return { return {
result: {}, result: {},
deletePath: "/test/case/delete", deletePath: "/test/case/delete",
condition: { condition: {
components: TEST_CASE_CONFIGS components: TEST_CASE_CONFIGS
},
tableData: [],
currentPage: 1,
pageSize: 10,
total: 0,
selectRows: new Set(),
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'}
],
showMore: false,
buttons: [
{
name: this.$t('test_track.case.batch_edit_case'), handleClick: this.handleBatchEdit
}, {
name: this.$t('test_track.case.batch_move_case'), handleClick: this.handleBatchMove
}, {
name: this.$t('test_track.case.batch_delete_case'), handleClick: this.handleDeleteBatch
}
],
typeArr: [
{id: 'priority', name: this.$t('test_track.case.priority')},
{id: 'type', name: this.$t('test_track.case.type')},
{id: 'method', name: this.$t('test_track.case.method')},
{id: 'maintainer', name: this.$t('test_track.case.maintainer')},
],
valueArr: {
priority: [
{name: 'P0', id: 'P0'},
{name: 'P1', id: 'P1'},
{name: 'P2', id: 'P2'},
{name: 'P3', id: 'P3'}
],
type: [
{name: this.$t('commons.functional'), id: 'functional'},
{name: this.$t('commons.performance'), id: 'performance'},
{name: this.$t('commons.api'), id: 'api'}
],
method: [
{name: this.$t('test_track.case.manual'), id: 'manual'},
{name: this.$t('test_track.case.auto'), id: 'auto'}
],
maintainer: [],
}
}
},
props: {
currentProject: {
type: Object
}, },
tableData: [], selectNodeIds: {
currentPage: 1, type: Array
pageSize: 10, },
total: 0, selectParentNodes: {
selectRows: new Set(), type: Array
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'}
],
showMore: false,
buttons: [
{
name: this.$t('test_track.case.batch_edit_case'), handleClick: this.handleBatchEdit
}, {
name: this.$t('test_track.case.batch_move_case'), handleClick: this.handleBatchMove
}, {
name: this.$t('test_track.case.batch_delete_case'), handleClick: this.handleDeleteBatch
}
],
typeArr: [
{id: 'priority', name: this.$t('test_track.case.priority')},
{id: 'type', name: this.$t('test_track.case.type')},
{id: 'method', name: this.$t('test_track.case.method')},
{id: 'maintainer', name: this.$t('test_track.case.maintainer')},
],
valueArr: {
priority: [
{name: 'P0', id: 'P0'},
{name: 'P1', id: 'P1'},
{name: 'P2', id: 'P2'},
{name: 'P3', id: 'P3'}
],
type: [
{name: this.$t('commons.functional'), id: 'functional'},
{name: this.$t('commons.performance'), id: 'performance'},
{name: this.$t('commons.api'), id: 'api'}
],
method: [
{name: this.$t('test_track.case.manual'), id: 'manual'},
{name: this.$t('test_track.case.auto'), id: 'auto'}
],
maintainer: [],
} }
}
},
props: {
currentProject: {
type: Object
}, },
selectNodeIds: { created: function () {
type: Array
},
selectParentNodes: {
type: Array
}
},
created: function () {
this.initTableData();
},
watch: {
currentProject() {
this.initTableData(); this.initTableData();
}, },
selectNodeIds() { watch: {
this.initTableData(); currentProject() {
}
},
methods: {
initTableData() {
if (this.planId) {
// param.planId = this.planId;
this.condition.planId = this.planId;
}
if (this.selectNodeIds && this.selectNodeIds.length > 0) {
// param.nodeIds = this.selectNodeIds;
this.condition.nodeIds = this.selectNodeIds;
}
if (this.currentProject) {
this.condition.projectId = this.currentProject.id;
this.result = this.$post(this.buildPagePath('/test/case/list'), this.condition, response => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
// this.selectIds.clear();
this.selectRows.clear();
});
}
},
search() {
this.initTableData();
},
buildPagePath(path) {
return path + "/" + this.currentPage + "/" + this.pageSize;
},
testCaseCreate() {
this.$emit('testCaseEdit');
},
handleEdit(testCase) {
this.$emit('testCaseEdit', testCase);
},
handleCopy(testCase) {
this.$emit('testCaseCopy', testCase);
},
handleDelete(testCase) {
this.$alert(this.$t('test_track.case.delete_confirm') + '\'' + testCase.name + '\'' + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this._handleDelete(testCase);
}
}
});
},
handleDeleteBatch() {
this.$alert(this.$t('test_track.case.delete_confirm') + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let ids = Array.from(this.selectRows).map(row => row.id);
this.$post('/test/case/batch/delete', {ids: ids}, () => {
this.selectRows.clear();
this.$emit("refresh");
this.$success(this.$t('commons.delete_success'));
// 广 head
TrackEvent.$emit(LIST_CHANGE);
});
}
}
});
},
_handleDelete(testCase) {
let testCaseId = testCase.id;
this.$post('/test/case/delete/' + testCaseId, {}, () => {
this.initTableData(); this.initTableData();
this.$success(this.$t('commons.delete_success')); },
// 广 head selectNodeIds() {
TrackEvent.$emit(LIST_CHANGE); this.currentPage = 1;
}); this.initTableData();
}
}, },
refresh() { methods: {
this.condition = {components: TEST_CASE_CONFIGS}; initTableData() {
// this.selectIds.clear(); if (this.planId) {
this.selectRows.clear(); // param.planId = this.planId;
this.$emit('refresh'); this.condition.planId = this.planId;
}, }
showDetail(row, event, column) { if (this.selectNodeIds && this.selectNodeIds.length > 0) {
this.$emit('testCaseDetail', row); // param.nodeIds = this.selectNodeIds;
}, this.condition.nodeIds = this.selectNodeIds;
handleSelectAll(selection) { }
if (selection.length > 0) { if (this.currentProject) {
if (selection.length === 1) { this.condition.projectId = this.currentProject.id;
this.selectRows.add(selection[0]); this.result = this.$post(this.buildPagePath('/test/case/list'), this.condition, response => {
} else { let data = response.data;
this.tableData.forEach(item => { this.total = data.itemCount;
this.$set(item, "showMore", true); this.tableData = data.listObject;
this.selectRows.add(item); // this.selectIds.clear();
this.selectRows.clear();
}); });
} }
} else { },
this.selectRows.clear(); search() {
this.tableData.forEach(row => { this.initTableData();
this.$set(row, "showMore", false); },
}) buildPagePath(path) {
} return path + "/" + this.currentPage + "/" + this.pageSize;
}, },
handleSelectionChange(selection, row) { testCaseCreate() {
// if (this.selectIds.has(row.id)) { this.$emit('testCaseEdit');
// this.selectIds.delete(row.id); },
// } else { handleEdit(testCase) {
// this.selectIds.add(row.id); this.$emit('testCaseEdit', testCase);
// } },
if (this.selectRows.has(row)) { handleCopy(testCase) {
this.$set(row, "showMore", false); this.$emit('testCaseCopy', testCase);
this.selectRows.delete(row); },
} else { handleDelete(testCase) {
this.$set(row, "showMore", true); this.$alert(this.$t('test_track.case.delete_confirm') + '\'' + testCase.name + '\'' + "", '', {
this.selectRows.add(row); confirmButtonText: this.$t('commons.confirm'),
} callback: (action) => {
if (action === 'confirm') {
let arr = Array.from(this.selectRows); this._handleDelete(testCase);
// 1
if (this.selectRows.size === 1) {
this.$set(arr[0], "showMore", false);
} else if (this.selectRows.size === 2) {
arr.forEach(row => {
this.$set(row, "showMore", true);
})
}
},
importTestCase() {
this.$refs.testCaseImport.open();
},
exportTestCase() {
let ids = Array.from(this.selectRows).map(row => row.id);
let config = {
url: '/test/case/export/testcase',
method: 'post',
responseType: 'blob',
// data: {ids: [...this.selectIds]}
data: {ids: ids, projectId: this.currentProject.id}
};
this.result = this.$request(config).then(response => {
const filename = this.$t('test_track.case.test_case') + ".xlsx";
const blob = new Blob([response.data]);
if ("download" in document.createElement("a")) {
let aTag = document.createElement('a');
aTag.download = filename;
aTag.href = URL.createObjectURL(blob);
aTag.click();
URL.revokeObjectURL(aTag.href)
} else {
navigator.msSaveBlob(blob, filename);
}
});
},
handleBatch(type) {
if (this.selectRows.size < 1) {
if (type === 'export') {
this.$alert(this.$t('test_track.case.export_all_cases'), '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this.exportTestCase();
}
} }
}) }
return; });
},
handleDeleteBatch() {
this.$alert(this.$t('test_track.case.delete_confirm') + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let ids = Array.from(this.selectRows).map(row => row.id);
this.$post('/test/case/batch/delete', {ids: ids}, () => {
this.selectRows.clear();
this.$emit("refresh");
this.$success(this.$t('commons.delete_success'));
// 广 head
TrackEvent.$emit(LIST_CHANGE);
});
}
}
});
},
_handleDelete(testCase) {
let testCaseId = testCase.id;
this.$post('/test/case/delete/' + testCaseId, {}, () => {
this.initTableData();
this.$success(this.$t('commons.delete_success'));
// 广 head
TrackEvent.$emit(LIST_CHANGE);
});
},
refresh() {
this.condition = {components: TEST_CASE_CONFIGS};
// this.selectIds.clear();
this.selectRows.clear();
this.$emit('refresh');
},
showDetail(row, event, column) {
this.$emit('testCaseDetail', row);
},
handleSelectAll(selection) {
if (selection.length > 0) {
if (selection.length === 1) {
this.selectRows.add(selection[0]);
} else {
this.tableData.forEach(item => {
this.$set(item, "showMore", true);
this.selectRows.add(item);
});
}
} else { } else {
this.$warning(this.$t('test_track.plan_view.select_manipulate')); this.selectRows.clear();
return; this.tableData.forEach(row => {
this.$set(row, "showMore", false);
})
} }
} },
if (type === 'move') { handleSelectionChange(selection, row) {
// if (this.selectIds.has(row.id)) {
// this.selectIds.delete(row.id);
// } else {
// this.selectIds.add(row.id);
// }
if (this.selectRows.has(row)) {
this.$set(row, "showMore", false);
this.selectRows.delete(row);
} else {
this.$set(row, "showMore", true);
this.selectRows.add(row);
}
let arr = Array.from(this.selectRows);
// 1
if (this.selectRows.size === 1) {
this.$set(arr[0], "showMore", false);
} else if (this.selectRows.size === 2) {
arr.forEach(row => {
this.$set(row, "showMore", true);
})
}
},
importTestCase() {
this.$refs.testCaseImport.open();
},
exportTestCase() {
let ids = Array.from(this.selectRows).map(row => row.id); let ids = Array.from(this.selectRows).map(row => row.id);
this.$emit('moveToNode', ids); let config = {
} else if (type === 'delete') { url: '/test/case/export/testcase',
this.handleDeleteBatch(); method: 'post',
} else { responseType: 'blob',
this.exportTestCase(); // data: {ids: [...this.selectIds]}
} data: {ids: ids, projectId: this.currentProject.id}
}, };
batchEdit(form) { this.result = this.$request(config).then(response => {
let sign = false; const filename = this.$t('test_track.case.test_case') + ".xlsx";
let arr = Array.from(this.selectRows); const blob = new Blob([response.data]);
// if ("download" in document.createElement("a")) {
if (form.type === 'method' && form.value === 'auto') { let aTag = document.createElement('a');
arr.forEach(row => { aTag.download = filename;
if (row.type === 'functional') { aTag.href = URL.createObjectURL(blob);
sign = true; aTag.click();
return; URL.revokeObjectURL(aTag.href)
} else {
navigator.msSaveBlob(blob, filename);
} }
}); });
} },
handleBatch(type) {
if (form.type === 'type' && form.value === 'functional') { if (this.selectRows.size < 1) {
arr.forEach(row => { if (type === 'export') {
if (row.method === 'auto') { this.$alert(this.$t('test_track.case.export_all_cases'), '', {
sign = true; confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this.exportTestCase();
}
}
})
return;
} else {
this.$warning(this.$t('test_track.plan_view.select_manipulate'));
return; return;
} }
}); }
} if (type === 'move') {
let ids = Array.from(this.selectRows).map(row => row.id);
this.$emit('moveToNode', ids);
} else if (type === 'delete') {
this.handleDeleteBatch();
} else {
this.exportTestCase();
}
},
batchEdit(form) {
let sign = false;
let arr = Array.from(this.selectRows);
//
if (form.type === 'method' && form.value === 'auto') {
arr.forEach(row => {
if (row.type === 'functional') {
sign = true;
return;
}
});
}
let ids = arr.map(row => row.id); if (form.type === 'type' && form.value === 'functional') {
let param = {}; arr.forEach(row => {
param[form.type] = form.value; if (row.method === 'auto') {
param.ids = ids; sign = true;
if (!sign) { return;
this.$post('/test/case/batch/edit', param, () => { }
this.$success(this.$t('commons.save_success')); });
this.refresh(); }
let ids = arr.map(row => row.id);
let param = {};
param[form.type] = form.value;
param.ids = ids;
if (!sign) {
this.$post('/test/case/batch/edit', param, () => {
this.$success(this.$t('commons.save_success'));
this.refresh();
});
} else {
this.$warning("功能测试的测试方式不能设置为自动!");
}
},
filter(filters) {
_filter(filters, this.condition);
this.initTableData();
},
sort(column) {
//
if (this.condition.orders) {
this.condition.orders = [];
}
_sort(column, this.condition);
this.initTableData();
},
handleBatchEdit() {
this.getMaintainerOptions();
this.$refs.batchEdit.open();
},
handleBatchMove() {
this.$emit("batchMove", Array.from(this.selectRows).map(row => row.id));
},
getMaintainerOptions() {
let workspaceId = localStorage.getItem(WORKSPACE_ID);
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
this.valueArr.maintainer = response.data;
}); });
} else {
this.$warning("功能测试的测试方式不能设置为自动!");
} }
},
filter(filters) {
_filter(filters, this.condition);
this.initTableData();
},
sort(column) {
//
if (this.condition.orders) {
this.condition.orders = [];
}
_sort(column, this.condition);
this.initTableData();
},
handleBatchEdit() {
this.getMaintainerOptions();
this.$refs.batchEdit.open();
},
handleBatchMove() {
this.$emit("batchMove", Array.from(this.selectRows).map(row => row.id));
},
getMaintainerOptions() {
let workspaceId = localStorage.getItem(WORKSPACE_ID);
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
this.valueArr.maintainer = response.data;
});
} }
} }
}
</script> </script>
<style scoped> <style scoped>
.table-page { .table-page {
padding-top: 20px; padding-top: 20px;
margin-right: -9px; margin-right: -9px;
float: right; float: right;
} }
.operate-button { .operate-button {
float: right; float: right;
} }
.operate-button > div { .operate-button > div {
display: inline-block; display: inline-block;
margin-left: 10px; margin-left: 10px;
} }
.search { .search {
margin-left: 10px; margin-left: 10px;
width: 240px; width: 240px;
} }
.el-table { .el-table {
cursor: pointer; cursor: pointer;
} }
</style> </style>

View File

@ -437,14 +437,10 @@
}, },
handleSelectAll(selection) { handleSelectAll(selection) {
if (selection.length > 0) { if (selection.length > 0) {
if (selection.length === 1) { this.tableData.forEach(item => {
this.selectRows.add(selection[0]); this.$set(item, "showMore", true);
} else { this.selectRows.add(item);
this.tableData.forEach(item => { });
this.$set(item, "showMore", true);
this.selectRows.add(item);
});
}
} else { } else {
this.selectRows.clear(); this.selectRows.clear();
this.tableData.forEach(row => { this.tableData.forEach(row => {
@ -460,17 +456,6 @@
this.$set(row, "showMore", true); this.$set(row, "showMore", true);
this.selectRows.add(row); this.selectRows.add(row);
} }
let arr = Array.from(this.selectRows);
// 1
if (this.selectRows.size === 1) {
this.$set(arr[0], "showMore", false);
} else if (this.selectRows.size === 2) {
arr.forEach(row => {
this.$set(row, "showMore", true);
})
}
}, },
handleBatch(type) { handleBatch(type) {
if (this.selectRows.size < 1) { if (this.selectRows.size < 1) {

View File

@ -1,12 +1,12 @@
import MsProject from "@/business/components/project/MsProject"; import MsProject from "@/business/components/project/MsProject";
const TestTrack = () => import(/* webpackChunkName: "track" */ '@/business/components/track/TestTrack') const TestTrack = () => import('@/business/components/track/TestTrack')
const TrackHome = () => import(/* webpackChunkName: "track" */ '@/business/components/track/home/TrackHome') const TrackHome = () => import('@/business/components/track/home/TrackHome')
const TestCase = () => import(/* webpackChunkName: "track" */ '@/business/components/track/case/TestCase') const TestCase = () => import('@/business/components/track/case/TestCase')
const TestPlan = () => import(/* webpackChunkName: "track" */ '@/business/components/track/plan/TestPlan') const TestPlan = () => import('@/business/components/track/plan/TestPlan')
const TestCaseReview = () => import(/* webpackChunkName: "track" */ '@/business/components/track/review/TestCaseReview') const TestCaseReview = () => import('@/business/components/track/review/TestCaseReview')
const TestCaseReviewView = () => import(/* webpackChunkName: "track" */ '@/business/components/track/review/view/TestCaseReviewView') const TestCaseReviewView = () => import('@/business/components/track/review/view/TestCaseReviewView')
const TestPlanView = () => import(/* webpackChunkName: "track" */ '@/business/components/track/plan/view/TestPlanView') const TestPlanView = () => import('@/business/components/track/plan/view/TestPlanView')
export default { export default {
path: "/track", path: "/track",

View File

@ -1,8 +1,11 @@
const path = require('path')
function resolve(dir) {
return path.join(__dirname, dir)
}
module.exports = { module.exports = {
productionSourceMap: true, productionSourceMap: true,
configureWebpack: {
devtool: 'source-map'
},
devServer: { devServer: {
port: 8080, port: 8080,
proxy: { proxy: {
@ -23,5 +26,16 @@ module.exports = {
template: "src/login/login.html", template: "src/login/login.html",
filename: "login.html" filename: "login.html"
} }
},
configureWebpack: {
devtool: 'source-map',
resolve: {
alias: {
'@': resolve('src')
}
}
},
chainWebpack(config) {
config.plugins.delete('prefetch')
} }
}; };