Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
q4speed 2020-05-09 14:51:51 +08:00
commit efec984b90
42 changed files with 758 additions and 470 deletions

View File

@ -1,18 +1,13 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.base.domain.TestCase;
import io.metersphere.controller.request.testcase.QueryTestCaseRequest;
import io.metersphere.controller.request.testplancase.QueryTestPlanCaseRequest;
import io.metersphere.dto.TestCaseReportMetricDTO;
import io.metersphere.dto.TestCaseReportResultDTO;
import io.metersphere.dto.TestPlanCaseDTO;
import io.metersphere.dto.TestCaseReportStatusResultDTO;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtTestPlanTestCaseMapper {
List<TestCaseReportResultDTO> getReportMetric(@Param("planId") String planId);
List<TestCaseReportStatusResultDTO> getReportMetric(@Param("planId") String planId);
List<String> getExecutors(@Param("planId") String planId);
}

View File

@ -2,7 +2,7 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper">
<select id="getReportMetric" parameterType="java.lang.String" resultType="io.metersphere.dto.TestCaseReportResultDTO">
<select id="getReportMetric" parameterType="java.lang.String" resultType="io.metersphere.dto.TestCaseReportStatusResultDTO">
select count(t1.id) as `count`, t1.status
from test_plan_test_case t1
inner join test_case t2

View File

@ -2,6 +2,7 @@ package io.metersphere.controller;
import io.metersphere.base.domain.TestCaseReport;
import io.metersphere.controller.request.testCaseReport.CreateReportRequest;
import io.metersphere.dto.TestCaseReportMetricDTO;
import io.metersphere.service.TestCaseReportService;
import org.springframework.web.bind.annotation.*;
@ -41,7 +42,7 @@ public class TestCaseReportController {
}
@GetMapping("/get/metric/{planId}")
public TestCaseReport getMetric(@PathVariable String planId){
public TestCaseReportMetricDTO getMetric(@PathVariable String planId){
return testCaseReportService.getMetric(planId);
}
}

View File

@ -118,10 +118,8 @@ public class UserController {
return userService.getUserList();
}
@PostMapping("/update/currentuser")
@PostMapping("/update/current")
public UserDTO updateCurrentUser(@RequestBody User user) {
SessionUser sessionUser = SessionUtils.getUser();
BeanUtils.copyProperties(user, sessionUser);
userService.updateUser(user);
return SessionUtils.getUser();
}

View File

@ -9,6 +9,7 @@ import io.metersphere.commons.utils.Pager;
import io.metersphere.controller.request.WorkspaceRequest;
import io.metersphere.dto.WorkspaceDTO;
import io.metersphere.dto.WorkspaceMemberDTO;
import io.metersphere.service.OrganizationService;
import io.metersphere.service.WorkspaceService;
import io.metersphere.user.SessionUtils;
import org.apache.shiro.authz.annotation.Logical;
@ -23,11 +24,14 @@ import java.util.List;
public class WorkspaceController {
@Resource
private WorkspaceService workspaceService;
@Resource
private OrganizationService organizationService;
@PostMapping("add")
@RequiresRoles(RoleConstants.ORG_ADMIN)
public Workspace addWorkspace(@RequestBody Workspace workspace) {
workspaceService.checkWorkspaceOwnerByOrgAdmin(workspace.getId());
String currentOrganizationId = SessionUtils.getCurrentOrganizationId();
organizationService.checkOrgOwner(currentOrganizationId);
return workspaceService.saveWorkspace(workspace);
}

View File

@ -7,7 +7,7 @@ import java.util.List;
@Data
public class TestCaseReportMetricDTO {
private List<TestCaseReportResultDTO> executeResult;
private List<TestCaseReportStatusResultDTO> executeResult;
private List<TestCaseReportModuleResultDTO> moduleExecuteResult;
private List<String> executors;
private String principal;

View File

@ -4,8 +4,10 @@ import lombok.Data;
@Data
public class TestCaseReportModuleResultDTO {
private String module;
private String moduleId;
private String moduleName;
private Integer caseCount;
private Integer passRate;
private Integer passCount;
private Double passRate;
private Integer flawCount;
}

View File

@ -1,9 +1,9 @@
package io.metersphere.dto;
import lombok.Data;
@Data
public class TestCaseReportResultDTO {
public class TestCaseReportStatusResultDTO {
private String status;
private String count;
private Integer count;
}

View File

@ -7,7 +7,9 @@ import io.metersphere.base.domain.TestCaseWithBLOBs;
import io.metersphere.commons.constants.TestCaseConstants;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.service.TestCaseService;
import org.apache.commons.lang3.StringUtils;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.UUID;
@ -38,12 +40,19 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
public String validate(TestCaseExcelData data, String errMsg) {
String nodePath = data.getNodePath();
StringBuilder stringBuilder = new StringBuilder(errMsg);
if ( nodePath.split("/").length > TestCaseConstants.MAX_NODE_DEPTH + 1) {
String[] nodes = nodePath.split("/");
if ( nodes.length > TestCaseConstants.MAX_NODE_DEPTH + 1) {
stringBuilder.append("节点最多为" + TestCaseConstants.MAX_NODE_DEPTH + "层;");
}
if ( nodePath.trim().contains(" ")) {
stringBuilder.append("所属模块不能包含空格");
for (int i = 0; i < nodes.length; i++) {
if (i != 0 && StringUtils.equals(nodes[i].trim(), "")) {
stringBuilder.append("所属模块不能为空格");
break;
}
}
if (!userIds.contains(data.getMaintainer())) {
stringBuilder.append("该工作空间下无该用户:" + data.getMaintainer() + ";");
}

View File

@ -51,7 +51,7 @@ public class TestCaseNodeService {
return getNodeTrees(nodes);
}
private List<TestCaseNodeDTO> getNodeTrees(List<TestCaseNode> nodes) {
public List<TestCaseNodeDTO> getNodeTrees(List<TestCaseNode> nodes) {
List<TestCaseNodeDTO> nodeTreeList = new ArrayList<>();
@ -91,12 +91,12 @@ public class TestCaseNodeService {
return nodeTree;
}
List<TestCaseNodeDTO> childrens = Optional.ofNullable(nodeTree.getChildren()).orElse(new ArrayList<>());
List<TestCaseNodeDTO> children = Optional.ofNullable(nodeTree.getChildren()).orElse(new ArrayList<>());
lowerNodes.forEach(node -> {
if (node.getParentId() != null && node.getParentId().equals(rootNode.getId())){
childrens.add(buildNodeTree(nodeLevelMap, node));
nodeTree.setChildren(childrens);
children.add(buildNodeTree(nodeLevelMap, node));
nodeTree.setChildren(children);
}
});

View File

@ -2,20 +2,21 @@ package io.metersphere.service;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper;
import io.metersphere.commons.constants.TestPlanTestCaseStatus;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.controller.request.testCaseReport.CreateReportRequest;
import io.metersphere.controller.request.testcase.QueryTestPlanRequest;
import io.metersphere.dto.TestCaseNodeDTO;
import io.metersphere.dto.TestCaseReportMetricDTO;
import io.metersphere.dto.TestCaseReportResultDTO;
import io.metersphere.dto.TestPlanDTO;
import io.metersphere.controller.request.testplancase.QueryTestPlanCaseRequest;
import io.metersphere.dto.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
@Service
@ -46,6 +47,9 @@ public class TestCaseReportService {
@Resource
TestPlanTestCaseMapper testPlanTestCaseMapper;
@Resource
ExtTestCaseMapper extTestCaseMapper;
public List<TestCaseReport> listTestCaseReport(TestCaseReport request) {
TestCaseReportExample example = new TestCaseReportExample();
if ( StringUtils.isNotBlank(request.getName()) ) {
@ -84,41 +88,110 @@ public class TestCaseReportService {
return report.getId();
}
public TestCaseReport getMetric(String planId) {
TestCaseReportMetricDTO testCaseReportMetricDTO = new TestCaseReportMetricDTO();
testCaseReportMetricDTO.setExecutors(extTestPlanTestCaseMapper.getExecutors(planId));
testCaseReportMetricDTO.setExecuteResult(extTestPlanTestCaseMapper.getReportMetric(planId));
public TestCaseReportMetricDTO getMetric(String planId) {
QueryTestPlanRequest queryTestPlanRequest = new QueryTestPlanRequest();
queryTestPlanRequest.setId(planId);
TestPlanDTO testPlan = extTestPlanMapper.list(queryTestPlanRequest).get(0);
testCaseReportMetricDTO.setProjectName(testPlan.getProjectName());
testCaseReportMetricDTO.setPrincipal(testPlan.getPrincipal());
TestPlanTestCaseExample example = new TestPlanTestCaseExample();
example.createCriteria().andPlanIdEqualTo(planId);
List<TestPlanTestCase> testPlanTestCases = testPlanTestCaseMapper.selectByExample(example);
Set<String> executors = new HashSet<>();
Map<String, TestCaseReportStatusResultDTO> reportStatusResultMap = new HashMap<>();
TestCaseNodeExample testCaseNodeExample = new TestCaseNodeExample();
testCaseNodeExample.createCriteria().andProjectIdEqualTo(testPlan.getProjectId());
List<TestCaseNode> nodes = testCaseNodeMapper.selectByExample(testCaseNodeExample);
return null;
List<TestCaseNodeDTO> nodeTrees = testCaseNodeService.getNodeTrees(nodes);
Map<String, Set<String>> childIdMap = new HashMap<>();
nodeTrees.forEach(item -> {
Set<String> childIds = new HashSet<>();
getChildIds(item, childIds);
childIdMap.put(item.getId(), childIds);
});
QueryTestPlanCaseRequest request = new QueryTestPlanCaseRequest();
request.setPlanId(planId);
List<TestPlanCaseDTO> testPlanTestCases = extTestCaseMapper.getTestPlanTestCases(request);
Map<String, TestCaseReportModuleResultDTO> moduleResultMap = new HashMap<>();
for (TestPlanCaseDTO testCase: testPlanTestCases) {
executors.add(testCase.getExecutor());
getStatusResultMap(reportStatusResultMap, testCase);
getModuleResultMap(childIdMap, moduleResultMap, testCase, nodeTrees);
}
nodeTrees.forEach(rootNode -> {
TestCaseReportModuleResultDTO moduleResult = moduleResultMap.get(rootNode.getId());
if (moduleResult != null) {
moduleResult.setModuleName(rootNode.getName());
}
});
for (TestCaseReportModuleResultDTO moduleResult : moduleResultMap.values()) {
moduleResult.setPassRate(new BigDecimal(moduleResult.getPassCount()*1.0f/moduleResult.getCaseCount())
.setScale(2, BigDecimal.ROUND_HALF_UP)
.doubleValue() * 100);
if (moduleResult.getCaseCount() <= 0) {
moduleResultMap.remove(moduleResult.getModuleId());
}
}
TestCaseReportMetricDTO testCaseReportMetricDTO = new TestCaseReportMetricDTO();
testCaseReportMetricDTO.setProjectName(testPlan.getProjectName());
testCaseReportMetricDTO.setPrincipal(testPlan.getPrincipal());
testCaseReportMetricDTO.setExecutors(new ArrayList<>(executors));
testCaseReportMetricDTO.setExecuteResult(new ArrayList<>(reportStatusResultMap.values()));
testCaseReportMetricDTO.setModuleExecuteResult(new ArrayList<>(moduleResultMap.values()));
return testCaseReportMetricDTO;
}
private TestCaseReport get(List<TestCaseNode> nodes) {
// List<TestCaseNode> rootNode = new ArrayList<>();
// Map<String, List<String>> nodeMap = new HashMap<>();
// nodes.forEach(node -> {
// Integer level = node.getLevel();
// if (level == 1) {
// rootNode.add(node);
// ArrayList<Object> objects = new ArrayList<>();
// }
// });
return null;
private void getStatusResultMap(Map<String, TestCaseReportStatusResultDTO> reportStatusResultMap, TestPlanCaseDTO testCase) {
TestCaseReportStatusResultDTO statusResult = reportStatusResultMap.get(testCase.getStatus());
if (statusResult == null) {
statusResult = new TestCaseReportStatusResultDTO();
statusResult.setStatus(testCase.getStatus());
statusResult.setCount(0);
}
statusResult.setCount(statusResult.getCount() + 1);
reportStatusResultMap.put(testCase.getStatus(), statusResult);
}
private void getModuleResultMap(Map<String, Set<String>> childIdMap, Map<String, TestCaseReportModuleResultDTO> moduleResultMap, TestPlanCaseDTO testCase, List<TestCaseNodeDTO> nodeTrees) {
childIdMap.forEach((rootNodeId, childIds) -> {
if (childIds.contains(testCase.getNodeId())) {
TestCaseReportModuleResultDTO moduleResult = moduleResultMap.get(rootNodeId);
if (moduleResult == null) {
moduleResult = new TestCaseReportModuleResultDTO();
moduleResult.setCaseCount(0);
moduleResult.setPassCount(0);
moduleResult.setModuleId(rootNodeId);
}
moduleResult.setCaseCount(moduleResult.getCaseCount() + 1);
if (StringUtils.equals(testCase.getStatus(), TestPlanTestCaseStatus.Pass.name())) {
moduleResult.setPassCount(moduleResult.getPassCount() + 1);
}
moduleResultMap.put(rootNodeId, moduleResult);
return;
}
});
}
private void getChildIds(TestCaseNodeDTO rootNode, Set<String> childIds) {
childIds.add(rootNode.getId());
List<TestCaseNodeDTO> children = rootNode.getChildren();
if(children != null) {
Iterator<TestCaseNodeDTO> iterator = children.iterator();
while(iterator.hasNext()){
getChildIds(iterator.next(), childIds);
}
}
}
}

View File

@ -11,10 +11,7 @@ import io.metersphere.controller.request.member.AddMemberRequest;
import io.metersphere.controller.request.member.QueryMemberRequest;
import io.metersphere.controller.request.organization.AddOrgMemberRequest;
import io.metersphere.controller.request.organization.QueryOrgMemberRequest;
import io.metersphere.dto.OrganizationMemberDTO;
import io.metersphere.dto.UserDTO;
import io.metersphere.dto.UserRoleDTO;
import io.metersphere.dto.UserRoleHelpDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.user.SessionUser;
import io.metersphere.user.SessionUtils;
@ -23,8 +20,10 @@ import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.*;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@Service
@ -70,7 +69,8 @@ public class UserService {
user.setUpdateTime(System.currentTimeMillis());
// 默认1:启用状态
user.setStatus("1");
// 密码使用 MD5
user.setPassword(CodingUtil.md5(user.getPassword()));
UserExample userExample = new UserExample();
UserExample.Criteria criteria = userExample.createCriteria();
criteria.andEmailEqualTo(user.getEmail());
@ -124,6 +124,11 @@ public class UserService {
}
public void updateUser(User user) {
UserDTO userDTO = getUserDTO(user.getId());
BeanUtils.copyProperties(user, userDTO);
// MD5
user.setPassword(CodingUtil.md5(user.getPassword()));
SessionUtils.putUser(SessionUser.fromUser(userDTO));
user.setUpdateTime(System.currentTimeMillis());
userMapper.updateByPrimaryKeySelective(user);
}

View File

@ -2,7 +2,7 @@
<div class="dialog-footer">
<el-button @click="cancel"> </el-button>
<el-button type="primary" @click="confirm"> </el-button>
<el-button type="primary" @click="confirm" @keydown.enter.native.prevent> </el-button>
</div>
</template>

View File

@ -14,7 +14,7 @@
<style scoped>
#body {
width: 100%;
height: calc(100vh - 80px);
height: calc(100vh - 40px);
background-color: #F5F5F5;
}

View File

@ -2,7 +2,8 @@
<div v-loading="result.loading">
<el-tabs type="border-card" :stretch="true">
<el-tab-pane v-for="(item, key) in logContent" :key="key" :label="key" class="logging-content">
{{item}}
{{item.substring(0, 2048) }}...
<el-link type="primary" @click="downloadLogFile(item)">{{$t('load_test.download_log_file')}}</el-link>
</el-tab-pane>
</el-tabs>
</div>
@ -23,6 +24,22 @@
this.result = this.$get("/performance/report/log/" + this.id, res => {
this.logContent = res.data;
})
},
downloadLogFile(content) {
const filename = 'jmeter.log'
const blob = new Blob([content]);
if ("download" in document.createElement("a")) {
// IE
// chrome/firefox
let aTag = document.createElement('a');
aTag.download = filename;
aTag.href = URL.createObjectURL(blob);
aTag.click();
URL.revokeObjectURL(aTag.href)
} else {
// IE10+
navigator.msSaveBlob(blob, filename);
}
}
},
watch: {
@ -39,7 +56,6 @@
.logging-content {
white-space: pre-line;
overflow: auto;
height: calc(100vh - 420px);
}
</style>

View File

@ -1,28 +1,35 @@
<template>
<div>
<el-row type="flex" justify="start">
<el-col :span="8">
<h3>{{$t('load_test.domain_bind')}}</h3>
</el-col>
<el-col :span="8">
<el-button type="primary" plain size="mini" @click="add('domains')">{{$t('commons.add')}}</el-button>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="add('domains')">{{$t('commons.add')}}</el-button>
</el-col>
</el-row>
<!-- -->
<el-row>
<el-table :data="domains">
<el-col :span="20">
<el-table :data="domains" size="mini" class="tb-edit" align="center" border highlight-current-row>
<el-table-column
align="center"
:label="$t('load_test.domain')"
show-overflow-tooltip>
<template v-slot:default="{row}">
<template v-if="row.edit">
<el-input v-model="row.domain" class="edit-input" size="mini"/>
</template>
<span v-else>{{ row.domain }}</span>
<el-input
size="mini"
v-if="readOnly"
type="textarea"
:rows="1"
class="edit-input"
v-model="row.domain"
:placeholder="$t('load_test.domain')"
clearable>
</el-input>
<span >{{row.domain}}</span>
</template>
</el-table-column>
<el-table-column
align="center"
:label="$t('load_test.enable')"
show-overflow-tooltip>
<template v-slot:default="{row}">
@ -31,46 +38,36 @@
size="mini"
v-model="row.enable"
active-color="#13ce66"
inactive-color="#ff4949">
inactive-color="#ff4949"
@click="confirmEdit(row)"
>
</el-switch>
</template>
</el-table-column>
<el-table-column
align="center"
:label="$t('load_test.ip')"
show-overflow-tooltip>
<template v-slot:default="{row}">
<template v-if="row.edit">
<el-input v-model="row.ip" class="edit-input" size="mini"/>
</template>
<span v-else>{{ row.ip }}</span>
<el-input
size="mini"
v-if="readOnly"
type="textarea"
class="edit-input"
:rows="1"
v-model="row.ip"
:placeholder="$t('load_test.ip')"
clearable></el-input>
<span>{{row.ip}}</span>
</template>
</el-table-column>
<el-table-column align="center">
<el-table-column align="center" :label="$t('load_test.operating')">
<template v-slot:default="{row, $index}">
<template v-if="row.edit">
<el-button
class="cancel-btn"
size="mini"
icon="el-icon-refresh"
type="warning"
circle
@click="cancelEdit(row)">
</el-button>
<el-button
type="success"
size="mini"
icon="el-icon-circle-check"
circle
@click="confirmEdit(row)">
</el-button>
</template>
<el-button
v-else
type="primary"
size="mini"
icon="el-icon-edit"
circle
@click="edit(row)">
icon="el-icon-plus"
circle size="mini"
@click="add('domains')">
</el-button>
<el-button
type="danger"
@ -82,31 +79,39 @@
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<h3>{{$t('load_test.params')}}</h3>
</el-col>
<el-col :span="8">
<el-button type="primary" plain size="mini" @click="add('params')">{{$t('commons.add')}}</el-button>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="add('params')">{{$t('commons.add')}}</el-button>
</el-col>
</el-row>
<!-- -->
<el-row>
<el-table :data="params">
<el-col :span="20">
<el-table :data="params" size="mini" class="tb-edit" align="center" border highlight-current-row>
<el-table-column
align="center"
:label="$t('load_test.param_name')"
show-overflow-tooltip>
<template v-slot:default="{row}">
<template v-if="row.edit">
<el-input v-model="row.name" class="edit-input" size="mini"/>
</template>
<span v-else>{{ row.name }}</span>
<el-input
size="mini"
v-if="readOnly"
type="textarea"
:rows="1"
class="edit-input"
v-model="row.name"
:placeholder="$t('load_test.param_name')"
clearable>
</el-input>
<span >{{row.name}}</span>
</template>
</el-table-column>
<el-table-column
align="center"
:label="$t('load_test.enable')"
show-overflow-tooltip>
<template v-slot:default="{row}">
@ -121,40 +126,32 @@
</el-table-column>
<el-table-column
:label="$t('load_test.param_value')"
show-overflow-tooltip>
show-overflow-tooltip align="center">
<template v-slot:default="{row}">
<template v-if="row.edit">
<!-- <template v-if="row.edit">
<el-input v-model="row.value" class="edit-input" size="mini"/>
</template>
<span v-else>{{ row.value }}</span>
<span v-else>{{ row.value }}</span>-->
<el-input
size="mini"
v-if="readOnly"
type="textarea"
class="edit-input"
:rows="1"
v-model="row.value"
:placeholder="$t('load_test.param_value')"
clearable></el-input>
<span>{{row.value}}</span>
</template>
</el-table-column>
<el-table-column align="center">
<el-table-column align="center" :label="$t('load_test.operating')">
<template v-slot:default="{row, $index}">
<template v-if="row.edit">
<el-button
class="cancel-btn"
size="mini"
icon="el-icon-refresh"
type="warning"
circle
@click="cancelEdit(row)">
</el-button>
<el-button
type="success"
size="mini"
icon="el-icon-circle-check"
circle
@click="confirmEdit(row)">
</el-button>
</template>
<el-button
v-else
type="primary"
size="mini"
icon="el-icon-edit"
icon="el-icon-plus"
circle
@click="edit(row)">
@click="add(row)">
</el-button>
<el-button
type="danger"
@ -166,6 +163,7 @@
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
<el-row>
@ -211,6 +209,12 @@
statusCodeStr: '',
}
},
props: {
readOnly: {
type: Boolean,
default: true
},
},
mounted() {
let testId = this.$route.path.split('/')[4];
if (testId) {
@ -253,8 +257,9 @@
this.statusCodeStr = this.statusCode.join(',');
this.domains = data.domains || [];
this.params = data.params || [];
this.domains.forEach(d => d.edit = false);
this.params.forEach(d => d.edit = false);
this.add('domains');
/*this.domains.forEach(d => d.edit = false);
this.params.forEach(d => d.edit = false);*/
}
});
},
@ -262,7 +267,7 @@
if (dataName === 'domains') {
this[dataName].push({
domain: 'fit2cloud.com',
enable: true,
enable: false,
ip: '127.0.0.1',
edit: true,
});
@ -290,6 +295,7 @@
},
confirmEdit(row) {
row.edit = false;
row.enable=true,
this.saveOriginObject(row);
},
groupBy(data, key) {
@ -360,7 +366,22 @@
}
.edit-input {
padding-right: 100px;
padding-right: 0px;
}
.tb-edit .el-textarea {
display: none;
}
.tb-edit .current-row .el-textarea {
display: block;
}
.tb-edit .current-row .el-textarea+span {
display: none;
}
.el-col{
text-align: left;
}
.el-col .el-table{
align:center;
}
</style>

View File

@ -90,6 +90,7 @@
</el-form>
</el-col>
<el-col :span="14">
<div class="title">{{$t('load_test.pressure_prediction_chart')}}</div>
<chart class="chart-container" ref="chart1" :options="orgOptions" :autoresize="true"></chart>
</el-col>
</el-row>
@ -306,9 +307,11 @@
}
</script>
<style scoped>
.pressure-config-container .el-input {
width: 130px;
}
.pressure-config-container .config-form-label {
@ -323,4 +326,15 @@
.chart-container {
width: 100%;
}
.el-col .el-form{
margin-top: 15px;
text-align: left;
}
.el-col {
margin-top: 15px;
text-align: left;
}
.title {
margin-left: 60px;
}
</style>

View File

@ -31,9 +31,9 @@
</el-form>
<template v-slot:footer>
<div class="dialog-footer">
<el-button type="primary" @keydown.enter.native.prevent @click="submit('form')" size="medium">
{{$t('commons.save')}}
</el-button>
<ms-dialog-footer
@cancel="createVisible = false"
@confirm="submit('form')"/>
</div>
</template>
</el-dialog>
@ -48,10 +48,11 @@
import MsTablePagination from "../common/pagination/TablePagination";
import MsTableHeader from "../common/components/MsTableHeader";
import MsTableOperator from "../common/components/MsTableOperator";
import MsDialogFooter from "../common/components/MsDialogFooter";
export default {
name: "MsProject",
components: {MsTableOperator, MsCreateBox, MsTablePagination, MsTableHeader},
components: {MsTableOperator, MsCreateBox, MsTablePagination, MsTableHeader, MsDialogFooter},
data() {
return {
createVisible: false,

View File

@ -25,7 +25,7 @@
</el-card>
<el-dialog :title="$t('member.create')" :visible.sync="createVisible" width="30%" :destroy-on-close="true"
@close="closeFunc">
@close="handleClose">
<el-form :model="form" ref="form" :rules="rules" label-position="right" label-width="100px" size="small">
<el-form-item :label="$t('commons.member')" prop="userIds">
<el-select v-model="form.userIds" multiple :placeholder="$t('member.please_choose_member')"
@ -52,16 +52,14 @@
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button @click="submitForm('form')" @keydown.enter.native.prevent type="primary"
size="medium">{{$t('commons.save')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="createVisible = false"
@confirm="submitForm('form')"/>
</template>
</el-dialog>
<el-dialog :title="$t('member.modify')" :visible.sync="updateVisible" width="30%" :destroy-on-close="true"
@close="closeFunc">
@close="handleClose">
<el-form :model="form" label-position="right" label-width="100px" size="small" ref="updateUserForm">
<el-form-item label="ID" prop="id">
<el-input v-model="form.id" autocomplete="off" :disabled="true"/>
@ -87,11 +85,9 @@
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button @click="updateOrgMember('updateUserForm')" @keydown.enter.native.prevent type="primary"
size="medium">{{$t('commons.save')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="updateVisible = false"
@confirm="updateOrgMember('updateUserForm')"/>
</template>
</el-dialog>
</div>
@ -104,10 +100,11 @@
import MsTableHeader from "../../common/components/MsTableHeader";
import MsRolesTag from "../../common/components/MsRolesTag";
import MsTableOperator from "../../common/components/MsTableOperator";
import MsDialogFooter from "../../common/components/MsDialogFooter";
export default {
name: "MsOrganizationMember",
components: {MsCreateBox, MsTablePagination, MsTableHeader, MsRolesTag, MsTableOperator},
components: {MsCreateBox, MsTablePagination, MsTableHeader, MsRolesTag, MsTableOperator, MsDialogFooter},
created() {
this.initTableData();
},
@ -161,13 +158,12 @@
buildPagePath(path) {
return path + "/" + this.currentPage + "/" + this.pageSize;
},
closeFunc() {
handleClose() {
this.form = {};
this.initTableData();
},
edit(row) {
this.updateVisible = true;
this.form = row;
this.form = Object.assign({}, row);
let roleIds = this.form.roles.map(r => r.id);
this.result = this.$get('/role/list/org', response => {
this.$set(this.form, "allroles", response.data);

View File

@ -34,11 +34,9 @@
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button @click="submit('form')" @keydown.enter.native.prevent type="primary"
size="medium">{{$t('commons.save')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="dialogWsAddVisible = false"
@confirm="submit('form')"/>
</template>
</el-dialog>
@ -99,11 +97,9 @@
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button @click="submitForm('form')" @keydown.enter.native.prevent type="primary"
size="medium">{{$t('commons.save')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="dialogWsMemberAddVisible = false"
@confirm="submitForm('form')"/>
</template>
</el-dialog>
@ -137,11 +133,9 @@
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button @click="updateOrgMember('updateUserForm')" @keydown.enter.native.prevent type="primary"
size="medium">{{$t('commons.save')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="dialogWsMemberUpdateVisible = false"
@confirm="updateOrgMember('updateUserForm')"/>
</template>
</el-dialog>
@ -156,10 +150,11 @@
import MsTableHeader from "../../common/components/MsTableHeader";
import MsRolesTag from "../../common/components/MsRolesTag";
import MsTableOperator from "../../common/components/MsTableOperator";
import MsDialogFooter from "../../common/components/MsDialogFooter";
export default {
name: "MsOrganizationWorkspace",
components: {MsCreateBox, MsTablePagination, MsTableHeader, MsRolesTag, MsTableOperator},
components: {MsCreateBox, MsTablePagination, MsTableHeader, MsRolesTag, MsTableOperator, MsDialogFooter},
mounted() {
this.list();
},
@ -193,7 +188,7 @@
},
edit(row) {
this.dialogWsAddVisible = true;
this.form = row;
this.form = Object.assign({}, row);
},
del(row) {
this.$confirm(this.$t('workspace.delete_confirm'), '', {
@ -317,7 +312,7 @@
},
editMember(row) {
this.dialogWsMemberUpdateVisible = true;
this.memberForm = row;
this.memberForm = Object.assign({}, row);
let roleIds = this.memberForm.roles.map(r => r.id);
this.result = this.$get('/role/list/test', response => {
this.$set(this.memberForm, "allroles", response.data);

View File

@ -28,7 +28,7 @@
</el-table>
<el-dialog :title="$t('member.modify_personal_info')" :visible.sync="updateVisible" width="30%"
:destroy-on-close="true" @close="closeFunc">
:destroy-on-close="true" @close="handleClose">
<el-form :model="form" label-position="right" label-width="100px" size="small" :rules="rule"
ref="updateUserForm">
<el-form-item label="ID" prop="id">
@ -43,13 +43,14 @@
<el-form-item :label="$t('commons.phone')" prop="phone">
<el-input v-model="form.phone" autocomplete="off"/>
</el-form-item>
<el-form-item :label="$t('commons.password')" prop="password">
<el-input v-model="form.password" autocomplete="off" show-password/>
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button @click="updateUser('updateUserForm')" @keydown.enter.native.prevent type="primary"
size="medium">{{$t('commons.save')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="updateVisible = false"
@confirm="updateUser('updateUserForm')"/>
</template>
</el-dialog>
@ -59,6 +60,7 @@
<script>
import {TokenKey} from "../../../../common/js/constants";
import MsDialogFooter from "../../common/components/MsDialogFooter";
export default {
data() {
@ -66,7 +68,7 @@
result: {},
updateVisible: false,
tableData: [],
updatePath: '/user/update/currentuser',
updatePath: '/user/update/current',
form: {},
rule: {
name: [
@ -95,11 +97,21 @@
message: this.$t('member.email_format_is_incorrect'),
trigger: 'blur'
}
],
password: [
{required: true, message: this.$t('user.input_password'), trigger: 'blur'},
{
required:true,
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/,
message: this.$t('member.password_format_is_incorrect'),
trigger: 'blur'
}
]
}
}
},
name: "MsPersonSetting",
components: {MsDialogFooter},
created() {
this.initTableData();
},
@ -110,7 +122,7 @@
},
edit(row) {
this.updateVisible = true;
this.form = row;
this.form = Object.assign({}, row);
},
updateUser(updateUserForm) {
this.$refs[updateUserForm].validate(valide => {
@ -135,7 +147,7 @@
this.tableData = dataList;
})
},
closeFunc() {
handleClose() {
this.form = {};
}
}

View File

@ -65,11 +65,9 @@
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button @click="createOrganization('createOrganization')" @keydown.enter.native.prevent type="primary"
size="medium">{{$t('commons.save')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="dialogOrgAddVisible = false"
@confirm="createOrganization('createOrganization')"/>
</template>
</el-dialog>
@ -87,11 +85,9 @@
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button @click="updateOrganization('updateOrganizationForm')" @keydown.enter.native.prevent type="primary"
size="medium">{{$t('organization.modify')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="dialogOrgUpdateVisible = false"
@confirm="updateOrganization('updateOrganizationForm')"/>
</template>
</el-dialog>
@ -127,11 +123,9 @@
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button @click="submitForm('form')" @keydown.enter.native.prevent type="primary"
size="medium">{{$t('commons.save')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="dialogOrgMemberAddVisible = false"
@confirm="submitForm('form')"/>
</template>
</el-dialog>
@ -165,11 +159,9 @@
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button @click="updateOrgMember('updateUserForm')" @keydown.enter.native.prevent type="primary"
size="medium">{{$t('commons.save')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="dialogOrgMemberUpdateVisible = false"
@confirm="updateOrgMember('updateUserForm')"/>
</template>
</el-dialog>
@ -182,10 +174,11 @@
import MsTableHeader from "../../common/components/MsTableHeader";
import MsRolesTag from "../../common/components/MsRolesTag";
import MsTableOperator from "../../common/components/MsTableOperator";
import MsDialogFooter from "../../common/components/MsDialogFooter";
export default {
name: "MsOrganization",
components: {MsCreateBox, MsTablePagination, MsTableHeader, MsRolesTag, MsTableOperator},
components: {MsCreateBox, MsTablePagination, MsTableHeader, MsRolesTag, MsTableOperator, MsDialogFooter},
data() {
return {
queryPath: '/organization/list',
@ -258,11 +251,11 @@
},
edit(row) {
this.dialogOrgUpdateVisible = true;
this.form = row;
this.form = Object.assign({}, row);
},
editMember(row) {
this.dialogOrgMemberUpdateVisible = true;
this.memberForm = row;
this.memberForm = Object.assign({}, row);
let roleIds = this.memberForm.roles.map(r => r.id);
this.result = this.$get('/role/list/org', response => {
this.$set(this.memberForm, "allroles", response.data);

View File

@ -12,7 +12,8 @@
<el-table-column prop="organizationName" :label="$t('workspace.organization_name')"/>
<el-table-column :label="$t('commons.member')">
<template v-slot:default="scope">
<el-button type="text" class="member-size" @click="cellClick(scope.row)">{{scope.row.memberSize}}
<el-button type="text" class="member-size" @click="cellClick(scope.row)">
{{scope.row.memberSize}}
</el-button>
</template>
</el-table-column>
@ -48,9 +49,9 @@
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button type="primary" @keydown.enter.native.prevent @click="submit('form')" size="medium">{{$t('commons.save')}}</el-button>
</span>
<ms-dialog-footer
@cancel="dialogWsAddVisible = false"
@confirm="submit('form')"/>
</template>
</el-dialog>
@ -76,16 +77,15 @@
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button type="primary" @click="updateWorkspace('updateForm')" @keydown.enter.native.prevent
size="medium">{{$t('commons.save')}}</el-button>
</span>
<ms-dialog-footer
@cancel="dialogWsUpdateVisible = false"
@confirm="updateWorkspace('updateForm')"/>
</template>
</el-dialog>
<!-- dialog of workspace member -->
<el-dialog :visible.sync="dialogWsMemberVisible" width="70%" :destroy-on-close="true" @close="closeMemberFunc">
<el-dialog :visible.sync="dialogWsMemberVisible" width="70%" :destroy-on-close="true" @close="closeWsMemberDialog">
<ms-table-header :condition.sync="dialogCondition" @create="addMember" @search="dialogSearch"
:create-tip="dialogBtnTips" :title="$t('commons.member')"/>
<!-- organization member table -->
@ -112,7 +112,7 @@
<!-- add workspace member dialog -->
<el-dialog :title="$t('member.create')" :visible.sync="dialogWsMemberAddVisible" width="30%"
:destroy-on-close="true"
@close="closeFunc">
@close="handleClose">
<el-form :model="memberForm" ref="form" :rules="wsMemberRule" label-position="right" label-width="100px"
size="small">
<el-form-item :label="$t('commons.member')" prop="userIds">
@ -141,18 +141,16 @@
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button type="primary" @keydown.enter.native.prevent @click="submitForm('form')" size="medium">
{{$t('commons.save')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="dialogWsMemberAddVisible = false"
@confirm="submitForm('form')"/>
</template>
</el-dialog>
<!-- update workspace member dialog -->
<el-dialog :title="$t('member.modify')" :visible.sync="dialogWsMemberUpdateVisible" width="30%"
:destroy-on-close="true"
@close="closeFunc">
@close="handleClose">
<el-form :model="memberForm" label-position="right" label-width="100px" size="small" ref="updateUserForm">
<el-form-item label="ID" prop="id">
<el-input v-model="memberForm.id" autocomplete="off" :disabled="true"/>
@ -179,11 +177,9 @@
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button type="primary" @click="updateOrgMember('updateUserForm')" @keydown.enter.native.prevent
size="medium">{{$t('commons.save')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="dialogWsMemberUpdateVisible = false"
@confirm="updateWorkspaceMember('updateUserForm')"/>
</template>
</el-dialog>
@ -198,10 +194,11 @@
import MsTableHeader from "../../common/components/MsTableHeader";
import MsRolesTag from "../../common/components/MsRolesTag";
import MsTableOperator from "../../common/components/MsTableOperator";
import MsDialogFooter from "../../common/components/MsDialogFooter";
export default {
name: "MsSystemWorkspace",
components: {MsCreateBox, MsTablePagination, MsTableHeader, MsRolesTag, MsTableOperator},
components: {MsCreateBox, MsTablePagination, MsTableHeader, MsRolesTag, MsTableOperator, MsDialogFooter},
mounted() {
this.list();
},
@ -232,7 +229,6 @@
},
addMember() {
this.dialogWsMemberAddVisible = true;
this.memberForm = {};
this.result = this.$get('/user/list/', response => {
this.$set(this.memberForm, "userList", response.data);
});
@ -318,10 +314,10 @@
});
},
closeFunc() {
this.form = {};
handleClose() {
this.memberForm = {};
},
closeMemberFunc() {
closeWsMemberDialog() {
this.memberLineData = [];
this.list();
},
@ -363,7 +359,7 @@
},
editMember(row) {
this.dialogWsMemberUpdateVisible = true;
this.memberForm = row;
this.memberForm = Object.assign({}, row);
let roleIds = this.memberForm.roles.map(r => r.id);
this.result = this.$get('/role/list/test', response => {
this.$set(this.memberForm, "allroles", response.data);
@ -385,7 +381,7 @@
this.$info(this.$t('commons.delete_cancel'));
});
},
updateOrgMember() {
updateWorkspaceMember() {
let param = {
id: this.memberForm.id,
name: this.memberForm.name,

View File

@ -68,64 +68,64 @@
</el-form-item>
<div v-for="(item,index) in infoList " :key="index">
<div class="node-line" v-if="form.type === 'K8S'">
<div class="k8s-master">
<el-col :span="11">
<el-row>
<el-col :span="9">
<el-form-item prop="masterUrl" label="Master URL">
<el-input v-model="item.masterUrl" autocomplete="off"/>
</el-form-item>
</el-col>
<el-form-item prop="masterUrl" label="Master URL">
<el-input v-model="item.masterUrl" autocomplete="off"/>
</el-form-item>
</div>
<div class="k8s-token">
<el-form-item prop="token" label="Token">
<el-input v-model="item.token" show-password autocomplete="off"/>
</el-form-item>
</div>
<div style="width: 30%;float: left">
<el-form-item prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')">
<el-input-number v-model="item.maxConcurrency" :min="1" :max="9999"></el-input-number>
</el-form-item>
</div>
<el-col :span="9">
<el-form-item prop="password" label="Token" style="padding-left: 20px">
<el-input v-model="item.token" show-password autocomplete="off"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')"
style="padding-left: 20px">
<el-input-number v-model="item.maxConcurrency" :min="1" :max="9999"></el-input-number>
</el-form-item>
</el-col>
</el-row>
</div>
<div class="node-line" v-if="form.type === 'NODE'">
<div style="width: 30%;float: left">
<el-form-item prop="ip" label="IP">
<el-input v-model="item.ip" autocomplete="off"/>
</el-form-item>
</div>
<div style="width: 30%;float: left">
<el-form-item prop="port" label="Port">
<el-input-number v-model="item.port" :min="1" :max="9999"></el-input-number>
</el-form-item>
</div>
<div style="width: 30%;float: left">
<el-form-item prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')">
<el-input-number v-model="item.maxConcurrency" :min="1" :max="9999"></el-input-number>
</el-form-item>
</div>
<div class="op">
<el-row>
<el-col :span="8">
<el-form-item prop="ip" label="IP">
<el-input v-model="item.ip" autocomplete="off"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item prop="port" label="Port" style="padding-left: 20px">
<el-input-number v-model="item.port" :min="1" :max="9999"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')"
style="padding-left: 20px">
<el-input-number v-model="item.maxConcurrency" :min="1" :max="9999"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="4">
<span class="box">
<el-button @click="addResourceInfo()" type="primary" size="mini" circle>
<font-awesome-icon :icon="['fas', 'plus']"/>
</el-button>
</span>
<span class="box">
<span class="box">
<el-button @click="removeResourceInfo(index)" type="primary" size="mini" circle>
<font-awesome-icon :icon="['fas', 'minus']"/>
</el-button>
</span>
</div>
</el-col>
</el-row>
</div>
</div>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button @click="createTestResourcePool('createTestResourcePoolForm')" @keydown.enter.native.prevent
type="primary"
size="medium">{{$t('commons.create')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="createVisible = false"
@confirm="createTestResourcePool('createTestResourcePoolForm')"/>
</template>
</el-dialog>
@ -151,62 +151,63 @@
</el-form-item>
<div v-for="(item,index) in infoList " :key="index">
<div class="node-line" v-if="form.type === 'K8S'">
<div class="k8s-master">
<el-form-item prop="masterUrl" label="Master URL">
<el-input v-model="item.masterUrl" autocomplete="off"/>
</el-form-item>
</div>
<div class="k8s-token">
<el-form-item prop="password" label="Token" style="padding-left: 20px">
<el-input v-model="item.token" show-password autocomplete="off"/>
</el-form-item>
</div>
<div style="width: 30%;float: left">
<el-form-item prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')"
style="padding-left: 20px">
<el-input-number v-model="item.maxConcurrency" :min="1" :max="9999"></el-input-number>
</el-form-item>
</div>
<el-row>
<el-col :span="9">
<el-form-item prop="masterUrl" label="Master URL">
<el-input v-model="item.masterUrl" autocomplete="off"/>
</el-form-item>
</el-col>
<el-col :span="9">
<el-form-item prop="password" label="Token" style="padding-left: 20px">
<el-input v-model="item.token" show-password autocomplete="off"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')"
style="padding-left: 20px">
<el-input-number v-model="item.maxConcurrency" :min="1" :max="9999"></el-input-number>
</el-form-item>
</el-col>
</el-row>
</div>
<div class="node-line" v-if="form.type === 'NODE'">
<div style="width: 30%;float: left">
<el-form-item prop="ip" label="IP">
<el-input v-model="item.ip" autocomplete="off"/>
</el-form-item>
</div>
<div style="width: 30%;float: left">
<el-form-item prop="port" label="Port" style="padding-left: 20px">
<el-input-number v-model="item.port" :min="1" :max="9999"></el-input-number>
</el-form-item>
</div>
<div style="width: 30%;float: left">
<el-form-item prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')"
style="padding-left: 20px">
<el-input-number v-model="item.maxConcurrency" :min="1" :max="9999"></el-input-number>
</el-form-item>
</div>
<div class="op">
<el-row>
<el-col :span="8">
<el-form-item prop="ip" label="IP">
<el-input v-model="item.ip" autocomplete="off"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item prop="port" label="Port" style="padding-left: 20px">
<el-input-number v-model="item.port" :min="1" :max="9999"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')"
style="padding-left: 20px">
<el-input-number v-model="item.maxConcurrency" :min="1" :max="9999"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="4">
<span class="box">
<el-button @click="addResourceInfo()" type="primary" size="mini" circle>
<font-awesome-icon :icon="['fas', 'plus']"/>
</el-button>
</span>
<span class="box">
<span class="box">
<el-button @click="removeResourceInfo(index)" type="primary" size="mini" circle>
<font-awesome-icon :icon="['fas', 'minus']"/>
</el-button>
</span>
</div>
</el-col>
</el-row>
</div>
</div>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button @click="updateTestResourcePool('updateTestResourcePoolForm')" @keydown.enter.native.prevent
type="primary"
size="medium">{{$t('commons.save')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="updateVisible = false"
@confirm="updateTestResourcePool('updateTestResourcePoolForm')"/>
</template>
</el-dialog>
@ -218,10 +219,11 @@
import MsTablePagination from "../../common/pagination/TablePagination";
import MsTableHeader from "../../common/components/MsTableHeader";
import MsTableOperator from "../../common/components/MsTableOperator";
import MsDialogFooter from "../../common/components/MsDialogFooter";
export default {
name: "MsTestResourcePool",
components: {MsCreateBox, MsTablePagination, MsTableHeader, MsTableOperator},
components: {MsCreateBox, MsTablePagination, MsTableHeader, MsTableOperator, MsDialogFooter},
data() {
return {
result: {},
@ -429,30 +431,8 @@
<style scoped>
.op {
float: left;
width: 10%;
}
.box {
padding-left: 5px;
}
.k8s-master {
width: 34%;
float: left
}
.k8s-token {
width: 36%;
float: left
}
.k8s-token .el-form-item__label {
padding-left: 20px;
}
.node-line {
clear: both;
}
</style>

View File

@ -40,7 +40,7 @@
</el-card>
<el-dialog :title="$t('user.create')" :visible.sync="createVisible" width="30%" @closed="closeFunc"
<el-dialog :title="$t('user.create')" :visible.sync="createVisible" width="30%" @closed="handleClose"
:destroy-on-close="true">
<el-form :model="form" label-position="right" label-width="100px" size="small" :rules="rule" ref="createUserForm">
<el-form-item label="ID" prop="id">
@ -55,17 +55,19 @@
<el-form-item :label="$t('commons.phone')" prop="phone">
<el-input v-model="form.phone" autocomplete="off"/>
</el-form-item>
<el-form-item :label="$t('commons.password')" prop="password">
<el-input v-model="form.password" autocomplete="off" show-password/>
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button @click="createUser('createUserForm')" @keydown.enter.native.prevent type="primary"
size="medium">{{$t('commons.save')}}</el-button>
</span>
<ms-dialog-footer
@cancel="createVisible = false"
@confirm="createUser('createUserForm')"/>
</template>
</el-dialog>
<el-dialog :title="$t('user.modify')" :visible.sync="updateVisible" width="30%" :destroy-on-close="true"
@close="closeFunc">
@close="handleClose">
<el-form :model="form" label-position="right" label-width="100px" size="small" :rules="rule" ref="updateUserForm">
<el-form-item label="ID" prop="id">
<el-input v-model="form.id" autocomplete="off" :disabled="true"/>
@ -79,13 +81,15 @@
<el-form-item :label="$t('commons.phone')" prop="phone">
<el-input v-model="form.phone" autocomplete="off"/>
</el-form-item>
<el-form-item :label="$t('commons.password')" prop="password">
<el-input v-model="form.password" autocomplete="off" show-password/>
</el-form-item>
<!--<el-input placeholder="请输入密码" v-model="input" show-password></el-input>-->
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button @click="updateUser('updateUserForm')" @keydown.enter.native.prevent type="primary"
size="medium">{{$t('commons.save')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="updateVisible = false"
@confirm="updateUser('updateUserForm')"/>
</template>
</el-dialog>
@ -97,12 +101,14 @@
import MsTablePagination from "../../common/pagination/TablePagination";
import MsTableHeader from "../../common/components/MsTableHeader";
import MsTableOperator from "../../common/components/MsTableOperator";
import MsDialogFooter from "../../common/components/MsDialogFooter";
export default {
name: "MsUser",
components: {MsCreateBox, MsTablePagination, MsTableHeader, MsTableOperator},
components: {MsCreateBox, MsTablePagination, MsTableHeader, MsTableOperator, MsDialogFooter},
data() {
return {
/*input:'',*/
queryPath: '/user/special/list',
deletePath: '/user/special/delete/',
createPath: '/user/special/add',
@ -149,6 +155,15 @@
message: this.$t('user.email_format_is_incorrect'),
trigger: 'blur'
}
],
password: [
{required: true, message: this.$t('user.input_password'), trigger: 'blur'},
{
required:true,
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/,
message: this.$t('member.password_format_is_incorrect'),
trigger: 'blur'
}
]
}
}
@ -162,7 +177,7 @@
},
edit(row) {
this.updateVisible = true;
this.form = row;
this.form = Object.assign({}, row);
},
del(row) {
this.$confirm(this.$t('user.delete_confirm'), '', {
@ -211,7 +226,7 @@
this.tableData = data.listObject;
})
},
closeFunc() {
handleClose() {
this.form = {};
},
changeSwitch(row) {

View File

@ -16,7 +16,8 @@
</el-table-column>
<el-table-column>
<template v-slot:default="scope">
<ms-table-operator @editClick="edit(scope.row)" @deleteClick="del(scope.row)" v-permission="['test_manager']"/>
<ms-table-operator @editClick="edit(scope.row)" @deleteClick="del(scope.row)"
v-permission="['test_manager']"/>
</template>
</el-table-column>
</el-table>
@ -25,7 +26,7 @@
</el-card>
<el-dialog :title="$t('member.create')" :visible.sync="createVisible" width="30%" :destroy-on-close="true"
@close="closeFunc">
@close="handleClose">
<el-form :model="form" ref="form" :rules="rules" label-position="right" label-width="100px" size="small">
<el-form-item :label="$t('commons.member')" prop="userIds">
<el-select v-model="form.userIds" multiple :placeholder="$t('member.please_choose_member')"
@ -52,16 +53,14 @@
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button @click="submitForm('form')" @keydown.enter.native.prevent type="primary"
size="medium">{{$t('commons.save')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="createVisible = false"
@confirm="submitForm('form')"/>
</template>
</el-dialog>
<el-dialog :title="$t('member.modify')" :visible.sync="updateVisible" width="30%" :destroy-on-close="true"
@close="closeFunc">
@close="handleClose">
<el-form :model="form" label-position="right" label-width="100px" size="small" ref="updateUserForm">
<el-form-item label="ID" prop="id">
<el-input v-model="form.id" autocomplete="off" :disabled="true"/>
@ -87,11 +86,9 @@
</el-form-item>
</el-form>
<template v-slot:footer>
<span class="dialog-footer">
<el-button @click="updateWorkspaceMember('updateUserForm')" @keydown.enter.native.prevent type="primary"
size="medium">{{$t('commons.save')}}
</el-button>
</span>
<ms-dialog-footer
@cancel="updateVisible = false"
@confirm="updateWorkspaceMember('updateUserForm')"/>
</template>
</el-dialog>
@ -105,10 +102,11 @@
import MsTableHeader from "../../common/components/MsTableHeader";
import MsRolesTag from "../../common/components/MsRolesTag";
import MsTableOperator from "../../common/components/MsTableOperator";
import MsDialogFooter from "../../common/components/MsDialogFooter";
export default {
name: "MsMember",
components: {MsCreateBox, MsTablePagination, MsTableHeader, MsRolesTag, MsTableOperator},
components: {MsCreateBox, MsTablePagination, MsTableHeader, MsRolesTag, MsTableOperator, MsDialogFooter},
data() {
return {
result: {},
@ -168,9 +166,8 @@
buildPagePath(path) {
return path + "/" + this.currentPage + "/" + this.pageSize;
},
closeFunc() {
handleClose() {
this.form = {};
this.initTableData();
},
del(row) {
this.$confirm(this.$t('member.delete_confirm'), '', {
@ -191,7 +188,7 @@
},
edit(row) {
this.updateVisible = true;
this.form = row;
this.form = Object.assign({}, row);
let roleIds = this.form.roles.map(r => r.id);
this.result = this.$get('/role/list/test', response => {
this.$set(this.form, "allroles", response.data);

View File

@ -1,6 +1,5 @@
<template>
<common-component :title="'基础信息'">
<template>
@ -8,7 +7,7 @@
<el-row type="flex" justify="space-between">
<el-col :span="12">
<span>所属项目</span>
<span class="item-value">{{reportInfo.project}}</span>
<span class="item-value">{{reportInfo.projectName}}</span>
</el-col>
<el-col :span="12">
<span>测试负责人</span>
@ -16,14 +15,16 @@
</el-col>
</el-row>
<el-row type="flex" justify="space-between">
<el-row type="flex" justify="space-between" class="select-time">
<el-col :span="12">
<span>开始时间</span>
<span class="item-value">{{reportInfo.startTime}}</span>
<span v-if="!isReport">{{reportInfo.startTime}}</span>
<el-date-picker v-if="isReport" size="mini" type="date" placeholder="选择日期" v-model="reportInfo.startTime"/>
</el-col>
<el-col :span="12">
<span>结束时间</span>
<span class="item-value">{{reportInfo.endTime}}</span>
<span v-if="!isReport">{{reportInfo.endTime}}</span>
<el-date-picker v-if="isReport" size="mini" type="date" placeholder="选择日期" v-model="reportInfo.endTime"/>
</el-col>
</el-row>
@ -45,22 +46,22 @@
export default {
name: "BaseInfoComponent",
components: {CommonComponent},
data() {
return {
}
},
props: {
reportInfo: {
type: Object,
default() {
return {
project: '项目名称',
projectName: '项目名称',
principal: '由丽媛',
executors: ['由丽媛','王振','陈建星'],
startTime: '2020-6-18',
endTime: '2020-6-18'
}
}
},
isReport: {
type: Boolean,
default: true
}
}
}
@ -82,4 +83,12 @@
height: 60px;
}
.select-time span {
display: inline-block;
}
.el-date-editor {
width: 150px;
}
</style>

View File

@ -0,0 +1,58 @@
<template>
<div>
<!--模版-->
<div v-if="!metric">
<base-info-component :is-report="false" v-if="preview.id == 1"/>
<test-result-component v-if="preview.id == 2"/>
<test-result-chart-component v-if="preview.id == 3"/>
<rich-text-component :preview="preview" v-if="preview.type != 'system'"/>
</div>
<!--报告-->
<div v-if="metric">
<base-info-component :report-info="metric" v-if="preview.id == 1"/>
<test-result-component :test-results="metric.moduleExecuteResult" v-if="preview.id == 2"/>
<test-result-chart-component :execute-result="metric.executeResult" v-if="preview.id == 3"/>
<rich-text-component :preview="preview" v-if="preview.type != 'system'"/>
</div>
</div>
</template>
<script>
import BaseInfoComponent from "./BaseInfoComponent";
import TestResultComponent from "./TestResultComponent";
import TestResultChartComponent from "./TestResultChartComponent";
import RichTextComponent from "./RichTextComponent";
export default {
name: "TemplateComponent",
components: {RichTextComponent, TestResultChartComponent, TestResultComponent, BaseInfoComponent},
props: {
preview: {
type: Object
},
metric: {
type: Object
},
isReport: {
type: Boolean,
default: true
}
}
}
</script>
<style scoped>
.el-card {
margin: 5px auto;
min-height: 300px;
width: 80%;
}
.el-card:hover {
box-shadow: 0 0 2px 2px #409EFF;
}
</style>

View File

@ -4,7 +4,7 @@
<template>
<ms-pie-chart :text="'测试结果统计图'" :name="'测试结果'" :data="charData"/>
<ms-pie-chart v-if="isShow" :text="'测试结果统计图'" :name="'测试结果'" :data="charData"/>
</template>
@ -21,38 +21,56 @@
components: {MsPieChart, CommonComponent},
data() {
return {
charData: [
{
value:235, name:'通过',
itemStyle: {
color: '#67C23A'
}
},
{
value:274, name:'阻塞',
itemStyle: {
color: '#E6A23C'
}
},
{
value:310, name:'失败',
itemStyle: {
color: '#F56C6C'
}
},
{
value:335, name:'跳过',
itemStyle: {
color: '#909399'
}
},
{
value:400, name:'未完成',
itemStyle: {
color: 'lightskyblue'
}
}
]
dataMap: new Map([
["Pass", {name:'通过', itemStyle: {color: '#67C23A'}}],
["Blocking", {name:'阻塞', itemStyle: {color: '#E6A23C'}}],
["Skip", {name:'跳过', itemStyle: {color: '#909399'}}],
["Prepare", {name:'未开始', itemStyle: {color: '#DEDE10'}}],
["Failure", {name:'失败', itemStyle: {color: '#F56C6C'}}],
["Underway", {name:'进行中', itemStyle: {color: 'lightskyblue'}}]
]),
charData: [],
isShow: true
}
},
props: {
executeResult: {
type: Array,
default() {
return [
{status: 'Pass', count: '235'},
{status: 'Blocking', count: '274'},
{status: 'Skip', count: '335'},
{status: 'Prepare', count: '265'},
{status: 'Failure', count: '310'},
{status: 'Underway', count: '245'},
]
}
}
},
watch: {
executeResult() {
this.getCharData();
}
},
created() {
this.getCharData();
},
methods: {
getCharData() {
this.charData = [];
this.executeResult.forEach(item => {
let data = this.dataMap.get(item.status);
data.value = item.count;
this.charData.push(data);
});
this.reload();
},
reload() {
this.isShow = false;
this.$nextTick(function () {
this.isShow = true;
})
}
}
}

View File

@ -1,14 +1,13 @@
<template>
<common-component :title="'测试结果'">
<template>
<el-table
:data="testResults"
stripe
style="width: 100%">
<el-table-column
prop="module"
prop="moduleName"
:label="'模块'"
width="180">
</el-table-column>
@ -20,6 +19,9 @@
<el-table-column
prop="passRate"
:label="'通过率'">
<template v-slot:default="scope">
{{scope.row.passRate}}%
</template>
</el-table-column>
<el-table-column
prop="flawCount"
@ -37,29 +39,25 @@
export default {
name: "TestResultComponent",
components: {CommonComponent},
data() {
return {
}
},
props: {
testResults: {
type: Array,
default() {
return [
{
module: '模块1',
moduleName: '模块1',
caseCount: '14',
passRate: 10.8,
flawCount: 3
},
{
module: '模块2',
moduleName: '模块2',
caseCount: '24',
passRate: 40,
flawCount: 6
},
{
module: '模块3',
moduleName: '模块3',
caseCount: '50',
passRate: 76.9,
flawCount: 8

View File

@ -5,6 +5,7 @@
:visible.sync="showDialog"
:with-header="false"
size="100%"
:modal-append-to-body="false"
ref="drawer"
v-loading="result.loading">
<template v-slot:default="scope">
@ -36,10 +37,7 @@
group="component">
<transition-group>
<div class="preview" v-for="item in previews" :key="item.id">
<base-info-component v-if="item.id == 1"/>
<test-result-component v-if="item.id == 2"/>
<test-result-chart-component v-if="item.id == 3"/>
<rich-text-component :preview="item" v-if="item.type != 'system'"/>
<template-component :is-report="isReport" :metric="metric" :preview="item"/>
<i class="el-icon-error" @click="handleDelete(item)"/>
</div>
</transition-group>
@ -53,24 +51,18 @@
<script>
import draggable from 'vuedraggable';
import BaseInfoComponent from "./TemplateComponent/BaseInfoComponent";
import TestResultComponent from "./TemplateComponent/TestResultComponent";
import TestResultChartComponent from "./TemplateComponent/TestResultChartComponent";
import TemplateComponentBar from "./TemplateComponentBar";
import RichTextComponent from "./TemplateComponent/RichTextComponent";
import TemplateComponentEditHeader from "./TemplateComponentEditHeader";
import {WORKSPACE_ID} from '../../../../../common/js/constants';
import {jsonToMap, mapToJson} from "../../../../../common/js/utils";
import TemplateComponent from "./TemplateComponent/TemplateComponent";
export default {
name: "TestCaseReportTemplateEdit",
components: {
TemplateComponent,
TemplateComponentEditHeader,
RichTextComponent,
TemplateComponentBar,
TestResultChartComponent,
TestResultComponent,
BaseInfoComponent,
draggable
},
data() {
@ -93,6 +85,11 @@
isReport: false
}
},
props: {
metric: {
type: Object
}
},
methods: {
open(id, isReport) {
if (isReport) {
@ -198,6 +195,12 @@
this.template.content = JSON.parse(response.data.content);
if (this.template.content.customComponent) {
this.template.content.customComponent = jsonToMap(this.template.content.customComponent);
if (this.template.startTime) {
this.metric.startTime = new Date(this.template.startTime);
}
if (this.template.endTime) {
this.metric.endTime = new Date(this.template.endTime);
}
}
this.initComponents();
});
@ -222,10 +225,10 @@
buildParam(param) {
let content = {};
content.components = [];
content.customComponent = new Map();
this.previews.forEach(item => {
content.components.push(item.id);
if (!this.componentMap.get(item.id)) {
content.customComponent = new Map();
content.customComponent.set(item.id, {title: item.title, content: item.content})
}
});
@ -242,6 +245,12 @@
if (this.template.workspaceId) {
param.workspaceId = localStorage.getItem(WORKSPACE_ID);
}
if (this.metric && this.metric.startTime) {
param.startTime = this.metric.startTime.getTime();
}
if (this.metric && this.metric.endTime) {
param.endTime = this.metric.endTime.getTime();
}
}
}
}
@ -270,16 +279,6 @@
position: absolute;
}
.el-card {
margin: 5px auto;
min-height: 300px;
width: 80%;
}
.el-card:hover {
box-shadow: 0 0 2px 2px #409EFF;
}
.description > span {
display: block;
padding-bottom: 5px;
@ -312,8 +311,13 @@
color: red;
}
.template-component:hover+i {
.preview:hover+i {
display: inline;
}
.preview:hover i{
display: inline;
}
</style>

View File

@ -117,7 +117,7 @@
}
}
if (!hasCurrentProject) {
this.currentProject = null;
this.setCurrentProject(this.projects[0]);
}
} else {
if(this.projects.length > 0){
@ -189,6 +189,7 @@
this.$get('/project/get/' + id, response => {
let project = response.data;
this.setCurrentProject(project);
this.$router.push('/track/case/all');
});
}
if (id === 'all') {

View File

@ -13,7 +13,7 @@
:label="$t('test_track.case.name')"
:label-width="formLabelWidth"
prop="name">
<el-input :disabled="readOnly" v-model.trim="form.name"></el-input>
<el-input :disabled="readOnly" v-model="form.name"></el-input>
</el-form-item>
</el-col>
@ -313,6 +313,11 @@
if(localStorage.getItem(CURRENT_PROJECT)) {
param.projectId = JSON.parse(localStorage.getItem(CURRENT_PROJECT)).id;
}
param.name = param.name.trim();
if (param.name == '') {
this.$warning(this.$t('test_track.case.input_name'));
return;
}
this.$post('/test/case/' + this.operationType, param, () => {
this.$success(this.$t('commons.save_success'));
this.dialogFormVisible = false;

View File

@ -5,7 +5,7 @@
:before-close="close"
width="20%">
<el-select v-model.trim="module"
<el-select v-model="module"
:placeholder="$t('test_track.case.move')"
filterable>
<el-option v-for="item in moduleOptions" :key="item.id"
@ -40,7 +40,7 @@
methods: {
save() {
if (this.module === '') {
this.$warning(this.$t('test_track.plan_view.select_execute_result'));
this.$warning(this.$t('test_track.case.input_module'));
return;
}
let param = {};
@ -50,11 +50,6 @@
param.nodePath = item.path;
}
});
if (this.module === '') {
this.$warning(this.$t('test_track.plan_view.select_executor'));
return;
}
param.ids = [...this.selectIds];
this.$post('/test/case/batch/edit' , param, () => {
this.$success(this.$t('commons.save_success'));

View File

@ -12,7 +12,7 @@
:label="$t('test_track.module.name')"
:label-width="formLabelWidth"
prop="name">
<el-input v-model.trim="form.name" autocomplete="off"></el-input>
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
</el-form>
</el-col>
@ -69,7 +69,10 @@
if (valid) {
let param = {};
let url = this.buildParam(param);
if (param.name.trim() == '') {
this.$warning(this.$t('test_track.case.input_name'));
return;
}
this.$post(url, param, () => {
this.$success(this.$t('commons.save_success'));
this.$emit('refresh');
@ -95,7 +98,7 @@
param.id = this.node.id;
param.level = this.node.level;
}
param.name = this.form.name;
param.name = this.form.name.trim();
param.label = this.form.name;
if (localStorage.getItem(CURRENT_PROJECT)) {
param.projectId = JSON.parse(localStorage.getItem(CURRENT_PROJECT)).id;

View File

@ -108,7 +108,7 @@
this.isRouterAlive = false;
this.$nextTick(function () {
this.isRouterAlive = true;
})
});
}
}
}

View File

@ -15,7 +15,7 @@
:label="$t('test_track.plan.plan_name')"
:label-width="formLabelWidth"
prop="name">
<el-input v-model.trim="form.name"></el-input>
<el-input v-model="form.name"></el-input>
</el-form-item>
</el-col>
@ -149,6 +149,11 @@
if (valid) {
let param = {};
Object.assign(param, this.form);
param.name = param.name.trim();
if (param.name == '') {
this.$warning(this.$t('test_track.plan.input_plan_name'));
return;
}
param.workspaceId = localStorage.getItem(WORKSPACE_ID);
this.$post('/test/plan/' + this.operationType, param, () => {
this.$success(this.$t('commons.save_success'));

View File

@ -5,6 +5,7 @@
:before-close="handleClose"
:visible.sync="showDialog"
:with-header="false"
:modal-append-to-body="false"
size="100%"
ref="drawer"
v-loading="result.loading">
@ -19,6 +20,7 @@
</div>
</el-col>
<el-col :span="12" class="head-right">
<el-button plain size="mini" @click="handleSave">保存</el-button>
<el-button plain size="mini" @click="handleEdit">编辑组件</el-button>
</el-col>
</el-row>
@ -26,32 +28,31 @@
<div class="container">
<el-main>
<div class="preview" v-for="item in previews" :key="item.id">
<base-info-component v-if="item.id == 1"/>
<test-result-component v-if="item.id == 2"/>
<test-result-chart-component v-if="item.id == 3"/>
<rich-text-component :preview="item" v-if="item.type != 'system'"/>
<template-component :metric="metric" :preview="item"/>
</div>
</el-main>
</div>
</template>
</el-drawer>
<test-case-report-template-edit ref="templateEdit" @refresh="getReport"/>
<test-case-report-template-edit :metric="metric" ref="templateEdit" @refresh="getReport"/>
</div>
</template>
<script>
import {jsonToMap} from "../../../../../../common/js/utils";
import {jsonToMap, mapToJson} from "../../../../../../common/js/utils";
import BaseInfoComponent from "../../../../settings/workspace/components/TemplateComponent/BaseInfoComponent";
import TestResultChartComponent from "../../../../settings/workspace/components/TemplateComponent/TestResultChartComponent";
import TestResultComponent from "../../../../settings/workspace/components/TemplateComponent/TestResultComponent";
import RichTextComponent from "../../../../settings/workspace/components/TemplateComponent/RichTextComponent";
import TestCaseReportTemplateEdit from "../../../../settings/workspace/components/TestCaseReportTemplateEdit";
import TemplateComponent from "../../../../settings/workspace/components/TemplateComponent/TemplateComponent";
export default {
name: "TestCaseReportView",
components: {
TemplateComponent,
TestCaseReportTemplateEdit,
RichTextComponent, TestResultComponent, TestResultChartComponent, BaseInfoComponent},
data() {
@ -61,6 +62,7 @@
previews: [],
report: {},
reportId: '',
metric: {},
componentMap: new Map(
[
[1, { name: "基础信息", id: 1 , type: 'system'}],
@ -71,6 +73,11 @@
)
}
},
props: {
planId: {
type: String
}
},
methods: {
open(id) {
if (id) {
@ -86,6 +93,7 @@
if (this.report.content.customComponent) {
this.report.content.customComponent = jsonToMap(this.report.content.customComponent);
}
this.getMetric();
this.initPreviews();
});
},
@ -110,6 +118,47 @@
},
handleEdit() {
this.$refs.templateEdit.open(this.reportId, true);
},
handleSave() {
let param = {};
this.buildParam(param);
this.result = this.$post('/case/report/edit', param, () =>{
this.$success('保存成功');
});
},
buildParam(param) {
let content = {};
content.components = [];
this.previews.forEach(item => {
content.components.push(item.id);
if (!this.componentMap.get(item.id)) {
content.customComponent = new Map();
content.customComponent.set(item.id, {title: item.title, content: item.content})
}
});
param.name = this.report.name;
if (content.customComponent) {
content.customComponent = mapToJson(content.customComponent);
}
param.content = JSON.stringify(content);
param.id = this.report.id;
if (this.metric.startTime) {
param.startTime = this.metric.startTime.getTime();
}
if (this.metric.endTime) {
param.endTime = this.metric.endTime.getTime();
}
},
getMetric() {
this.result = this.$get('/case/report/get/metric/' + this.planId, response => {
this.metric = response.data;
if (this.report.startTime) {
this.metric.startTime = new Date(this.report.startTime);
}
if (this.report.endTime) {
this.metric.endTime = new Date(this.report.endTime);
}
});
}
}
}

View File

@ -4,6 +4,7 @@
:before-close="handleClose"
:visible.sync="showDialog"
:with-header="false"
:modal-append-to-body="false"
size="100%"
ref="drawer"
v-loading="result.loading">

View File

@ -109,7 +109,7 @@
@refreshTable="search"/>
<test-report-template-list @openReport="openReport" :plan-id="planId" ref="testReporTtemplateList"/>
<test-case-report-view ref="testCaseReportView"/>
<test-case-report-view :plan-id="planId" ref="testCaseReportView"/>
</el-card>
</template>
@ -195,16 +195,14 @@
},
watch: {
planId() {
this.getTestPlanById();
this.initTableData();
this.refreshTableAndPlan();
},
selectNodeIds() {
this.search();
}
},
mounted() {
this.getTestPlanById();
this.initTableData();
this.refreshTableAndPlan();
},
methods: {
initTableData() {
@ -224,6 +222,16 @@
this.selectIds.clear();
this.$emit('refresh');
},
refreshTableAndPlan() {
this.getTestPlanById();
this.initTableData();
},
refreshTestPlanRecent() {
let param = {};
param.id = this.planId;
param.updateTime = Date.now();
this.$post('/test/plan/edit', param);
},
search() {
this.initTableData();
},
@ -298,6 +306,7 @@
if (this.planId) {
this.$post('/test/plan/get/' + this.planId, {}, response => {
this.testPlan = response.data;
this.refreshTestPlanRecent();
});
}
},

View File

@ -94,6 +94,7 @@ export default {
'special_characters_are_not_supported': 'Special characters are not supported',
'mobile_number_format_is_incorrect': 'Mobile number format is incorrect',
'email_format_is_incorrect': 'Email format is incorrect',
'password_format_is_incorrect':'Password format is incorrect (At least 8-16 characters, at least 1 uppercase letter, 1 lowercase letter and 1 number)',
},
user: {
'create': 'Create',
@ -101,6 +102,7 @@ export default {
'input_name': 'Please enter a user name',
'input_id': 'Please enter a ID',
'input_email': 'Please enter a email',
'input_password':'Please enter a password',
'special_characters_are_not_supported': 'Special characters are not supported',
'mobile_number_format_is_incorrect': 'Mobile number format is incorrect',
'email_format_is_incorrect': 'Email format is incorrect',
@ -129,6 +131,8 @@ export default {
'being_generated': 'Report is being generated...',
},
load_test: {
'operating':'Operating',
'pressure_prediction_chart':'Pressure Prediction Chart',
'recent': 'Recent Tests',
'search_by_name': 'Search by name',
'project_name': 'Project',
@ -181,6 +185,7 @@ export default {
'create': 'Create Test',
'select_resource_pool': 'Please Select Resource Pool',
'resource_pool_is_null': 'Resource Pool is empty',
'download_log_file': 'Download',
},
api_test: {
'select_resource_pool': 'Please select resource pool'

View File

@ -96,6 +96,7 @@ export default {
'special_characters_are_not_supported': '不支持特殊字符',
'mobile_number_format_is_incorrect': '手机号码格式不正确',
'email_format_is_incorrect': '邮箱格式不正确',
'password_format_is_incorrect':'密码格式不正确(至少8-16个字符至少1个大写字母1个小写字母和1个数字)',
},
user: {
'create': '创建用户',
@ -103,6 +104,7 @@ export default {
'input_name': '请输入用户名',
'input_id': '请输入ID',
'input_email': '请输入邮箱',
'input_password':'请输入密码',
'special_characters_are_not_supported': '不支持特殊字符',
'mobile_number_format_is_incorrect': '手机号码格式不正确',
'email_format_is_incorrect': '邮箱格式不正确',
@ -131,6 +133,7 @@ export default {
'being_generated': '报告正在生成中...',
},
load_test: {
'operating':'操作',
'recent': '最近的测试',
'search_by_name': '根据名称搜索',
'project_name': '所属项目',
@ -183,6 +186,8 @@ export default {
'create': '创建测试',
'select_resource_pool': '请选择资源池',
'resource_pool_is_null': '资源池为空',
'download_log_file': '下载完整日志文件',
'pressure_prediction_chart':'压力预估图',
},
api_test: {