This commit is contained in:
chenjianxing 2020-07-15 15:35:49 +08:00
commit ddf4d7f938
63 changed files with 2958 additions and 1437 deletions

View File

@ -10,6 +10,8 @@ MeterSphere 是一站式的开源企业级持续测试平台,涵盖测试跟
- 性能测试: 兼容 JMeter支持 Kubernetes 和云环境,轻松支持高并发、分布式的性能测试; - 性能测试: 兼容 JMeter支持 Kubernetes 和云环境,轻松支持高并发、分布式的性能测试;
- 团队协作: 两级租户体系,天然支持团队协作。 - 团队协作: 两级租户体系,天然支持团队协作。
![产品定位](https://metersphere.io/images/icon/ct-devops.png)
UI 展示: UI 展示:
![UI](https://metersphere.io/images/screenshot/ss07.png) ![UI](https://metersphere.io/images/screenshot/ss07.png)

View File

@ -300,7 +300,7 @@
<dependency> <dependency>
<groupId>mysql</groupId> <groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId> <artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version> <version>8.0.16</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.itfsw</groupId> <groupId>com.itfsw</groupId>

View File

@ -18,4 +18,5 @@ public class QueryAPIReportRequest {
private boolean recent = false; private boolean recent = false;
private List<OrderRequest> orders; private List<OrderRequest> orders;
private Map<String, List<String>> filters; private Map<String, List<String>> filters;
private Map<String, Object> combine;
} }

View File

@ -18,5 +18,5 @@ public class QueryAPITestRequest {
private boolean recent = false; private boolean recent = false;
private List<OrderRequest> orders; private List<OrderRequest> orders;
private Map<String, List<String>> filters; private Map<String, List<String>> filters;
private Map<String, Object> combine;
} }

View File

@ -2,17 +2,15 @@ package io.metersphere.api.service;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.APITestResult; import io.metersphere.api.dto.APITestResult;
import io.metersphere.api.dto.parse.ApiImport;
import io.metersphere.api.dto.QueryAPITestRequest; import io.metersphere.api.dto.QueryAPITestRequest;
import io.metersphere.api.dto.SaveAPITestRequest; import io.metersphere.api.dto.SaveAPITestRequest;
import io.metersphere.api.dto.parse.ApiImport;
import io.metersphere.api.jmeter.JMeterService; import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.parse.ApiImportParser; import io.metersphere.api.parse.ApiImportParser;
import io.metersphere.api.parse.ApiImportParserFactory; import io.metersphere.api.parse.ApiImportParserFactory;
import io.metersphere.api.parse.MsParser;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiTestFileMapper; import io.metersphere.base.mapper.ApiTestFileMapper;
import io.metersphere.base.mapper.ApiTestMapper; import io.metersphere.base.mapper.ApiTestMapper;
import io.metersphere.base.mapper.TestCaseMapper;
import io.metersphere.base.mapper.ext.ExtApiTestMapper; import io.metersphere.base.mapper.ext.ExtApiTestMapper;
import io.metersphere.commons.constants.APITestStatus; import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.FileType; import io.metersphere.commons.constants.FileType;
@ -27,19 +25,22 @@ import io.metersphere.i18n.Translator;
import io.metersphere.job.sechedule.ApiTestJob; import io.metersphere.job.sechedule.ApiTestJob;
import io.metersphere.service.FileService; import io.metersphere.service.FileService;
import io.metersphere.service.ScheduleService; import io.metersphere.service.ScheduleService;
import io.metersphere.track.service.TestCaseService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import java.io.ByteArrayInputStream;
import java.io.*; import java.io.InputStream;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Random; import java.util.Random;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Resource;
@Service @Service
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public class APITestService { public class APITestService {
@ -59,7 +60,7 @@ public class APITestService {
@Resource @Resource
private ScheduleService scheduleService; private ScheduleService scheduleService;
@Resource @Resource
private TestCaseMapper testCaseMapper; private TestCaseService testCaseService;
public List<APITestResult> list(QueryAPITestRequest request) { public List<APITestResult> list(QueryAPITestRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders())); request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
@ -132,20 +133,7 @@ public class APITestService {
} }
public void delete(String testId) { public void delete(String testId) {
testCaseService.checkIsRelateTest(testId);
// 是否关联测试用例
TestCaseExample testCaseExample = new TestCaseExample();
testCaseExample.createCriteria().andTestIdEqualTo(testId);
List<TestCase> testCases = testCaseMapper.selectByExample(testCaseExample);
if (testCases.size() > 0) {
String caseName = "";
for (int i = 0; i < testCases.size(); i++) {
caseName = caseName + testCases.get(i).getName() + ",";
}
caseName = caseName.substring(0, caseName.length() - 1);
MSException.throwException(Translator.get("related_case_del_fail_prefix") + caseName + Translator.get("related_case_del_fail_suffix"));
}
deleteFileByTestId(testId); deleteFileByTestId(testId);
apiReportService.deleteByTestId(testId); apiReportService.deleteByTestId(testId);
apiTestMapper.deleteByPrimaryKey(testId); apiTestMapper.deleteByPrimaryKey(testId);
@ -188,10 +176,7 @@ public class APITestService {
private Boolean isNameExist(SaveAPITestRequest request) { private Boolean isNameExist(SaveAPITestRequest request) {
ApiTestExample example = new ApiTestExample(); ApiTestExample example = new ApiTestExample();
example.createCriteria().andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId()); example.createCriteria().andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId());
if (apiTestMapper.countByExample(example) > 0) { return apiTestMapper.countByExample(example) > 0;
return true;
}
return false;
} }
private ApiTest updateTest(SaveAPITestRequest request) { private ApiTest updateTest(SaveAPITestRequest request) {
@ -292,11 +277,11 @@ public class APITestService {
} }
private SaveAPITestRequest getImportApiTest(MultipartFile file, ApiImport apiImport) { private SaveAPITestRequest getImportApiTest(MultipartFile file, ApiImport apiImport) {
SaveAPITestRequest request = new SaveAPITestRequest(); SaveAPITestRequest request = new SaveAPITestRequest();
request.setName(file.getOriginalFilename()); request.setName(file.getOriginalFilename());
request.setProjectId(""); request.setProjectId("");
request.setScenarioDefinition(apiImport.getScenarios()); request.setScenarioDefinition(apiImport.getScenarios());
request.setUserId(SessionUtils.getUser().getId()); request.setUserId(SessionUtils.getUserId());
request.setId(UUID.randomUUID().toString()); request.setId(UUID.randomUUID().toString());
for (FileType fileType : FileType.values()) { for (FileType fileType : FileType.values()) {
String suffix = fileType.suffix(); String suffix = fileType.suffix();
@ -304,7 +289,8 @@ public class APITestService {
if (name.endsWith(suffix)) { if (name.endsWith(suffix)) {
request.setName(name.substring(0, name.length() - suffix.length())); request.setName(name.substring(0, name.length() - suffix.length()));
} }
}; }
if (isNameExist(request)) { if (isNameExist(request)) {
request.setName(request.getName() + "_" + request.getId().substring(0, 5)); request.setName(request.getName() + "_" + request.getId().substring(0, 5));
} }

View File

@ -1,8 +1,7 @@
package io.metersphere.base.domain; package io.metersphere.base.domain;
import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import lombok.Data;
@Data @Data
public class User implements Serializable { public class User implements Serializable {
@ -28,5 +27,7 @@ public class User implements Serializable {
private String phone; private String phone;
private String source;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
} }

View File

@ -175,72 +175,72 @@ public class UserExample {
} }
public Criteria andNameIsNull() { public Criteria andNameIsNull() {
addCriterion("name is null"); addCriterion("`name` is null");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andNameIsNotNull() { public Criteria andNameIsNotNull() {
addCriterion("name is not null"); addCriterion("`name` is not null");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andNameEqualTo(String value) { public Criteria andNameEqualTo(String value) {
addCriterion("name =", value, "name"); addCriterion("`name` =", value, "name");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andNameNotEqualTo(String value) { public Criteria andNameNotEqualTo(String value) {
addCriterion("name <>", value, "name"); addCriterion("`name` <>", value, "name");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andNameGreaterThan(String value) { public Criteria andNameGreaterThan(String value) {
addCriterion("name >", value, "name"); addCriterion("`name` >", value, "name");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andNameGreaterThanOrEqualTo(String value) { public Criteria andNameGreaterThanOrEqualTo(String value) {
addCriterion("name >=", value, "name"); addCriterion("`name` >=", value, "name");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andNameLessThan(String value) { public Criteria andNameLessThan(String value) {
addCriterion("name <", value, "name"); addCriterion("`name` <", value, "name");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andNameLessThanOrEqualTo(String value) { public Criteria andNameLessThanOrEqualTo(String value) {
addCriterion("name <=", value, "name"); addCriterion("`name` <=", value, "name");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andNameLike(String value) { public Criteria andNameLike(String value) {
addCriterion("name like", value, "name"); addCriterion("`name` like", value, "name");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andNameNotLike(String value) { public Criteria andNameNotLike(String value) {
addCriterion("name not like", value, "name"); addCriterion("`name` not like", value, "name");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andNameIn(List<String> values) { public Criteria andNameIn(List<String> values) {
addCriterion("name in", values, "name"); addCriterion("`name` in", values, "name");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andNameNotIn(List<String> values) { public Criteria andNameNotIn(List<String> values) {
addCriterion("name not in", values, "name"); addCriterion("`name` not in", values, "name");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andNameBetween(String value1, String value2) { public Criteria andNameBetween(String value1, String value2) {
addCriterion("name between", value1, value2, "name"); addCriterion("`name` between", value1, value2, "name");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andNameNotBetween(String value1, String value2) { public Criteria andNameNotBetween(String value1, String value2) {
addCriterion("name not between", value1, value2, "name"); addCriterion("`name` not between", value1, value2, "name");
return (Criteria) this; return (Criteria) this;
} }
@ -315,142 +315,142 @@ public class UserExample {
} }
public Criteria andPasswordIsNull() { public Criteria andPasswordIsNull() {
addCriterion("password is null"); addCriterion("`password` is null");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andPasswordIsNotNull() { public Criteria andPasswordIsNotNull() {
addCriterion("password is not null"); addCriterion("`password` is not null");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andPasswordEqualTo(String value) { public Criteria andPasswordEqualTo(String value) {
addCriterion("password =", value, "password"); addCriterion("`password` =", value, "password");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andPasswordNotEqualTo(String value) { public Criteria andPasswordNotEqualTo(String value) {
addCriterion("password <>", value, "password"); addCriterion("`password` <>", value, "password");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andPasswordGreaterThan(String value) { public Criteria andPasswordGreaterThan(String value) {
addCriterion("password >", value, "password"); addCriterion("`password` >", value, "password");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andPasswordGreaterThanOrEqualTo(String value) { public Criteria andPasswordGreaterThanOrEqualTo(String value) {
addCriterion("password >=", value, "password"); addCriterion("`password` >=", value, "password");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andPasswordLessThan(String value) { public Criteria andPasswordLessThan(String value) {
addCriterion("password <", value, "password"); addCriterion("`password` <", value, "password");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andPasswordLessThanOrEqualTo(String value) { public Criteria andPasswordLessThanOrEqualTo(String value) {
addCriterion("password <=", value, "password"); addCriterion("`password` <=", value, "password");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andPasswordLike(String value) { public Criteria andPasswordLike(String value) {
addCriterion("password like", value, "password"); addCriterion("`password` like", value, "password");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andPasswordNotLike(String value) { public Criteria andPasswordNotLike(String value) {
addCriterion("password not like", value, "password"); addCriterion("`password` not like", value, "password");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andPasswordIn(List<String> values) { public Criteria andPasswordIn(List<String> values) {
addCriterion("password in", values, "password"); addCriterion("`password` in", values, "password");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andPasswordNotIn(List<String> values) { public Criteria andPasswordNotIn(List<String> values) {
addCriterion("password not in", values, "password"); addCriterion("`password` not in", values, "password");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andPasswordBetween(String value1, String value2) { public Criteria andPasswordBetween(String value1, String value2) {
addCriterion("password between", value1, value2, "password"); addCriterion("`password` between", value1, value2, "password");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andPasswordNotBetween(String value1, String value2) { public Criteria andPasswordNotBetween(String value1, String value2) {
addCriterion("password not between", value1, value2, "password"); addCriterion("`password` not between", value1, value2, "password");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andStatusIsNull() { public Criteria andStatusIsNull() {
addCriterion("status is null"); addCriterion("`status` is null");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andStatusIsNotNull() { public Criteria andStatusIsNotNull() {
addCriterion("status is not null"); addCriterion("`status` is not null");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andStatusEqualTo(String value) { public Criteria andStatusEqualTo(String value) {
addCriterion("status =", value, "status"); addCriterion("`status` =", value, "status");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andStatusNotEqualTo(String value) { public Criteria andStatusNotEqualTo(String value) {
addCriterion("status <>", value, "status"); addCriterion("`status` <>", value, "status");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andStatusGreaterThan(String value) { public Criteria andStatusGreaterThan(String value) {
addCriterion("status >", value, "status"); addCriterion("`status` >", value, "status");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andStatusGreaterThanOrEqualTo(String value) { public Criteria andStatusGreaterThanOrEqualTo(String value) {
addCriterion("status >=", value, "status"); addCriterion("`status` >=", value, "status");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andStatusLessThan(String value) { public Criteria andStatusLessThan(String value) {
addCriterion("status <", value, "status"); addCriterion("`status` <", value, "status");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andStatusLessThanOrEqualTo(String value) { public Criteria andStatusLessThanOrEqualTo(String value) {
addCriterion("status <=", value, "status"); addCriterion("`status` <=", value, "status");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andStatusLike(String value) { public Criteria andStatusLike(String value) {
addCriterion("status like", value, "status"); addCriterion("`status` like", value, "status");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andStatusNotLike(String value) { public Criteria andStatusNotLike(String value) {
addCriterion("status not like", value, "status"); addCriterion("`status` not like", value, "status");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andStatusIn(List<String> values) { public Criteria andStatusIn(List<String> values) {
addCriterion("status in", values, "status"); addCriterion("`status` in", values, "status");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andStatusNotIn(List<String> values) { public Criteria andStatusNotIn(List<String> values) {
addCriterion("status not in", values, "status"); addCriterion("`status` not in", values, "status");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andStatusBetween(String value1, String value2) { public Criteria andStatusBetween(String value1, String value2) {
addCriterion("status between", value1, value2, "status"); addCriterion("`status` between", value1, value2, "status");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andStatusNotBetween(String value1, String value2) { public Criteria andStatusNotBetween(String value1, String value2) {
addCriterion("status not between", value1, value2, "status"); addCriterion("`status` not between", value1, value2, "status");
return (Criteria) this; return (Criteria) this;
} }
@ -575,72 +575,72 @@ public class UserExample {
} }
public Criteria andLanguageIsNull() { public Criteria andLanguageIsNull() {
addCriterion("language is null"); addCriterion("`language` is null");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andLanguageIsNotNull() { public Criteria andLanguageIsNotNull() {
addCriterion("language is not null"); addCriterion("`language` is not null");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andLanguageEqualTo(String value) { public Criteria andLanguageEqualTo(String value) {
addCriterion("language =", value, "language"); addCriterion("`language` =", value, "language");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andLanguageNotEqualTo(String value) { public Criteria andLanguageNotEqualTo(String value) {
addCriterion("language <>", value, "language"); addCriterion("`language` <>", value, "language");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andLanguageGreaterThan(String value) { public Criteria andLanguageGreaterThan(String value) {
addCriterion("language >", value, "language"); addCriterion("`language` >", value, "language");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andLanguageGreaterThanOrEqualTo(String value) { public Criteria andLanguageGreaterThanOrEqualTo(String value) {
addCriterion("language >=", value, "language"); addCriterion("`language` >=", value, "language");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andLanguageLessThan(String value) { public Criteria andLanguageLessThan(String value) {
addCriterion("language <", value, "language"); addCriterion("`language` <", value, "language");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andLanguageLessThanOrEqualTo(String value) { public Criteria andLanguageLessThanOrEqualTo(String value) {
addCriterion("language <=", value, "language"); addCriterion("`language` <=", value, "language");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andLanguageLike(String value) { public Criteria andLanguageLike(String value) {
addCriterion("language like", value, "language"); addCriterion("`language` like", value, "language");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andLanguageNotLike(String value) { public Criteria andLanguageNotLike(String value) {
addCriterion("language not like", value, "language"); addCriterion("`language` not like", value, "language");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andLanguageIn(List<String> values) { public Criteria andLanguageIn(List<String> values) {
addCriterion("language in", values, "language"); addCriterion("`language` in", values, "language");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andLanguageNotIn(List<String> values) { public Criteria andLanguageNotIn(List<String> values) {
addCriterion("language not in", values, "language"); addCriterion("`language` not in", values, "language");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andLanguageBetween(String value1, String value2) { public Criteria andLanguageBetween(String value1, String value2) {
addCriterion("language between", value1, value2, "language"); addCriterion("`language` between", value1, value2, "language");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andLanguageNotBetween(String value1, String value2) { public Criteria andLanguageNotBetween(String value1, String value2) {
addCriterion("language not between", value1, value2, "language"); addCriterion("`language` not between", value1, value2, "language");
return (Criteria) this; return (Criteria) this;
} }
@ -853,6 +853,76 @@ public class UserExample {
addCriterion("phone not between", value1, value2, "phone"); addCriterion("phone not between", value1, value2, "phone");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andSourceIsNull() {
addCriterion("`source` is null");
return (Criteria) this;
}
public Criteria andSourceIsNotNull() {
addCriterion("`source` is not null");
return (Criteria) this;
}
public Criteria andSourceEqualTo(String value) {
addCriterion("`source` =", value, "source");
return (Criteria) this;
}
public Criteria andSourceNotEqualTo(String value) {
addCriterion("`source` <>", value, "source");
return (Criteria) this;
}
public Criteria andSourceGreaterThan(String value) {
addCriterion("`source` >", value, "source");
return (Criteria) this;
}
public Criteria andSourceGreaterThanOrEqualTo(String value) {
addCriterion("`source` >=", value, "source");
return (Criteria) this;
}
public Criteria andSourceLessThan(String value) {
addCriterion("`source` <", value, "source");
return (Criteria) this;
}
public Criteria andSourceLessThanOrEqualTo(String value) {
addCriterion("`source` <=", value, "source");
return (Criteria) this;
}
public Criteria andSourceLike(String value) {
addCriterion("`source` like", value, "source");
return (Criteria) this;
}
public Criteria andSourceNotLike(String value) {
addCriterion("`source` not like", value, "source");
return (Criteria) this;
}
public Criteria andSourceIn(List<String> values) {
addCriterion("`source` in", values, "source");
return (Criteria) this;
}
public Criteria andSourceNotIn(List<String> values) {
addCriterion("`source` not in", values, "source");
return (Criteria) this;
}
public Criteria andSourceBetween(String value1, String value2) {
addCriterion("`source` between", value1, value2, "source");
return (Criteria) this;
}
public Criteria andSourceNotBetween(String value1, String value2) {
addCriterion("`source` not between", value1, value2, "source");
return (Criteria) this;
}
} }
public static class Criteria extends GeneratedCriteria { public static class Criteria extends GeneratedCriteria {

View File

@ -2,9 +2,8 @@ package io.metersphere.base.mapper;
import io.metersphere.base.domain.User; import io.metersphere.base.domain.User;
import io.metersphere.base.domain.UserExample; import io.metersphere.base.domain.UserExample;
import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface UserMapper { public interface UserMapper {
long countByExample(UserExample example); long countByExample(UserExample example);
@ -28,7 +27,4 @@ public interface UserMapper {
int updateByPrimaryKeySelective(User record); int updateByPrimaryKeySelective(User record);
int updateByPrimaryKey(User record); int updateByPrimaryKey(User record);
} }

View File

@ -13,6 +13,7 @@
<result column="last_workspace_id" jdbcType="VARCHAR" property="lastWorkspaceId" /> <result column="last_workspace_id" jdbcType="VARCHAR" property="lastWorkspaceId" />
<result column="last_organization_id" jdbcType="VARCHAR" property="lastOrganizationId" /> <result column="last_organization_id" jdbcType="VARCHAR" property="lastOrganizationId" />
<result column="phone" jdbcType="VARCHAR" property="phone" /> <result column="phone" jdbcType="VARCHAR" property="phone" />
<result column="source" jdbcType="VARCHAR" property="source" />
</resultMap> </resultMap>
<sql id="Example_Where_Clause"> <sql id="Example_Where_Clause">
<where> <where>
@ -73,8 +74,8 @@
</where> </where>
</sql> </sql>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, name, email, password, status, create_time, update_time, language, last_workspace_id, id, `name`, email, `password`, `status`, create_time, update_time, `language`, last_workspace_id,
last_organization_id, phone last_organization_id, phone, `source`
</sql> </sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.UserExample" resultMap="BaseResultMap"> <select id="selectByExample" parameterType="io.metersphere.base.domain.UserExample" resultMap="BaseResultMap">
select select
@ -107,14 +108,16 @@
</if> </if>
</delete> </delete>
<insert id="insert" parameterType="io.metersphere.base.domain.User"> <insert id="insert" parameterType="io.metersphere.base.domain.User">
insert into user (id, name, email, insert into user (id, `name`, email,
password, status, create_time, `password`, `status`, create_time,
update_time, language, last_workspace_id, update_time, `language`, last_workspace_id,
last_organization_id, phone) last_organization_id, phone, `source`
)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR}, values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR},
#{password,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{password,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT},
#{updateTime,jdbcType=BIGINT}, #{language,jdbcType=VARCHAR}, #{lastWorkspaceId,jdbcType=VARCHAR}, #{updateTime,jdbcType=BIGINT}, #{language,jdbcType=VARCHAR}, #{lastWorkspaceId,jdbcType=VARCHAR},
#{lastOrganizationId,jdbcType=VARCHAR}, #{phone,jdbcType=VARCHAR}) #{lastOrganizationId,jdbcType=VARCHAR}, #{phone,jdbcType=VARCHAR}, #{source,jdbcType=VARCHAR}
)
</insert> </insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.User"> <insert id="insertSelective" parameterType="io.metersphere.base.domain.User">
insert into user insert into user
@ -123,16 +126,16 @@
id, id,
</if> </if>
<if test="name != null"> <if test="name != null">
name, `name`,
</if> </if>
<if test="email != null"> <if test="email != null">
email, email,
</if> </if>
<if test="password != null"> <if test="password != null">
password, `password`,
</if> </if>
<if test="status != null"> <if test="status != null">
status, `status`,
</if> </if>
<if test="createTime != null"> <if test="createTime != null">
create_time, create_time,
@ -141,7 +144,7 @@
update_time, update_time,
</if> </if>
<if test="language != null"> <if test="language != null">
language, `language`,
</if> </if>
<if test="lastWorkspaceId != null"> <if test="lastWorkspaceId != null">
last_workspace_id, last_workspace_id,
@ -152,6 +155,9 @@
<if test="phone != null"> <if test="phone != null">
phone, phone,
</if> </if>
<if test="source != null">
`source`,
</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null"> <if test="id != null">
@ -187,6 +193,9 @@
<if test="phone != null"> <if test="phone != null">
#{phone,jdbcType=VARCHAR}, #{phone,jdbcType=VARCHAR},
</if> </if>
<if test="source != null">
#{source,jdbcType=VARCHAR},
</if>
</trim> </trim>
</insert> </insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.UserExample" resultType="java.lang.Long"> <select id="countByExample" parameterType="io.metersphere.base.domain.UserExample" resultType="java.lang.Long">
@ -202,16 +211,16 @@
id = #{record.id,jdbcType=VARCHAR}, id = #{record.id,jdbcType=VARCHAR},
</if> </if>
<if test="record.name != null"> <if test="record.name != null">
name = #{record.name,jdbcType=VARCHAR}, `name` = #{record.name,jdbcType=VARCHAR},
</if> </if>
<if test="record.email != null"> <if test="record.email != null">
email = #{record.email,jdbcType=VARCHAR}, email = #{record.email,jdbcType=VARCHAR},
</if> </if>
<if test="record.password != null"> <if test="record.password != null">
password = #{record.password,jdbcType=VARCHAR}, `password` = #{record.password,jdbcType=VARCHAR},
</if> </if>
<if test="record.status != null"> <if test="record.status != null">
status = #{record.status,jdbcType=VARCHAR}, `status` = #{record.status,jdbcType=VARCHAR},
</if> </if>
<if test="record.createTime != null"> <if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT}, create_time = #{record.createTime,jdbcType=BIGINT},
@ -220,7 +229,7 @@
update_time = #{record.updateTime,jdbcType=BIGINT}, update_time = #{record.updateTime,jdbcType=BIGINT},
</if> </if>
<if test="record.language != null"> <if test="record.language != null">
language = #{record.language,jdbcType=VARCHAR}, `language` = #{record.language,jdbcType=VARCHAR},
</if> </if>
<if test="record.lastWorkspaceId != null"> <if test="record.lastWorkspaceId != null">
last_workspace_id = #{record.lastWorkspaceId,jdbcType=VARCHAR}, last_workspace_id = #{record.lastWorkspaceId,jdbcType=VARCHAR},
@ -231,6 +240,9 @@
<if test="record.phone != null"> <if test="record.phone != null">
phone = #{record.phone,jdbcType=VARCHAR}, phone = #{record.phone,jdbcType=VARCHAR},
</if> </if>
<if test="record.source != null">
`source` = #{record.source,jdbcType=VARCHAR},
</if>
</set> </set>
<if test="_parameter != null"> <if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" /> <include refid="Update_By_Example_Where_Clause" />
@ -239,16 +251,17 @@
<update id="updateByExample" parameterType="map"> <update id="updateByExample" parameterType="map">
update user update user
set id = #{record.id,jdbcType=VARCHAR}, set id = #{record.id,jdbcType=VARCHAR},
name = #{record.name,jdbcType=VARCHAR}, `name` = #{record.name,jdbcType=VARCHAR},
email = #{record.email,jdbcType=VARCHAR}, email = #{record.email,jdbcType=VARCHAR},
password = #{record.password,jdbcType=VARCHAR}, `password` = #{record.password,jdbcType=VARCHAR},
status = #{record.status,jdbcType=VARCHAR}, `status` = #{record.status,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT}, create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT}, update_time = #{record.updateTime,jdbcType=BIGINT},
language = #{record.language,jdbcType=VARCHAR}, `language` = #{record.language,jdbcType=VARCHAR},
last_workspace_id = #{record.lastWorkspaceId,jdbcType=VARCHAR}, last_workspace_id = #{record.lastWorkspaceId,jdbcType=VARCHAR},
last_organization_id = #{record.lastOrganizationId,jdbcType=VARCHAR}, last_organization_id = #{record.lastOrganizationId,jdbcType=VARCHAR},
phone = #{record.phone,jdbcType=VARCHAR} phone = #{record.phone,jdbcType=VARCHAR},
`source` = #{record.source,jdbcType=VARCHAR}
<if test="_parameter != null"> <if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" /> <include refid="Update_By_Example_Where_Clause" />
</if> </if>
@ -257,16 +270,16 @@
update user update user
<set> <set>
<if test="name != null"> <if test="name != null">
name = #{name,jdbcType=VARCHAR}, `name` = #{name,jdbcType=VARCHAR},
</if> </if>
<if test="email != null"> <if test="email != null">
email = #{email,jdbcType=VARCHAR}, email = #{email,jdbcType=VARCHAR},
</if> </if>
<if test="password != null"> <if test="password != null">
password = #{password,jdbcType=VARCHAR}, `password` = #{password,jdbcType=VARCHAR},
</if> </if>
<if test="status != null"> <if test="status != null">
status = #{status,jdbcType=VARCHAR}, `status` = #{status,jdbcType=VARCHAR},
</if> </if>
<if test="createTime != null"> <if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT}, create_time = #{createTime,jdbcType=BIGINT},
@ -275,7 +288,7 @@
update_time = #{updateTime,jdbcType=BIGINT}, update_time = #{updateTime,jdbcType=BIGINT},
</if> </if>
<if test="language != null"> <if test="language != null">
language = #{language,jdbcType=VARCHAR}, `language` = #{language,jdbcType=VARCHAR},
</if> </if>
<if test="lastWorkspaceId != null"> <if test="lastWorkspaceId != null">
last_workspace_id = #{lastWorkspaceId,jdbcType=VARCHAR}, last_workspace_id = #{lastWorkspaceId,jdbcType=VARCHAR},
@ -286,22 +299,25 @@
<if test="phone != null"> <if test="phone != null">
phone = #{phone,jdbcType=VARCHAR}, phone = #{phone,jdbcType=VARCHAR},
</if> </if>
<if test="source != null">
`source` = #{source,jdbcType=VARCHAR},
</if>
</set> </set>
where id = #{id,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR}
</update> </update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.User"> <update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.User">
update user update user
set name = #{name,jdbcType=VARCHAR}, set `name` = #{name,jdbcType=VARCHAR},
email = #{email,jdbcType=VARCHAR}, email = #{email,jdbcType=VARCHAR},
password = #{password,jdbcType=VARCHAR}, `password` = #{password,jdbcType=VARCHAR},
status = #{status,jdbcType=VARCHAR}, `status` = #{status,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT}, create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT}, update_time = #{updateTime,jdbcType=BIGINT},
language = #{language,jdbcType=VARCHAR}, `language` = #{language,jdbcType=VARCHAR},
last_workspace_id = #{lastWorkspaceId,jdbcType=VARCHAR}, last_workspace_id = #{lastWorkspaceId,jdbcType=VARCHAR},
last_organization_id = #{lastOrganizationId,jdbcType=VARCHAR}, last_organization_id = #{lastOrganizationId,jdbcType=VARCHAR},
phone = #{phone,jdbcType=VARCHAR} phone = #{phone,jdbcType=VARCHAR},
`source` = #{source,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR}
</update> </update>
</mapper> </mapper>

View File

@ -8,15 +8,109 @@
<result column="user_name" property="userName"/> <result column="user_name" property="userName"/>
</resultMap> </resultMap>
<sql id="condition">
<choose>
<when test='${object}.operator == "like"'>
like CONCAT('%', #{${object}.value},'%')
</when>
<when test='${object}.operator == "not like"'>
not like CONCAT('%', #{${object}.value},'%')
</when>
<when test='${object}.operator == "in"'>
in
<foreach collection="${object}.value" item="v" separator="," open="(" close=")">
#{v}
</foreach>
</when>
<when test='${object}.operator == "not in"'>
not in
<foreach collection="${object}.value" item="v" separator="," open="(" close=")">
#{v}
</foreach>
</when>
<when test='${object}.operator == "between"'>
between #{${object}.value[0]} and #{${object}.value[1]}
</when>
<when test='${object}.operator == "gt"'>
&gt; #{${object}.value}
</when>
<when test='${object}.operator == "lt"'>
&lt; #{${object}.value}
</when>
<when test='${object}.operator == "ge"'>
&gt;= #{${object}.value}
</when>
<when test='${object}.operator == "le"'>
&lt;= #{${object}.value}
</when>
<when test='${object}.operator == "current user"'>
= '${@io.metersphere.commons.utils.SessionUtils@getUserId()}'
</when>
<otherwise>
= #{${object}.value}
</otherwise>
</choose>
</sql>
<sql id="combine">
<if test="${condition}.name != null">
and api_test.name
<include refid="condition">
<property name="object" value="${condition}.name"/>
</include>
</if>
<if test="${condition}.updateTime != null">
and api_test.update_time
<include refid="condition">
<property name="object" value="${condition}.updateTime"/>
</include>
</if>
<if test="${condition}.projectName != null">
and project.name
<include refid="condition">
<property name="object" value="${condition}.projectName"/>
</include>
</if>
<if test="${condition}.createTime != null">
and api_test.create_time
<include refid="condition">
<property name="object" value="${condition}.createTime"/>
</include>
</if>
<if test="${condition}.status != null">
and api_test.status
<include refid="condition">
<property name="object" value="${condition}.status"/>
</include>
</if>
<if test="${condition}.creator != null">
and api_test.user_id
<include refid="condition">
<property name="object" value="${condition}.creator"/>
</include>
</if>
</sql>
<select id="list" resultMap="BaseResultMap" parameterType="io.metersphere.api.dto.APITestResult"> <select id="list" resultMap="BaseResultMap" parameterType="io.metersphere.api.dto.APITestResult">
select api_test.*, project.name as project_name, user.name as user_name select api_test.*, project.name as project_name, user.name as user_name
from api_test from api_test
left join project on api_test.project_id = project.id left join project on api_test.project_id = project.id
left join user on api_test.user_id = user.id left join user on api_test.user_id = user.id
<where> <where>
<if test="request.name != null"> <choose>
and api_test.name like CONCAT('%', #{request.name},'%') <!--高级-->
</if> <when test="request.combine != null">
<include refid="combine">
<property name="condition" value="request.combine"/>
</include>
</when>
<!--普通-->
<otherwise>
<if test="request.name != null">
and api_test.name like CONCAT('%', #{request.name},'%')
</if>
</otherwise>
</choose>
<if test="request.workspaceId != null"> <if test="request.workspaceId != null">
AND project.workspace_id = #{request.workspaceId} AND project.workspace_id = #{request.workspaceId}
</if> </if>

View File

@ -9,6 +9,55 @@
<result column="user_name" property="userName"/> <result column="user_name" property="userName"/>
</resultMap> </resultMap>
<sql id="condition">
<include refid="io.metersphere.base.mapper.ext.ExtApiTestMapper.condition"/>
</sql>
<sql id="combine">
<if test="${condition}.name != null">
and r.name
<include refid="condition">
<property name="object" value="${condition}.name"/>
</include>
</if>
<if test="${condition}.testName != null">
and t.name
<include refid="condition">
<property name="object" value="${condition}.testName"/>
</include>
</if>
<if test="${condition}.projectName != null">
and project.name
<include refid="condition">
<property name="object" value="${condition}.projectName"/>
</include>
</if>
<if test="${condition}.createTime != null">
and r.create_time
<include refid="condition">
<property name="object" value="${condition}.createTime"/>
</include>
</if>
<if test="${condition}.status != null">
and r.status
<include refid="condition">
<property name="object" value="${condition}.status"/>
</include>
</if>
<if test="${condition}.triggerMode != null">
and r.trigger_mode
<include refid="condition">
<property name="object" value="${condition}.triggerMode"/>
</include>
</if>
<if test="${condition}.creator != null">
and r.user_id
<include refid="condition">
<property name="object" value="${condition}.creator"/>
</include>
</if>
</sql>
<select id="list" resultMap="BaseResultMap"> <select id="list" resultMap="BaseResultMap">
SELECT t.name AS test_name, SELECT t.name AS test_name,
r.name, r.description, r.id, r.test_id, r.create_time, r.update_time, r.status, r.trigger_mode, r.name, r.description, r.id, r.test_id, r.create_time, r.update_time, r.status, r.trigger_mode,
@ -17,9 +66,20 @@
LEFT JOIN project ON project.id = t.project_id LEFT JOIN project ON project.id = t.project_id
LEFT JOIN user ON user.id = r.user_id LEFT JOIN user ON user.id = r.user_id
<where> <where>
<if test="request.name != null"> <choose>
AND r.name like CONCAT('%', #{request.name},'%') <!--高级-->
</if> <when test="request.combine != null">
<include refid="combine">
<property name="condition" value="request.combine"/>
</include>
</when>
<!--普通-->
<otherwise>
<if test="request.name != null">
and r.name like CONCAT('%', #{request.name},'%')
</if>
</otherwise>
</choose>
<if test="request.projectId != null"> <if test="request.projectId != null">
AND project.id = #{request.projectId} AND project.id = #{request.projectId}
</if> </if>

View File

@ -8,15 +8,69 @@
<result column="user_name" property="userName"/> <result column="user_name" property="userName"/>
</resultMap> </resultMap>
<sql id="condition">
<include refid="io.metersphere.base.mapper.ext.ExtApiTestMapper.condition"/>
</sql>
<sql id="combine">
<if test="${condition}.name != null">
and load_test.name
<include refid="condition">
<property name="object" value="${condition}.name"/>
</include>
</if>
<if test="${condition}.updateTime != null">
and load_test.update_time
<include refid="condition">
<property name="object" value="${condition}.updateTime"/>
</include>
</if>
<if test="${condition}.projectName != null">
and project.name
<include refid="condition">
<property name="object" value="${condition}.projectName"/>
</include>
</if>
<if test="${condition}.createTime != null">
and load_test.create_time
<include refid="condition">
<property name="object" value="${condition}.createTime"/>
</include>
</if>
<if test="${condition}.status != null">
and load_test.status
<include refid="condition">
<property name="object" value="${condition}.status"/>
</include>
</if>
<if test="${condition}.creator != null">
and load_test.user_id
<include refid="condition">
<property name="object" value="${condition}.creator"/>
</include>
</if>
</sql>
<select id="list" resultMap="BaseResultMap" parameterType="io.metersphere.track.request.testplan.QueryTestPlanRequest"> <select id="list" resultMap="BaseResultMap" parameterType="io.metersphere.track.request.testplan.QueryTestPlanRequest">
select load_test.*, project.name as project_name, user.name as user_name select load_test.*, project.name as project_name, user.name as user_name
from load_test from load_test
left join project on load_test.project_id = project.id left join project on load_test.project_id = project.id
left join user on load_test.user_id = user.id left join user on load_test.user_id = user.id
<where> <where>
<if test="request.name != null"> <choose>
and load_test.name like CONCAT('%', #{request.name},'%') <!--高级-->
</if> <when test="request.combine != null">
<include refid="combine">
<property name="condition" value="request.combine"/>
</include>
</when>
<!--普通-->
<otherwise>
<if test="request.name != null">
and load_test.name like CONCAT('%', #{request.name},'%')
</if>
</otherwise>
</choose>
<if test="request.workspaceId != null"> <if test="request.workspaceId != null">
AND project.workspace_id = #{request.workspaceId} AND project.workspace_id = #{request.workspaceId}
</if> </if>

View File

@ -15,6 +15,55 @@
id, test_id, name, create_time, update_time, status id, test_id, name, create_time, update_time, status
</sql> </sql>
<sql id="condition">
<include refid="io.metersphere.base.mapper.ext.ExtApiTestMapper.condition"/>
</sql>
<sql id="combine">
<if test="${condition}.name != null">
and ltr.name
<include refid="condition">
<property name="object" value="${condition}.name"/>
</include>
</if>
<if test="${condition}.testName != null">
and lt.name
<include refid="condition">
<property name="object" value="${condition}.testName"/>
</include>
</if>
<if test="${condition}.projectName != null">
and project.name
<include refid="condition">
<property name="object" value="${condition}.projectName"/>
</include>
</if>
<if test="${condition}.createTime != null">
and ltr.create_time
<include refid="condition">
<property name="object" value="${condition}.createTime"/>
</include>
</if>
<if test="${condition}.status != null">
and ltr.status
<include refid="condition">
<property name="object" value="${condition}.status"/>
</include>
</if>
<if test="${condition}.triggerMode != null">
and ltr.trigger_mode
<include refid="condition">
<property name="object" value="${condition}.triggerMode"/>
</include>
</if>
<if test="${condition}.creator != null">
and ltr.user_id
<include refid="condition">
<property name="object" value="${condition}.creator"/>
</include>
</if>
</sql>
<select id="getReportList" resultType="io.metersphere.dto.ReportDTO"> <select id="getReportList" resultType="io.metersphere.dto.ReportDTO">
select ltr.id, ltr.name, ltr.test_id as testId, ltr.description, user.name as userName, project.name as select ltr.id, ltr.name, ltr.test_id as testId, ltr.description, user.name as userName, project.name as
projectName, ltr.trigger_mode, projectName, ltr.trigger_mode,
@ -26,9 +75,20 @@
JOIN project on project.id = lt.project_id JOIN project on project.id = lt.project_id
</if> </if>
<where> <where>
<if test="reportRequest.name != null"> <choose>
AND ltr.name like CONCAT('%', #{reportRequest.name},'%') <!--高级-->
</if> <when test="reportRequest.combine != null">
<include refid="combine">
<property name="condition" value="reportRequest.combine"/>
</include>
</when>
<!--普通-->
<otherwise>
<if test="reportRequest.name != null">
AND ltr.name like CONCAT('%', #{reportRequest.name},'%')
</if>
</otherwise>
</choose>
<if test="reportRequest.workspaceId != null"> <if test="reportRequest.workspaceId != null">
AND workspace_id = #{reportRequest.workspaceId,jdbcType=VARCHAR} AND workspace_id = #{reportRequest.workspaceId,jdbcType=VARCHAR}
</if> </if>

View File

@ -15,4 +15,6 @@ public interface ExtTestCaseMapper {
List<TestCaseDTO> listByMethod(@Param("request") QueryTestCaseRequest request); List<TestCaseDTO> listByMethod(@Param("request") QueryTestCaseRequest request);
List<TestCaseDTO> listBytestCaseIds(@Param("request") QueryTestCaseRequest request);
} }

View File

@ -2,10 +2,120 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <!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.ExtTestCaseMapper"> <mapper namespace="io.metersphere.base.mapper.ext.ExtTestCaseMapper">
<sql id="condition">
<choose>
<when test='${object}.operator == "like"'>
like CONCAT('%', #{${object}.value},'%')
</when>
<when test='${object}.operator == "not like"'>
not like CONCAT('%', #{${object}.value},'%')
</when>
<when test='${object}.operator == "in"'>
in
<foreach collection="${object}.value" item="v" separator="," open="(" close=")">
#{v}
</foreach>
</when>
<when test='${object}.operator == "not in"'>
not in
<foreach collection="${object}.value" item="v" separator="," open="(" close=")">
#{v}
</foreach>
</when>
<when test='${object}.operator == "between"'>
between #{${object}.value[0]} and #{${object}.value[1]}
</when>
<when test='${object}.operator == "gt"'>
&gt; #{${object}.value}
</when>
<when test='${object}.operator == "lt"'>
&lt; #{${object}.value}
</when>
<when test='${object}.operator == "ge"'>
&gt;= #{${object}.value}
</when>
<when test='${object}.operator == "le"'>
&lt;= #{${object}.value}
</when>
<when test='${object}.operator == "current user"'>
= '${@io.metersphere.commons.utils.SessionUtils@getUserId()}'
</when>
<otherwise>
= #{${object}.value}
</otherwise>
</choose>
</sql>
<sql id="combine">
<if test="${condition}.name != null">
and test_case.name
<include refid="condition">
<property name="object" value="${condition}.name"/>
</include>
</if>
<if test="${condition}.module != null">
and test_case.node_path
<include refid="condition">
<property name="object" value="${condition}.module"/>
</include>
</if>
<if test="${condition}.priority != null">
and test_case.priority
<include refid="condition">
<property name="object" value="${condition}.priority"/>
</include>
</if>
<if test="${condition}.createTime != null">
and test_case.create_time
<include refid="condition">
<property name="object" value="${condition}.createTime"/>
</include>
</if>
<if test="${condition}.type != null">
and test_case.type
<include refid="condition">
<property name="object" value="${condition}.type"/>
</include>
</if>
<if test="${condition}.updateTime != null">
and test_case.update_time
<include refid="condition">
<property name="object" value="${condition}.updateTime"/>
</include>
</if>
<if test="${condition}.method != null">
and test_case.method
<include refid="condition">
<property name="object" value="${condition}.method"/>
</include>
</if>
<if test="${condition}.creator != null">
and test_case.maintainer
<include refid="condition">
<property name="object" value="${condition}.creator"/>
</include>
</if>
</sql>
<select id="getTestCaseNames" resultType="io.metersphere.base.domain.TestCase"> <select id="getTestCaseNames" resultType="io.metersphere.base.domain.TestCase">
select test_case.id, test_case.name, test_case.priority, test_case.type select test_case.id, test_case.name, test_case.priority, test_case.type
from test_case from test_case
<where> <where>
<choose>
<!--高级-->
<when test="request.combine != null">
<include refid="combine">
<property name="condition" value="request.combine"/>
</include>
</when>
<!--普通-->
<otherwise>
<if test="request.name != null">
and test_case.name like CONCAT('%', #{request.name},'%')
</if>
</otherwise>
</choose>
<if test="request.projectId != null"> <if test="request.projectId != null">
AND test_case.project_id = #{request.projectId} AND test_case.project_id = #{request.projectId}
</if> </if>
@ -14,7 +124,6 @@
<foreach collection="request.nodeIds" open="(" close=")" separator="," item="nodeId"> <foreach collection="request.nodeIds" open="(" close=")" separator="," item="nodeId">
#{nodeId} #{nodeId}
</foreach> </foreach>
</if> </if>
<if test="request.filters != null and request.filters.size() > 0"> <if test="request.filters != null and request.filters.size() > 0">
<foreach collection="request.filters.entrySet()" index="key" item="values"> <foreach collection="request.filters.entrySet()" index="key" item="values">
@ -78,4 +187,15 @@
</if> </if>
</where> </where>
</select> </select>
<select id="listBytestCaseIds" resultType="io.metersphere.track.dto.TestCaseDTO">
select test_case.*,api_test.name as apiName,load_test.name AS performName from test_case left join api_test on test_case.test_id=api_test.id left join load_test on test_case.test_id=load_test.id
<where>
<if test="request.testCaseIds!=null and request.testCaseIds.size() > 0">
and test_case.id in
<foreach collection="request.testCaseIds" open="(" close=")" separator="," item="id">
#{id}
</foreach>
</if>
</where>
</select>
</mapper> </mapper>

View File

@ -1,5 +1,5 @@
package io.metersphere.commons.constants; package io.metersphere.commons.constants;
public enum APITestStatus { public enum APITestStatus {
Saved, Starting, Running, Completed, Error Saved, Starting, Running, Reporting, Completed, Error
} }

View File

@ -0,0 +1,5 @@
package io.metersphere.commons.constants;
public enum UserSource {
LOCAL, LDAP
}

View File

@ -5,12 +5,17 @@ import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session; import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.Subject;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import static io.metersphere.commons.constants.SessionConstants.ATTR_USER; import static io.metersphere.commons.constants.SessionConstants.ATTR_USER;
public class SessionUtils { public class SessionUtils {
public static String getUserId() {
return Objects.requireNonNull(getUser()).getId();
}
public static SessionUser getUser() { public static SessionUser getUser() {
try { try {
Subject subject = SecurityUtils.getSubject(); Subject subject = SecurityUtils.getSubject();

View File

@ -1,23 +1,13 @@
package io.metersphere.controller; package io.metersphere.controller;
import io.metersphere.base.domain.UserRole; import io.metersphere.commons.constants.UserSource;
import io.metersphere.controller.request.LoginRequest; import io.metersphere.controller.request.LoginRequest;
import io.metersphere.dto.UserDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.service.UserService; import io.metersphere.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.subject.Subject;
import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
import static io.metersphere.commons.constants.SessionConstants.ATTR_USER;
@RestController @RestController
@RequestMapping @RequestMapping
@ -36,6 +26,7 @@ public class LoginController {
@PostMapping(value = "/signin") @PostMapping(value = "/signin")
public ResultHolder login(@RequestBody LoginRequest request) { public ResultHolder login(@RequestBody LoginRequest request) {
SecurityUtils.getSubject().getSession().setAttribute("authenticate", UserSource.LOCAL.name());
return userService.login(request); return userService.login(request);
} }

View File

@ -21,6 +21,8 @@ public class UserDTO {
private String status; private String status;
private String source;
private Long createTime; private Long createTime;
private Long updateTime; private Long updateTime;

View File

@ -2,18 +2,19 @@ package io.metersphere.ldap.controller;
import io.metersphere.base.domain.User; import io.metersphere.base.domain.User;
import io.metersphere.commons.constants.ParamConstants; import io.metersphere.commons.constants.ParamConstants;
import io.metersphere.commons.constants.UserSource;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.controller.ResultHolder; import io.metersphere.controller.ResultHolder;
import io.metersphere.controller.request.LoginRequest; import io.metersphere.controller.request.LoginRequest;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import io.metersphere.ldap.domain.Person; import io.metersphere.ldap.domain.Person;
import io.metersphere.ldap.service.LdapService; import io.metersphere.ldap.service.LdapService;
import io.metersphere.ldap.domain.LdapInfo;
import io.metersphere.service.SystemParameterService; import io.metersphere.service.SystemParameterService;
import io.metersphere.service.UserService; import io.metersphere.service.UserService;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
@RestController @RestController
@ -37,10 +38,9 @@ public class LdapController {
Person person = ldapService.authenticate(request); Person person = ldapService.authenticate(request);
SecurityUtils.getSubject().getSession().setAttribute("authenticate", "ldap"); SecurityUtils.getSubject().getSession().setAttribute("authenticate", UserSource.LDAP.name());
String username = request.getUsername(); String username = request.getUsername();
String password = request.getPassword();
String email = person.getEmail(); String email = person.getEmail();
@ -54,18 +54,15 @@ public class LdapController {
user.setId(username); user.setId(username);
user.setName(username); user.setName(username);
user.setEmail(email); user.setEmail(email);
user.setPassword(password); user.setSource(UserSource.LDAP.name());
userService.createUser(user); userService.addLdapUser(user);
} else {
request.setUsername(u.getId());
request.setPassword(u.getPassword());
} }
return userService.login(request); return userService.login(request);
} }
@PostMapping("/test/connect") @PostMapping("/test/connect")
public void testConnect(@RequestBody LdapInfo ldapInfo) { public void testConnect() {
ldapService.testConnect(); ldapService.testConnect();
} }

View File

@ -57,17 +57,22 @@ public class PersonRepoImpl implements PersonRepo {
LdapTemplate ldapTemplate = getConnection(); LdapTemplate ldapTemplate = getConnection();
String filter = getUserFilter(); String filter = getUserFilter();
String ou = getUserOu(); String[] arr = getUserOu();
List<Person> result = null; List<Person> result = null;
try { for (String ou : arr) {
result = ldapTemplate.search(query().base(ou).filter(filter, username), getContextMapper()); try {
} catch (NameNotFoundException e) { result = ldapTemplate.search(query().base(ou.trim()).filter(filter, username), getContextMapper());
MSException.throwException(Translator.get("login_fail_ou_error")); if (result.size() == 1) {
} catch (InvalidNameException e) { return result.get(0);
MSException.throwException(Translator.get("login_fail_ou_error")); }
} catch (InvalidSearchFilterException e) { } catch (NameNotFoundException e) {
MSException.throwException(Translator.get("login_fail_filter_error")); MSException.throwException(Translator.get("login_fail_ou_error"));
} catch (InvalidNameException e) {
MSException.throwException(Translator.get("login_fail_ou_error"));
} catch (InvalidSearchFilterException e) {
MSException.throwException(Translator.get("login_fail_filter_error"));
}
} }
if (result.size() != 1) { if (result.size() != 1) {
@ -87,14 +92,16 @@ public class PersonRepoImpl implements PersonRepo {
return filter; return filter;
} }
private String getUserOu() { private String[] getUserOu() {
String ou = service.getValue(ParamConstants.LDAP.OU.getValue()); String ou = service.getValue(ParamConstants.LDAP.OU.getValue());
if (StringUtils.isBlank(ou)) { if (StringUtils.isBlank(ou)) {
MSException.throwException(Translator.get("ldap_ou_is_null")); MSException.throwException(Translator.get("ldap_ou_is_null"));
} }
return ou; String[] arr = ou.split("\\|");
return arr;
} }
protected ContextMapper getContextMapper() { protected ContextMapper getContextMapper() {

View File

@ -14,4 +14,5 @@ public class ReportRequest {
private String workspaceId; private String workspaceId;
private List<OrderRequest> orders; private List<OrderRequest> orders;
private Map<String, List<String>> filters; private Map<String, List<String>> filters;
private Map<String, Object> combine;
} }

View File

@ -110,6 +110,8 @@ public class EngineFactory {
try (ByteArrayInputStream source = new ByteArrayInputStream(fileContent.getFile())) { try (ByteArrayInputStream source = new ByteArrayInputStream(fileContent.getFile())) {
String content = engineSourceParser.parse(engineContext, source); String content = engineSourceParser.parse(engineContext, source);
engineContext.setContent(content); engineContext.setContent(content);
} catch (MSException e) {
throw e;
} catch (Exception e) { } catch (Exception e) {
MSException.throwException(e); MSException.throwException(e);
} }

View File

@ -66,6 +66,8 @@ public class DockerTestEngine extends AbstractEngine {
EngineContext context = null; EngineContext context = null;
try { try {
context = EngineFactory.createContext(loadTest, resource.getId(), realThreadNum, this.getStartTime(), this.getReportId(), resourceIndex); context = EngineFactory.createContext(loadTest, resource.getId(), realThreadNum, this.getStartTime(), this.getReportId(), resourceIndex);
} catch (MSException e) {
throw e;
} catch (Exception e) { } catch (Exception e) {
MSException.throwException(e); MSException.throwException(e);
} }

View File

@ -2,8 +2,10 @@ package io.metersphere.performance.parse.xml.reader.jmx;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.config.KafkaProperties; import io.metersphere.config.KafkaProperties;
import io.metersphere.i18n.Translator;
import io.metersphere.performance.engine.EngineContext; import io.metersphere.performance.engine.EngineContext;
import io.metersphere.performance.parse.xml.reader.DocumentParser; import io.metersphere.performance.parse.xml.reader.DocumentParser;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -709,6 +711,14 @@ public class JmeterDocumentParser implements DocumentParser {
} }
private void processThreadGroup(Element threadGroup) { private void processThreadGroup(Element threadGroup) {
// 检查 threadgroup 后面的hashtree是否为空
Node hashTree = threadGroup.getNextSibling();
while (!(hashTree instanceof Element)) {
hashTree = hashTree.getNextSibling();
}
if (!hashTree.hasChildNodes()) {
MSException.throwException(Translator.get("jmx_content_valid"));
}
// 重命名 tagName // 重命名 tagName
Document document = threadGroup.getOwnerDocument(); Document document = threadGroup.getOwnerDocument();
document.renameNode(threadGroup, threadGroup.getNamespaceURI(), CONCURRENCY_THREAD_GROUP); document.renameNode(threadGroup, threadGroup.getNamespaceURI(), CONCURRENCY_THREAD_GROUP);

View File

@ -22,6 +22,7 @@ import io.metersphere.service.FileService;
import io.metersphere.service.ScheduleService; import io.metersphere.service.ScheduleService;
import io.metersphere.service.TestResourceService; import io.metersphere.service.TestResourceService;
import io.metersphere.track.request.testplan.*; import io.metersphere.track.request.testplan.*;
import io.metersphere.track.service.TestCaseService;
import org.apache.commons.collections4.ListUtils; import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -73,6 +74,8 @@ public class PerformanceTestService {
private ScheduleService scheduleService; private ScheduleService scheduleService;
@Resource @Resource
private TestCaseMapper testCaseMapper; private TestCaseMapper testCaseMapper;
@Resource
private TestCaseService testCaseService;
public List<LoadTestDTO> list(QueryTestPlanRequest request) { public List<LoadTestDTO> list(QueryTestPlanRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders())); request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
@ -82,18 +85,7 @@ public class PerformanceTestService {
public void delete(DeleteTestPlanRequest request) { public void delete(DeleteTestPlanRequest request) {
String testId = request.getId(); String testId = request.getId();
// 是否关联测试用例 testCaseService.checkIsRelateTest(testId);
TestCaseExample testCaseExample = new TestCaseExample();
testCaseExample.createCriteria().andTestIdEqualTo(testId);
List<TestCase> testCases = testCaseMapper.selectByExample(testCaseExample);
if (testCases.size() > 0) {
String caseName = "";
for (int i = 0; i < testCases.size(); i++) {
caseName = caseName + testCases.get(i).getName() + ",";
}
caseName = caseName.substring(0, caseName.length() - 1);
MSException.throwException(Translator.get("related_case_del_fail_prefix") + caseName + Translator.get("related_case_del_fail_suffix"));
}
LoadTestReportExample loadTestReportExample = new LoadTestReportExample(); LoadTestReportExample loadTestReportExample = new LoadTestReportExample();
loadTestReportExample.createCriteria().andTestIdEqualTo(testId); loadTestReportExample.createCriteria().andTestIdEqualTo(testId);

View File

@ -2,6 +2,7 @@ package io.metersphere.security;
import io.metersphere.base.domain.Role; import io.metersphere.base.domain.Role;
import io.metersphere.commons.constants.UserSource;
import io.metersphere.commons.user.SessionUser; import io.metersphere.commons.user.SessionUser;
import io.metersphere.commons.utils.SessionUtils; import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.dto.UserDTO; import io.metersphere.dto.UserDTO;
@ -19,6 +20,8 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -64,8 +67,36 @@ public class ShiroDBRealm extends AuthorizingRealm {
@Override @Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String login = (String) SecurityUtils.getSubject().getSession().getAttribute("authenticate");
String userId = token.getUsername(); String userId = token.getUsername();
String password = String.valueOf(token.getPassword()); String password = String.valueOf(token.getPassword());
if (StringUtils.equals("local", runMode)) {
UserDTO user = getUserWithOutAuthenticate(userId);
userId = user.getId();
SessionUser sessionUser = SessionUser.fromUser(user);
SessionUtils.putUser(sessionUser);
return new SimpleAuthenticationInfo(userId, password, getName());
}
if (StringUtils.equals(login, UserSource.LOCAL.name())) {
return loginLocalMode(userId, password);
}
if (StringUtils.equals(login, UserSource.LDAP.name())) {
return loginLdapMode(userId, password);
}
UserDTO user = getUserWithOutAuthenticate(userId);
userId = user.getId();
SessionUser sessionUser = SessionUser.fromUser(user);
SessionUtils.putUser(sessionUser);
return new SimpleAuthenticationInfo(userId, password, getName());
}
private UserDTO getUserWithOutAuthenticate(String userId) {
UserDTO user = userService.getUserDTO(userId); UserDTO user = userService.getUserDTO(userId);
String msg; String msg;
if (user == null) { if (user == null) {
@ -75,29 +106,40 @@ public class ShiroDBRealm extends AuthorizingRealm {
logger.warn(msg); logger.warn(msg);
throw new UnknownAccountException(Translator.get("user_not_exist") + userId); throw new UnknownAccountException(Translator.get("user_not_exist") + userId);
} }
}
return user;
}
private AuthenticationInfo loginLdapMode(String userId, String password) {
//
UserDTO user = userService.getLoginUser(userId, Arrays.asList(UserSource.LDAP.name(), UserSource.LOCAL.name()));
String msg;
if (user == null) {
msg = "The user does not exist: " + userId;
logger.warn(msg);
throw new UnknownAccountException(Translator.get("user_not_exist") + userId);
}
userId = user.getId();
SessionUser sessionUser = SessionUser.fromUser(user);
SessionUtils.putUser(sessionUser);
return new SimpleAuthenticationInfo(userId, password, getName());
}
private AuthenticationInfo loginLocalMode(String userId, String password) {
UserDTO user = userService.getLoginUser(userId, Collections.singletonList(UserSource.LOCAL.name()));
String msg;
if (user == null) {
user = userService.getLoginUserByEmail(userId, UserSource.LOCAL.name());
if (user == null) {
msg = "The user does not exist: " + userId;
logger.warn(msg);
throw new UnknownAccountException(Translator.get("user_not_exist") + userId);
}
userId = user.getId(); userId = user.getId();
} }
// local test
if (StringUtils.equals("local", runMode)) {
SessionUser sessionUser = SessionUser.fromUser(user);
SessionUtils.putUser(sessionUser);
return new SimpleAuthenticationInfo(userId, password, getName());
}
// apikey 校验不验证密码
if (ApiKeySessionHandler.random.equalsIgnoreCase(password)) {
SessionUser sessionUser = SessionUser.fromUser(user);
SessionUtils.putUser(sessionUser);
return new SimpleAuthenticationInfo(userId, password, getName());
}
String login = (String) SecurityUtils.getSubject().getSession().getAttribute("authenticate");
if (StringUtils.equals(login, "ldap")) {
SessionUser sessionUser = SessionUser.fromUser(user);
SessionUtils.putUser(sessionUser);
return new SimpleAuthenticationInfo(userId, password, getName());
}
// 密码验证 // 密码验证
if (!userService.checkUserPassword(userId, password)) { if (!userService.checkUserPassword(userId, password)) {
throw new IncorrectCredentialsException(Translator.get("password_is_incorrect")); throw new IncorrectCredentialsException(Translator.get("password_is_incorrect"));

View File

@ -5,6 +5,7 @@ import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtUserMapper; import io.metersphere.base.mapper.ext.ExtUserMapper;
import io.metersphere.base.mapper.ext.ExtUserRoleMapper; import io.metersphere.base.mapper.ext.ExtUserRoleMapper;
import io.metersphere.commons.constants.RoleConstants; import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.commons.constants.UserSource;
import io.metersphere.commons.constants.UserStatus; import io.metersphere.commons.constants.UserStatus;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.user.SessionUser; import io.metersphere.commons.user.SessionUser;
@ -137,16 +138,29 @@ public class UserService {
user.setUpdateTime(System.currentTimeMillis()); user.setUpdateTime(System.currentTimeMillis());
// 默认1:启用状态 // 默认1:启用状态
user.setStatus(UserStatus.NORMAL); user.setStatus(UserStatus.NORMAL);
user.setSource(UserSource.LOCAL.name());
// 密码使用 MD5 // 密码使用 MD5
user.setPassword(CodingUtil.md5(user.getPassword())); user.setPassword(CodingUtil.md5(user.getPassword()));
checkEmailIsExist(user.getEmail());
userMapper.insertSelective(user);
}
public void addLdapUser(User user) {
user.setCreateTime(System.currentTimeMillis());
user.setUpdateTime(System.currentTimeMillis());
user.setStatus(UserStatus.NORMAL);
checkEmailIsExist(user.getEmail());
userMapper.insertSelective(user);
}
private void checkEmailIsExist(String email) {
UserExample userExample = new UserExample(); UserExample userExample = new UserExample();
UserExample.Criteria criteria = userExample.createCriteria(); UserExample.Criteria criteria = userExample.createCriteria();
criteria.andEmailEqualTo(user.getEmail()); criteria.andEmailEqualTo(email);
List<User> userList = userMapper.selectByExample(userExample); List<User> userList = userMapper.selectByExample(userExample);
if (!CollectionUtils.isEmpty(userList)) { if (!CollectionUtils.isEmpty(userList)) {
MSException.throwException(Translator.get("user_email_already_exists")); MSException.throwException(Translator.get("user_email_already_exists"));
} }
userMapper.insertSelective(user);
} }
public UserDTO getUserDTO(String userId) { public UserDTO getUserDTO(String userId) {
@ -166,6 +180,15 @@ public class UserService {
return userDTO; return userDTO;
} }
public UserDTO getLoginUser(String userId, List<String> list) {
UserExample example = new UserExample();
example.createCriteria().andIdEqualTo(userId).andSourceIn(list);
if (userMapper.countByExample(example) == 0) {
return null;
}
return getUserDTO(userId);
}
public UserDTO getUserDTOByEmail(String email) { public UserDTO getUserDTOByEmail(String email) {
UserExample example = new UserExample(); UserExample example = new UserExample();
example.createCriteria().andEmailEqualTo(email); example.createCriteria().andEmailEqualTo(email);
@ -176,6 +199,16 @@ public class UserService {
return getUserDTO(users.get(0).getId()); return getUserDTO(users.get(0).getId());
} }
public UserDTO getLoginUserByEmail(String email, String source) {
UserExample example = new UserExample();
example.createCriteria().andEmailEqualTo(email).andSourceEqualTo(source);
List<User> users = userMapper.selectByExample(example);
if (users == null || users.size() <= 0) {
return null;
}
return getUserDTO(users.get(0).getId());
}
public UserRoleDTO getUserRole(String userId) { public UserRoleDTO getUserRole(String userId) {
UserRoleDTO userRoleDTO = new UserRoleDTO(); UserRoleDTO userRoleDTO = new UserRoleDTO();
// //
@ -473,11 +506,15 @@ public class UserService {
} }
public ResultHolder login(LoginRequest request) { public ResultHolder login(LoginRequest request) {
String login = (String) SecurityUtils.getSubject().getSession().getAttribute("authenticate");
String msg; String msg;
String username = StringUtils.trim(request.getUsername()); String username = StringUtils.trim(request.getUsername());
String password = StringUtils.trim(request.getPassword()); String password = "";
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) { if (!StringUtils.equals(login, UserSource.LDAP.name())) {
return ResultHolder.error("user or password can't be null"); password = StringUtils.trim(request.getPassword());
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
return ResultHolder.error("user or password can't be null");
}
} }
UsernamePasswordToken token = new UsernamePasswordToken(username, password); UsernamePasswordToken token = new UsernamePasswordToken(username, password);
@ -518,6 +555,7 @@ public class UserService {
} catch (UnauthorizedException e) { } catch (UnauthorizedException e) {
msg = Translator.get("not_authorized") + e.getMessage(); msg = Translator.get("not_authorized") + e.getMessage();
} }
return ResultHolder.error(msg); MSException.throwException(msg);
return null;
} }
} }

View File

@ -109,6 +109,11 @@ public class TestCaseController {
public void testCaseTemplateExport(HttpServletResponse response){ public void testCaseTemplateExport(HttpServletResponse response){
testCaseService.testCaseTemplateExport(response); testCaseService.testCaseTemplateExport(response);
} }
@GetMapping("/export/testCase/{testCaseIds}")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public void testCaseExport(HttpServletResponse response,QueryTestCaseRequest request){
testCaseService.testCaseExport(response,request);
}
@PostMapping("/batch/edit") @PostMapping("/batch/edit")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR) @RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)

View File

@ -6,8 +6,10 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
public class TestCaseDTO extends TestCaseWithBLOBs{ public class TestCaseDTO extends TestCaseWithBLOBs {
private String maintainerName; private String maintainerName;
private String apiName;
private String performName;
} }

View File

@ -12,8 +12,12 @@ import java.util.Map;
@Setter @Setter
public class QueryTestCaseRequest extends TestCase { public class QueryTestCaseRequest extends TestCase {
private String name;
private List<String> nodeIds; private List<String> nodeIds;
private List<String> testCaseIds;
private List<OrderRequest> orders; private List<OrderRequest> orders;
private Map<String, List<String>> filters; private Map<String, List<String>> filters;
@ -21,4 +25,6 @@ public class QueryTestCaseRequest extends TestCase {
private String planId; private String planId;
private String workspaceId; private String workspaceId;
private Map<String, Object> combine;
} }

View File

@ -13,4 +13,5 @@ public class QueryTestPlanRequest extends TestPlanRequest {
private String workspaceId; private String workspaceId;
private List<OrderRequest> orders; private List<OrderRequest> orders;
private Map<String, List<String>> filters; private Map<String, List<String>> filters;
private Map<String, Object> combine;
} }

View File

@ -2,6 +2,8 @@ package io.metersphere.track.service;
import com.alibaba.excel.EasyExcelFactory; import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*; import io.metersphere.base.mapper.*;
@ -101,7 +103,7 @@ public class TestCaseService {
return testCaseMapper.updateByPrimaryKeySelective(testCase); return testCaseMapper.updateByPrimaryKeySelective(testCase);
} }
private void checkTestCaseExist (TestCaseWithBLOBs testCase) { private void checkTestCaseExist(TestCaseWithBLOBs testCase) {
if (testCase.getName() != null) { if (testCase.getName() != null) {
TestCaseExample example = new TestCaseExample(); TestCaseExample example = new TestCaseExample();
example.createCriteria() example.createCriteria()
@ -154,7 +156,7 @@ public class TestCaseService {
List<TestCase> testCaseNames = extTestCaseMapper.getTestCaseNames(request); List<TestCase> testCaseNames = extTestCaseMapper.getTestCaseNames(request);
if ( StringUtils.isNotBlank(request.getPlanId()) ) { if (StringUtils.isNotBlank(request.getPlanId())) {
TestPlanTestCaseExample testPlanTestCaseExample = new TestPlanTestCaseExample(); TestPlanTestCaseExample testPlanTestCaseExample = new TestPlanTestCaseExample();
testPlanTestCaseExample.createCriteria().andPlanIdEqualTo(request.getPlanId()); testPlanTestCaseExample.createCriteria().andPlanIdEqualTo(request.getPlanId());
List<String> relevanceIds = testPlanTestCaseMapper.selectByExample(testPlanTestCaseExample).stream() List<String> relevanceIds = testPlanTestCaseMapper.selectByExample(testPlanTestCaseExample).stream()
@ -284,9 +286,9 @@ public class TestCaseService {
data.setName(Translator.get("test_case") + i); data.setName(Translator.get("test_case") + i);
path.append("/" + Translator.get("module") + i); path.append("/" + Translator.get("module") + i);
data.setNodePath(path.toString()); data.setNodePath(path.toString());
data.setPriority("P" + i%4); data.setPriority("P" + i % 4);
data.setType(types.get(i%3)); data.setType(types.get(i % 3));
data.setMethod(methods.get(i%2)); data.setMethod(methods.get(i % 2));
data.setPrerequisite(Translator.get("preconditions_optional")); data.setPrerequisite(Translator.get("preconditions_optional"));
data.setStepDesc("1. " + Translator.get("step_tip_separate") + data.setStepDesc("1. " + Translator.get("step_tip_separate") +
"\n2. " + Translator.get("step_tip_order") + "\n3. " + Translator.get("step_tip_optional")); "\n2. " + Translator.get("step_tip_order") + "\n3. " + Translator.get("step_tip_optional"));
@ -309,6 +311,75 @@ public class TestCaseService {
return list; return list;
} }
public void testCaseExport(HttpServletResponse response, QueryTestCaseRequest request) {
EasyExcelExporter easyExcelExporter = null;
try {
easyExcelExporter = new EasyExcelExporter(TestCaseExcelData.class);
easyExcelExporter.export(response, generateTestCaseExcel(request),
Translator.get("test_case_import_template_name"), Translator.get("test_case_import_template_sheet"));
} catch (Exception e) {
MSException.throwException(e);
} finally {
easyExcelExporter.close();
}
}
private List<TestCaseExcelData> generateTestCaseExcel(QueryTestCaseRequest request) {
List<TestCaseDTO> TestCaseList = extTestCaseMapper.listBytestCaseIds(request);
List<TestCaseExcelData> list = new ArrayList<>();
SessionUser user = SessionUtils.getUser();
StringBuilder step = new StringBuilder("");
StringBuilder result = new StringBuilder("");
TestCaseList.forEach(t -> {
TestCaseExcelData data = new TestCaseExcelData();
data.setName(t.getName());
data.setNodePath(t.getNodePath());
data.setPriority(t.getPriority());
data.setType(t.getType());
data.setMethod(t.getMethod());
data.setPrerequisite(t.getPrerequisite());
if (t.getMethod().equals("manual")) {
String steps = t.getSteps();
JSONArray jsonArray = JSON.parseArray(steps);
for (int j = 0; j < jsonArray.size(); j++) {
int num = j + 1;
step.append(num + ":" + jsonArray.getJSONObject(j).getString("desc") + "\n");
result.append(num + ":" + jsonArray.getJSONObject(j).getString("result") + "\n");
}
data.setStepDesc(step.toString());
data.setStepResult(result.toString());
step.setLength(0);
result.setLength(0);
data.setRemark(t.getRemark());
} else if (t.getMethod().equals("auto") && t.getType().equals("api")) {
data.setStepDesc("");
data.setStepResult("");
data.setRemark(t.getApiName());
} else if (t.getMethod().equals("auto") && t.getType().equals("performance")) {
data.setStepDesc("");
data.setStepResult("");
data.setRemark(t.getPerformName());
}
data.setMaintainer(user.getId());
list.add(data);
});
list.add(new TestCaseExcelData());
TestCaseExcelData explain = new TestCaseExcelData();
explain.setName(Translator.get("do_not_modify_header_order"));
explain.setNodePath(Translator.get("module_created_automatically"));
explain.setType(Translator.get("options") + "functional、performance、api");
explain.setMethod(Translator.get("options") + "manual、auto");
explain.setPriority(Translator.get("options") + "P0、P1、P2、P3");
explain.setMaintainer(Translator.get("please_input_workspace_member"));
list.add(explain);
return list;
}
public void editTestCaseBath(TestCaseBatchRequest request) { public void editTestCaseBath(TestCaseBatchRequest request) {
TestCaseExample testCaseExample = new TestCaseExample(); TestCaseExample testCaseExample = new TestCaseExample();
testCaseExample.createCriteria().andIdIn(request.getIds()); testCaseExample.createCriteria().andIdIn(request.getIds());
@ -339,4 +410,23 @@ public class TestCaseService {
example.createCriteria().andProjectIdEqualTo(projectId); example.createCriteria().andProjectIdEqualTo(projectId);
testCaseMapper.deleteByExample(example); testCaseMapper.deleteByExample(example);
} }
/**
* 是否关联测试
*
* @param testId
*/
public void checkIsRelateTest(String testId) {
TestCaseExample testCaseExample = new TestCaseExample();
testCaseExample.createCriteria().andTestIdEqualTo(testId);
List<TestCase> testCases = testCaseMapper.selectByExample(testCaseExample);
StringBuilder caseName = new StringBuilder();
if (testCases.size() > 0) {
for (TestCase testCase : testCases) {
caseName = caseName.append(testCase.getName()).append(",");
}
String str = caseName.toString().substring(0, caseName.length() - 1);
MSException.throwException(Translator.get("related_case_del_fail_prefix") + " " + str + " " + Translator.get("related_case_del_fail_suffix"));
}
}
} }

View File

@ -0,0 +1,3 @@
alter table user add source varchar(50) null;
update user set source = 'LOCAL' where source is null;

View File

@ -45,6 +45,7 @@ duplicate_node_ip=Duplicate IPs
max_thread_insufficient=The number of concurrent users exceeds max_thread_insufficient=The number of concurrent users exceeds
related_case_del_fail_prefix=Connected to related_case_del_fail_prefix=Connected to
related_case_del_fail_suffix=TestCase, please disassociate first related_case_del_fail_suffix=TestCase, please disassociate first
jmx_content_valid=JMX content is invalid
#workspace #workspace
workspace_name_is_null=Workspace name cannot be null workspace_name_is_null=Workspace name cannot be null
workspace_name_already_exists=The workspace name already exists workspace_name_already_exists=The workspace name already exists

View File

@ -45,6 +45,7 @@ duplicate_node_ip=节点 IP 重复
max_thread_insufficient=并发用户数超额 max_thread_insufficient=并发用户数超额
related_case_del_fail_prefix=已关联到 related_case_del_fail_prefix=已关联到
related_case_del_fail_suffix=测试用例,请先解除关联 related_case_del_fail_suffix=测试用例,请先解除关联
jmx_content_valid=JMX 内容无效,请检查
#workspace #workspace
workspace_name_is_null=工作空间名不能为空 workspace_name_is_null=工作空间名不能为空
workspace_name_already_exists=工作空间名已存在 workspace_name_already_exists=工作空间名已存在

View File

@ -45,6 +45,7 @@ duplicate_node_ip=節點 IP 重復
max_thread_insufficient=並發用戶數超額 max_thread_insufficient=並發用戶數超額
related_case_del_fail_prefix=已關聯到 related_case_del_fail_prefix=已關聯到
related_case_del_fail_suffix=測試用例,請先解除關聯 related_case_del_fail_suffix=測試用例,請先解除關聯
jmx_content_valid=JMX 內容無效,請檢查
#workspace #workspace
workspace_name_is_null=工作空間名不能為空 workspace_name_is_null=工作空間名不能為空
workspace_name_already_exists=工作空間名已存在 workspace_name_already_exists=工作空間名已存在

View File

@ -147,7 +147,6 @@
<logger name="io.metersphere" additivity="false"> <logger name="io.metersphere" additivity="false">
<level value="${logger.level:INFO}" /> <level value="${logger.level:INFO}" />
<appender-ref ref="debugAsyncAppender" />
<appender-ref ref="infoAsyncAppender" /> <appender-ref ref="infoAsyncAppender" />
<appender-ref ref="warnAsyncAppender" /> <appender-ref ref="warnAsyncAppender" />
<appender-ref ref="errorAsyncAppender" /> <appender-ref ref="errorAsyncAppender" />

View File

@ -14,13 +14,13 @@
<el-table-column prop="testName" :label="$t('api_report.test_name')" width="200" show-overflow-tooltip/> <el-table-column prop="testName" :label="$t('api_report.test_name')" width="200" show-overflow-tooltip/>
<el-table-column prop="projectName" :label="$t('load_test.project_name')" width="150" show-overflow-tooltip/> <el-table-column prop="projectName" :label="$t('load_test.project_name')" width="150" show-overflow-tooltip/>
<el-table-column prop="userName" :label="$t('api_test.creator')" width="150" show-overflow-tooltip/> <el-table-column prop="userName" :label="$t('api_test.creator')" width="150" show-overflow-tooltip/>
<el-table-column width="250" :label="$t('commons.create_time')" sortable <el-table-column prop="createTime" width="250" :label="$t('commons.create_time')" sortable>
prop="createTime">
<template v-slot:default="scope"> <template v-slot:default="scope">
<span>{{ scope.row.createTime | timestampFormatDate }}</span> <span>{{ scope.row.createTime | timestampFormatDate }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="triggerMode" width="150" :label="'触发方式'" column-key="triggerMode" :filters="triggerFilters"> <el-table-column prop="triggerMode" width="150" :label="$t('commons.trigger_mode.name')"
column-key="triggerMode" :filters="triggerFilters">
<template v-slot:default="scope"> <template v-slot:default="scope">
<report-trigger-mode-item :trigger-mode="scope.row.triggerMode"/> <report-trigger-mode-item :trigger-mode="scope.row.triggerMode"/>
</template> </template>
@ -34,8 +34,10 @@
</el-table-column> </el-table-column>
<el-table-column width="150" :label="$t('commons.operating')"> <el-table-column width="150" :label="$t('commons.operating')">
<template v-slot:default="scope"> <template v-slot:default="scope">
<ms-table-operator-button :tip="$t('api_report.detail')" icon="el-icon-s-data" @exec="handleView(scope.row)" type="primary"/> <ms-table-operator-button :tip="$t('api_report.detail')" icon="el-icon-s-data"
<ms-table-operator-button :is-tester-permission="true" :tip="$t('api_report.delete')" icon="el-icon-delete" @exec="handleDelete(scope.row)" type="danger"/> @exec="handleView(scope.row)" type="primary"/>
<ms-table-operator-button :is-tester-permission="true" :tip="$t('api_report.delete')"
icon="el-icon-delete" @exec="handleDelete(scope.row)" type="danger"/>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -55,16 +57,20 @@
import {_filter, _sort} from "../../../../common/js/utils"; import {_filter, _sort} from "../../../../common/js/utils";
import MsTableOperatorButton from "../../common/components/MsTableOperatorButton"; import MsTableOperatorButton from "../../common/components/MsTableOperatorButton";
import ReportTriggerModeItem from "../../common/tableItem/ReportTriggerModeItem"; import ReportTriggerModeItem from "../../common/tableItem/ReportTriggerModeItem";
import {REPORT_CONFIGS} from "../../common/components/search/search-components";
export default { export default {
components: { components: {
ReportTriggerModeItem, ReportTriggerModeItem,
MsTableOperatorButton, MsTableOperatorButton,
MsApiReportStatus, MsMainContainer, MsContainer, MsTableHeader, MsTablePagination}, MsApiReportStatus, MsMainContainer, MsContainer, MsTableHeader, MsTablePagination
},
data() { data() {
return { return {
result: {}, result: {},
condition: {}, condition: {
components: REPORT_CONFIGS
},
tableData: [], tableData: [],
multipleSelection: [], multipleSelection: [],
currentPage: 1, currentPage: 1,
@ -80,9 +86,9 @@
{text: 'Error', value: 'Error'} {text: 'Error', value: 'Error'}
], ],
triggerFilters: [ triggerFilters: [
{text: '手动', value: 'MANUAL'}, {text: this.$t('commons.trigger_mode.manual'), value: 'MANUAL'},
{text: '定时任务', value: 'SCHEDULE'}, {text: this.$t('commons.trigger_mode.schedule'), value: 'SCHEDULE'},
{text: 'API', value: 'API'} {text: this.$t('commons.trigger_mode.api'), value: 'API'}
], ],
} }
}, },
@ -92,13 +98,15 @@
}, },
methods: { methods: {
search() { search(combine) {
// combine
let condition = combine ? {combine: combine} : this.condition;
if (this.testId !== 'all') { if (this.testId !== 'all') {
this.condition.testId = this.testId; condition.testId = this.testId;
} }
let url = "/api/report/list/" + this.currentPage + "/" + this.pageSize; let url = "/api/report/list/" + this.currentPage + "/" + this.pageSize;
this.result = this.$post(url, this.condition, response => { this.result = this.$post(url, condition, response => {
let data = response.data; let data = response.data;
this.total = data.itemCount; this.total = data.itemCount;
this.tableData = data.listObject; this.tableData = data.listObject;

View File

@ -54,6 +54,7 @@
import MsApiTestStatus from "./ApiTestStatus"; import MsApiTestStatus from "./ApiTestStatus";
import MsTableOperators from "../../common/components/MsTableOperators"; import MsTableOperators from "../../common/components/MsTableOperators";
import {_filter, _sort} from "../../../../common/js/utils"; import {_filter, _sort} from "../../../../common/js/utils";
import {TEST_CONFIGS} from "../../common/components/search/search-components";
export default { export default {
components: { components: {
@ -63,7 +64,9 @@
data() { data() {
return { return {
result: {}, result: {},
condition: {}, condition: {
components: TEST_CONFIGS
},
projectId: null, projectId: null,
tableData: [], tableData: [],
multipleSelection: [], multipleSelection: [],
@ -102,15 +105,15 @@
create() { create() {
this.$router.push('/api/test/create'); this.$router.push('/api/test/create');
}, },
search() { search(combine) {
// combine
let condition = combine ? {combine: combine} : this.condition;
if (this.projectId !== 'all') { if (this.projectId !== 'all') {
this.condition.projectId = this.projectId; condition.projectId = this.projectId;
} }
let url = "/api/list/" + this.currentPage + "/" + this.pageSize let url = "/api/list/" + this.currentPage + "/" + this.pageSize;
this.result = this.$post(url, this.condition, response => { this.result = this.$post(url, condition, response => {
let data = response.data; let data = response.data;
this.total = data.itemCount; this.total = data.itemCount;
this.tableData = data.listObject; this.tableData = data.listObject;

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<el-row :gutter="10" type="flex" justify="space-between" align="middle"> <el-row :gutter="10" type="flex" justify="space-between" align="middle">
<el-col v-if="extractType == 'Regex'" :span="5"> <el-col v-if="extractType === 'Regex'" :span="5">
<el-select :disabled="isReadOnly" class="extract-item" v-model="common.useHeaders" :placeholder="$t('api_test.request.assertions.select_subject')" size="small"> <el-select :disabled="isReadOnly" class="extract-item" v-model="common.useHeaders" :placeholder="$t('api_test.request.assertions.select_subject')" size="small">
<el-option v-for="item in useHeadersOption" :key="item.value" :label="item.label" :value="item.value"/> <el-option v-for="item in useHeadersOption" :key="item.value" :label="item.label" :value="item.value"/>
</el-select> </el-select>

View File

@ -3,16 +3,18 @@
<div> <div>
<el-row class="table-title" type="flex" justify="space-between" align="middle"> <el-row class="table-title" type="flex" justify="space-between" align="middle">
<slot name="title"> <slot name="title">
{{title}} {{title}}
</slot> </slot>
</el-row> </el-row>
<el-row type="flex" justify="space-between" align="middle"> <el-row type="flex" justify="space-between" align="middle">
<span class="operate-button"> <span class="operate-button">
<ms-table-button :is-tester-permission="isTesterPermission" v-if="showCreate" icon="el-icon-circle-plus-outline" :content="createTip" @click="create"/> <ms-table-button :is-tester-permission="isTesterPermission" v-if="showCreate" icon="el-icon-circle-plus-outline"
:content="createTip" @click="create"/>
<slot name="button"></slot> <slot name="button"></slot>
</span> </span>
<span> <span>
<ms-table-search-bar :condition.sync="condition" @change="search"/> <ms-table-search-bar :condition.sync="condition" @change="search" class="search-bar"/>
<ms-table-adv-search-bar :condition="condition" @search="search" v-if="isCombine"/>
</span> </span>
</el-row> </el-row>
</div> </div>
@ -22,45 +24,51 @@
<script> <script>
import MsTableSearchBar from './MsTableSearchBar'; import MsTableSearchBar from './MsTableSearchBar';
import MsTableButton from './MsTableButton'; import MsTableButton from './MsTableButton';
import MsTableAdvSearchBar from "./search/MsTableAdvSearchBar";
export default { export default {
name: "MsTableHeader", name: "MsTableHeader",
components: {MsTableSearchBar, MsTableButton}, components: {MsTableAdvSearchBar, MsTableSearchBar, MsTableButton},
props: { props: {
title: { title: {
type: String, type: String,
default() { default() {
return this.$t('commons.name'); return this.$t('commons.name');
}
},
showCreate: {
type: Boolean,
default: true
},
condition: {
type: Object
},
createTip: {
type: String,
default() {
return this.$t('commons.create');
}
},
isTesterPermission: {
type: Boolean,
default: false
} }
}, },
methods: { showCreate: {
search() { type: Boolean,
this.$emit('update:condition', this.condition); default: true
this.$emit('search'); },
}, condition: {
create() { type: Object
this.$emit('create'); },
createTip: {
type: String,
default() {
return this.$t('commons.create');
} }
},
isTesterPermission: {
type: Boolean,
default: false
}
},
methods: {
search(value) {
this.$emit('update:condition', this.condition);
this.$emit('search', value);
},
create() {
this.$emit('create');
}
},
computed: {
isCombine() {
return this.condition.components !== undefined && this.condition.components.length > 0;
} }
} }
}
</script> </script>
<style> <style>
@ -79,4 +87,8 @@
margin-bottom: -5px; margin-bottom: -5px;
} }
.search-bar {
width: 200px
}
</style> </style>

View File

@ -0,0 +1,169 @@
<template>
<span class="adv-search-bar">
<el-link type="primary" @click="open">{{$t('commons.adv_search.title')}}</el-link>
<el-dialog :title="$t('commons.adv_search.combine')" :visible.sync="visible" custom-class="adv-dialog"
:append-to-body="true">
<div>
<!-- 如果有需求再加上-->
<!-- <div class="search-label">{{$t('commons.adv_search.combine')}}: </div>-->
<!-- <el-select v-model="logic" :placeholder="$t('commons.please_select')" size="small" class="search-combine">-->
<!-- <el-option v-for="o in options" :key="o.value" :label="o.label" :value="o.value"/>-->
<!-- </el-select>-->
<div class="search-items">
<component class="search-item" v-for="(component, index) in config.components" :key="index"
:is="component.name" :component="component"/>
</div>
</div>
<template v-slot:footer>
<div class="dialog-footer">
<el-button @click="reset">{{$t('commons.adv_search.reset')}}</el-button>
<el-button type="primary" @click="search">{{$t('commons.adv_search.search')}}</el-button>
</div>
</template>
</el-dialog>
</span>
</template>
<script>
import components from "./search-components";
import _ from "lodash";
export default {
components: {...components},
name: "MsTableAdvSearchBar",
props: {
condition: Object,
},
data() {
return {
visible: false,
config: this.init(),
options: [{
label: this.$t("commons.adv_search.and"),
value: "and"
}, {
label: this.$t("commons.adv_search.or"),
value: "or"
}],
logic: this.condition.logic || "and"
}
},
methods: {
init() { //
let config = _.cloneDeep(this.condition);
config.components.forEach(component => {
let operator = component.operator.value;
component.operator.value = operator === undefined ? component.operator.options[0].value : operator;
})
return config;
},
search() {
let condition = {
// logic: this.logic //
}
this.config.components.forEach(component => {
let operator = component.operator.value;
let value = component.value;
if (Array.isArray(component.value)) {
if (component.value.length > 0) {
condition[component.key] = {
operator: operator,
value: value
}
}
} else {
if (component.value !== undefined && component.value !== null && component.value !== "") {
condition[component.key] = {
operator: operator,
value: value
}
}
}
});
this.$emit('search', condition);
this.visible = false;
},
reset() {
let source = this.condition.components;
this.config.components.forEach((component, index) => {
let operator = source[index].operator.value;
component.operator.value = operator === undefined ? component.operator.options[0].value : operator;
component.value = source[index].value;
})
},
open() {
this.visible = true;
}
}
}
</script>
<style>
@media only screen and (min-width: 1870px) {
.el-dialog.adv-dialog {
width: 70%;
}
}
@media only screen and (min-width: 1650px) and (max-width: 1869px) {
.el-dialog.adv-dialog {
width: 80%;
}
}
@media only screen and (min-width: 1470px) and (max-width: 1649px) {
.el-dialog.adv-dialog {
width: 90%;
}
}
@media only screen and (max-width: 1469px) {
.el-dialog.adv-dialog {
width: 70%;
min-width: 695px;
}
}
</style>
<style scoped>
.adv-search-bar {
margin-left: 5px;
}
.dialog-footer {
text-align: center;
}
.search-label {
display: inline-block;
width: 80px;
box-sizing: border-box;
padding-left: 5px;
}
.search-combine {
width: 160px;
}
.search-items {
width: 100%;
}
@media only screen and (max-width: 1469px) {
.search-item {
width: 100%;
}
}
@media only screen and (min-width: 1470px) {
.search-item {
width: 50%;
}
}
.search-item {
display: inline-block;
margin-top: 10px;
}
</style>

View File

@ -0,0 +1,67 @@
<template>
<div>
<div class="search-label">{{$t(component.label)}}</div>
<el-select class="search-operator" v-model="component.operator.value" :placeholder="$t('commons.please_select')"
size="small"
@change="change" @input="input" v-bind="component.operator.props">
<el-option v-for="o in operators" :key="o.value" :label="$t(o.label)" :value="o.value"/>
</el-select>
<div class="search-content" v-if="showContent">
<slot v-bind:component="component"></slot>
</div>
</div>
</template>
<script>
export default {
name: "MsTableSearchComponent",
props: ['component'],
data() {
return {
operators: this.component.operator.options || [],
}
},
methods: {
change(value) {
if (this.component.operator.change) {
this.component.operator.change(this.component, value)
}
this.$emit('change', value);
},
input(value) {
this.$emit('input', value);
}
},
computed: {
showContent() {
if (this.component.isShow) {
return this.component.isShow(this.component.operator.value);
}
return true;
}
}
}
</script>
<style scoped>
.search-label {
display: inline-block;
width: 120px;
box-sizing: border-box;
padding-left: 5px;
}
.search-operator {
display: inline-block;
width: 120px;
}
.search-content {
display: inline-block;
padding: 0 5px 0 10px;
width: calc(100% - 240px);
box-sizing: border-box;
}
</style>

View File

@ -0,0 +1,52 @@
<template>
<ms-table-search-component v-model="component.operator.value" :component="component">
<template v-slot="scope">
<el-date-picker
v-model="scope.component.value" v-bind="scope.component.props"
:placeholder="$t('commons.date.select_date')" size="small"
:type="type" :key="type" value-format="timestamp"
:range-separator="$t('commons.date.range_separator')"
:start-placeholder="$t('commons.date.start_date')"
:end-placeholder="$t('commons.date.end_date')">
</el-date-picker>
</template>
</ms-table-search-component>
</template>
<script>
import MsTableSearchComponent from "./MsTableSearchComponet";
import {OPERATORS} from "./search-components"
export default {
name: "MsTableSearchDatePicker",
components: {MsTableSearchComponent},
props: ['component'],
methods: {
change(value) {
if (value === OPERATORS.BETWEEN.value) {
if (!Array.isArray(this.component.value)) {
this.component.value = [];
}
} else {
if (Array.isArray(this.component.value)) {
this.component.value = "";
}
}
}
},
computed: {
type() {
if (this.component.operator.value === OPERATORS.BETWEEN.value) {
return "daterange";
} else {
return "date";
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,51 @@
<template>
<ms-table-search-component v-model="component.operator.value" :component="component" @change="change">
<template v-slot="scope">
<el-date-picker v-model="scope.component.value" v-bind="scope.component.props"
:placeholder="$t('commons.date.select_date_time')" size="small"
:type="type" :key="type" value-format="timestamp"
:range-separator="$t('commons.date.range_separator')"
:start-placeholder="$t('commons.date.start_date_time')"
:end-placeholder="$t('commons.date.end_date_time')">
</el-date-picker>
</template>
</ms-table-search-component>
</template>
<script>
import MsTableSearchComponent from "./MsTableSearchComponet";
import {OPERATORS} from "./search-components"
export default {
name: "MsTableSearchDateTimePicker",
components: {MsTableSearchComponent},
props: ['component'],
methods: {
change(value) {
if (value === OPERATORS.BETWEEN.value) {
if (!Array.isArray(this.component.value)) {
this.component.value = [];
}
} else {
if (Array.isArray(this.component.value)) {
this.component.value = "";
}
}
}
},
computed: {
type() {
if (this.component.operator.value === OPERATORS.BETWEEN.value) {
return "datetimerange";
} else {
return "datetime";
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,31 @@
<template>
<ms-table-search-component v-model="component.operator.value" :component="component">
<template v-slot="scope">
<el-input v-model="scope.component.value" v-bind="props"
:placeholder="$t('commons.input_content')" size="small"/>
</template>
</ms-table-search-component>
</template>
<script>
import MsTableSearchComponent from "./MsTableSearchComponet";
export default {
name: "MsTableSearchInput",
components: {MsTableSearchComponent},
props: ['component'],
data() {
return {
props: {
maxlength: "60",
showWordLimit: true,
...this.component.props
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,56 @@
<template>
<ms-table-search-component v-model="component.operator.value" :component="component">
<template v-slot="scope">
<el-select v-model="scope.component.value" :placeholder="$t('commons.please_select')" size="small"
filterable v-bind="scope.component.props" class="search-select">
<el-option v-for="op in options" :key="op.value" :label="label(op)" :value="op.value"></el-option>
</el-select>
</template>
</ms-table-search-component>
</template>
<script>
import MsTableSearchComponent from "./MsTableSearchComponet";
export default {
name: "MsTableSearchSelect",
components: {MsTableSearchComponent},
props: ['component'],
data() {
return {
options: !(this.component.options instanceof Array) ? [] : this.component.options || []
}
},
created() {
if (!(this.component.options instanceof Array) && this.component.options.url) {
this.$get(this.component.options.url, response => {
if (response.data) {
response.data.forEach(item => {
this.options.push({
label: item[this.component.options.labelKey],
value: item[this.component.options.valueKey]
})
})
}
})
}
},
computed: {
label() {
return op => {
if (this.component.options.showLabel) {
return this.component.options.showLabel(op);
}
return op.label.indexOf(".") !== -1 ? this.$t(op.label) : op.label;
}
}
}
}
</script>
<style scoped>
.search-select {
display: inline-block;
width: 100%;
}
</style>

View File

@ -0,0 +1,227 @@
import MsTableSearchInput from "./MsTableSearchInput";
import MsTableSearchDateTimePicker from "./MsTableSearchDateTimePicker";
import MsTableSearchDatePicker from "./MsTableSearchDatePicker";
import MsTableSearchSelect from "./MsTableSearchSelect";
export default {
MsTableSearchInput, MsTableSearchDatePicker, MsTableSearchDateTimePicker, MsTableSearchSelect
}
export const OPERATORS = {
LIKE: {
label: "commons.adv_search.operators.like",
value: "like"
},
NOT_LIKE: {
label: "commons.adv_search.operators.not_like",
value: "not like"
},
IN: {
label: "commons.adv_search.operators.in",
value: "in"
},
NOT_IN: {
label: "commons.adv_search.operators.not_in",
value: "not in"
},
GT: {
label: "commons.adv_search.operators.gt",
value: "gt"
},
GE: {
label: "commons.adv_search.operators.ge",
value: "ge"
},
LT: {
label: "commons.adv_search.operators.lt",
value: "lt"
},
LE: {
label: "commons.adv_search.operators.le",
value: "le"
},
EQ: {
label: "commons.adv_search.operators.equals",
value: "eq"
},
BETWEEN: {
label: "commons.adv_search.operators.between",
value: "between"
},
CURRENT_USER: {
label: "commons.adv_search.operators.current_user",
value: "current user"
},
}
export const NAME = {
key: "name", // 返回结果Map的key
name: 'MsTableSearchInput', // Vue控件名称
label: 'commons.name', // 显示名称
operator: { // 运算符设置
value: OPERATORS.LIKE.value, // 如果未设置value初始值则value初始值为options[0]
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE] // 运算符候选项
},
}
export const UPDATE_TIME = {
key: "updateTime",
name: 'MsTableSearchDateTimePicker',
label: 'commons.update_time',
operator: {
options: [OPERATORS.BETWEEN, OPERATORS.GT, OPERATORS.GE, OPERATORS.LT, OPERATORS.LE, OPERATORS.EQ]
},
}
export const PROJECT_NAME = {
key: "projectName",
name: 'MsTableSearchInput',
label: 'commons.adv_search.project',
operator: {
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE]
},
}
export const TEST_NAME = {
key: "testName",
name: 'MsTableSearchInput',
label: 'commons.adv_search.test',
operator: {
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE]
},
}
export const CREATE_TIME = {
key: "createTime",
name: 'MsTableSearchDateTimePicker',
label: 'commons.create_time',
operator: {
options: [OPERATORS.BETWEEN, OPERATORS.GT, OPERATORS.GE, OPERATORS.LT, OPERATORS.LE, OPERATORS.EQ]
},
}
export const STATUS = {
key: "status",
name: 'MsTableSearchSelect',
label: 'commons.status',
operator: {
options: [OPERATORS.IN, OPERATORS.NOT_IN]
},
options: [
{label: "Saved", value: "Saved"}, {label: "Starting", value: "Starting"},
{label: "Running", value: "Running"}, {label: "Reporting", value: "Reporting"},
{label: "Completed", value: "Completed"}, {label: "Error", value: "Error"}
],
props: { // 尾部控件的props一般为element ui控件的props
multiple: true
}
}
export const CREATOR = {
key: "creator",
name: 'MsTableSearchSelect',
label: 'api_test.creator',
operator: {
options: [OPERATORS.IN, OPERATORS.NOT_IN, OPERATORS.CURRENT_USER],
change: function (component, value) { // 运算符change事件
if (value === OPERATORS.CURRENT_USER.value) {
component.value = value;
}
}
},
options: { // 异步获取候选项
url: "/user/list",
labelKey: "name",
valueKey: "id",
showLabel: option => {
return option.label + "(" + option.value + ")";
}
},
props: {
multiple: true
},
isShow: operator => {
return operator !== OPERATORS.CURRENT_USER.value;
}
}
export const TRIGGER_MODE = {
key: "triggerMode",
name: 'MsTableSearchSelect',
label: 'commons.trigger_mode.name',
operator: {
options: [OPERATORS.IN, OPERATORS.NOT_IN]
},
options: [
{label: "commons.trigger_mode.manual", value: "MANUAL"},
{label: "commons.trigger_mode.schedule", value: "SCHEDULE"},
{label: "commons.trigger_mode.api", value: "API"}
],
props: {
multiple: true
}
}
export const PRIORITY = {
key: "priority",
name: 'MsTableSearchSelect',
label: "test_track.case.priority",
operator: {
options: [OPERATORS.IN, OPERATORS.NOT_IN]
},
options: [
{label: "P0", value: "P0"},
{label: "P1", value: "P1"},
{label: "P2", value: "P2"},
{label: "P3", value: "P3"},
],
props: {
multiple: true
}
}
export const TYPE = {
key: "type",
name: 'MsTableSearchSelect',
label: "test_track.case.type",
operator: {
options: [OPERATORS.IN, OPERATORS.NOT_IN]
},
options: [
{label: 'commons.functional', value: 'functional'},
{label: 'commons.performance', value: 'performance'},
{label: 'commons.api', value: 'api'}
],
props: {
multiple: true
}
}
export const METHOD = {
key: "method",
name: 'MsTableSearchSelect',
label: "test_track.case.method",
operator: {
options: [OPERATORS.IN, OPERATORS.NOT_IN]
},
options: [
{label: 'test_track.case.manual', value: 'manual'},
{label: 'test_track.case.auto', value: 'auto'}
],
props: {
multiple: true
}
}
export const MODULE = {
key: "module",
name: 'MsTableSearchInput',
label: "test_track.case.module",
operator: {
value: OPERATORS.LIKE.value, // 如果未设置value初始值则value初始值为options[0]
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE] // 运算符候选项
},
}
export const TEST_CONFIGS = [NAME, UPDATE_TIME, PROJECT_NAME, CREATE_TIME, STATUS, CREATOR];
export const REPORT_CONFIGS = [NAME, TEST_NAME, PROJECT_NAME, CREATE_TIME, STATUS, CREATOR, TRIGGER_MODE];
export const TEST_CASE_CONFIGS = [NAME, MODULE, PRIORITY, CREATE_TIME, TYPE, UPDATE_TIME, METHOD, CREATOR];

View File

@ -1,8 +1,8 @@
<template> <template>
<span> <span>
<span v-if="triggerMode == 'MANUAL'">手动</span> <span v-if="triggerMode === 'MANUAL'">{{$t('commons.trigger_mode.manual')}}</span>
<span v-if="triggerMode == 'SCHEDULE'">定时任务</span> <span v-if="triggerMode === 'SCHEDULE'">{{$t('commons.trigger_mode.schedule')}}</span>
<span v-if="triggerMode == 'API'">API</span> <span v-if="triggerMode === 'API'">{{$t('commons.trigger_mode.api')}}</span>
</span> </span>
</template> </template>

View File

@ -3,17 +3,9 @@
<ms-main-container> <ms-main-container>
<el-card class="table-card" v-loading="result.loading"> <el-card class="table-card" v-loading="result.loading">
<template v-slot:header> <template v-slot:header>
<div> <ms-table-header :is-tester-permission="true" :condition.sync="condition" @search="search"
<el-row type="flex" justify="space-between" align="middle"> :title="$t('commons.report')"
<span class="title">{{$t('commons.report')}}</span> :show-create="false"/>
<span class="search">
<el-input type="text" size="small" :placeholder="$t('report.search_by_name')"
prefix-icon="el-icon-search"
maxlength="60"
v-model="condition.name" @change="search" clearable/>
</span>
</el-row>
</div>
</template> </template>
<el-table :data="tableData" class="test-content" <el-table :data="tableData" class="test-content"
@ -91,10 +83,13 @@
import {_filter, _sort} from "../../../../common/js/utils"; import {_filter, _sort} from "../../../../common/js/utils";
import MsTableOperatorButton from "../../common/components/MsTableOperatorButton"; import MsTableOperatorButton from "../../common/components/MsTableOperatorButton";
import ReportTriggerModeItem from "../../common/tableItem/ReportTriggerModeItem"; import ReportTriggerModeItem from "../../common/tableItem/ReportTriggerModeItem";
import {REPORT_CONFIGS} from "../../common/components/search/search-components";
import MsTableHeader from "../../common/components/MsTableHeader";
export default { export default {
name: "PerformanceTestReport", name: "PerformanceTestReport",
components: { components: {
MsTableHeader,
ReportTriggerModeItem, ReportTriggerModeItem,
MsTableOperatorButton, MsPerformanceReportStatus, MsTablePagination, MsContainer, MsMainContainer}, MsTableOperatorButton, MsPerformanceReportStatus, MsTablePagination, MsContainer, MsMainContainer},
created: function () { created: function () {
@ -105,7 +100,9 @@
result: {}, result: {},
queryPath: "/performance/report/list/all", queryPath: "/performance/report/list/all",
deletePath: "/performance/report/delete/", deletePath: "/performance/report/delete/",
condition: {}, condition: {
components: REPORT_CONFIGS
},
projectId: null, projectId: null,
tableData: [], tableData: [],
multipleSelection: [], multipleSelection: [],
@ -129,15 +126,19 @@
} }
}, },
methods: { methods: {
initTableData() { initTableData(combine) {
this.result = this.$post(this.buildPagePath(this.queryPath), this.condition, response => { let condition = combine ? {combine: combine} : this.condition;
if (this.testId !== 'all') {
condition.testId = this.testId;
}
this.result = this.$post(this.buildPagePath(this.queryPath), condition, response => {
let data = response.data; let data = response.data;
this.total = data.itemCount; this.total = data.itemCount;
this.tableData = data.listObject; this.tableData = data.listObject;
}); });
}, },
search() { search(combine) {
this.initTableData(); this.initTableData(combine);
}, },
buildPagePath(path) { buildPagePath(path) {
return path + "/" + this.currentPage + "/" + this.pageSize; return path + "/" + this.currentPage + "/" + this.pageSize;

View File

@ -82,6 +82,7 @@
import MsTableOperators from "../../common/components/MsTableOperators"; import MsTableOperators from "../../common/components/MsTableOperators";
import {_filter, _sort} from "../../../../common/js/utils"; import {_filter, _sort} from "../../../../common/js/utils";
import MsTableHeader from "../../common/components/MsTableHeader"; import MsTableHeader from "../../common/components/MsTableHeader";
import {TEST_CONFIGS} from "../../common/components/search/search-components";
export default { export default {
components: { components: {
@ -98,7 +99,9 @@
result: {}, result: {},
queryPath: "/performance/list", queryPath: "/performance/list",
deletePath: "/performance/delete", deletePath: "/performance/delete",
condition: {}, condition: {
components: TEST_CONFIGS
},
projectId: null, projectId: null,
tableData: [], tableData: [],
multipleSelection: [], multipleSelection: [],
@ -140,20 +143,20 @@
this.initTableData(); this.initTableData();
}, },
methods: { methods: {
initTableData() { initTableData(combine) {
let condition = combine ? {combine: combine} : this.condition;
if (this.projectId !== 'all') { if (this.projectId !== 'all') {
this.condition.projectId = this.projectId; condition.projectId = this.projectId;
} }
this.result = this.$post(this.buildPagePath(this.queryPath), this.condition, response => { this.result = this.$post(this.buildPagePath(this.queryPath), condition, response => {
let data = response.data; let data = response.data;
this.total = data.itemCount; this.total = data.itemCount;
this.tableData = data.listObject; this.tableData = data.listObject;
}); });
}, },
search() { search(combine) {
this.initTableData(); this.initTableData(combine);
}, },
buildPagePath(path) { buildPagePath(path) {
return path + "/" + this.currentPage + "/" + this.pageSize; return path + "/" + this.currentPage + "/" + this.pageSize;
@ -225,6 +228,6 @@
} }
.el-table { .el-table {
cursor:pointer; cursor: pointer;
} }
</style> </style>

View File

@ -24,7 +24,7 @@
<template v-slot:default="scope"> <template v-slot:default="scope">
<ms-table-operator-button :tip="$t('member.edit_information')" icon="el-icon-edit" <ms-table-operator-button :tip="$t('member.edit_information')" icon="el-icon-edit"
type="primary" @exec="edit(scope.row)"/> type="primary" @exec="edit(scope.row)"/>
<ms-table-operator-button :tip="$t('member.edit_password')" icon="el-icon-s-tools" <ms-table-operator-button :tip="$t('member.edit_password')" icon="el-icon-s-tools" v-if="!isLdapUser"
type="success" @exec="editPassword(scope.row)"/> type="success" @exec="editPassword(scope.row)"/>
</template> </template>
</el-table-column> </el-table-column>
@ -43,7 +43,7 @@
<el-input v-model="form.name" autocomplete="off"/> <el-input v-model="form.name" autocomplete="off"/>
</el-form-item> </el-form-item>
<el-form-item :label="$t('commons.email')" prop="email"> <el-form-item :label="$t('commons.email')" prop="email">
<el-input v-model="form.email" autocomplete="off"/> <el-input v-model="form.email" autocomplete="off" :disabled="isLdapUser"/>
</el-form-item> </el-form-item>
<el-form-item :label="$t('commons.phone')" prop="phone"> <el-form-item :label="$t('commons.phone')" prop="phone">
<el-input v-model="form.phone" autocomplete="off"/> <el-input v-model="form.phone" autocomplete="off"/>
@ -89,6 +89,7 @@
data() { data() {
return { return {
result: {}, result: {},
isLdapUser: false,
updateVisible: false, updateVisible: false,
editPasswordVisible: false, editPasswordVisible: false,
tableData: [], tableData: [],
@ -198,6 +199,7 @@
initTableData() { initTableData() {
this.result = this.$get("/user/info/" + this.currentUser().id, response => { this.result = this.$get("/user/info/" + this.currentUser().id, response => {
let data = response.data; let data = response.data;
this.isLdapUser = response.data.source === 'LDAP' ? true : false;
let dataList = []; let dataList = [];
dataList[0] = data; dataList[0] = data;
this.tableData = dataList; this.tableData = dataList;

View File

@ -429,7 +429,7 @@
getTestOptions() { getTestOptions() {
this.testOptions = []; this.testOptions = [];
if (this.currentProject && this.form.type != '' && this.form.type != 'functional') { if (this.currentProject && this.form.type != '' && this.form.type != 'functional') {
this.$get('/' + this.form.type + '/list/' + this.currentProject.id, response => { this.result = this.$get('/' + this.form.type + '/list/' + this.currentProject.id, response => {
this.testOptions = response.data; this.testOptions = response.data;
}); });
} }

View File

@ -1,15 +1,25 @@
<template> <template>
<div> <div>
<el-tooltip class="item" effect="dark" :content="$t('test_track.case.export.export')" placement="right"> <el-row>
<el-button type="info" icon="el-icon-download" size="mini" circle></el-button> <el-link type="primary" class="download-case"
</el-tooltip> @click="downloadCase"
>{{$t('test_track.case.import.download_case')}}
</el-link>
</el-row>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: "TestCaseImport" name: "TestCaseExport",
methods: {
downloadCase() {
}
} }
}
</script> </script>
<style scoped> <style scoped>

View File

@ -10,16 +10,22 @@
<node-breadcrumb class="table-title" :nodes="selectParentNodes" @refresh="refresh"/> <node-breadcrumb class="table-title" :nodes="selectParentNodes" @refresh="refresh"/>
</template> </template>
<template v-slot:button> <template v-slot:button>
<ms-table-button :is-tester-permission="true" icon="el-icon-upload2" :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-right" :content="$t('test_track.case.move')" @click="handleBatch('move')"/> :content="$t('test_track.case.import.import')" @click="importTestCase"/>
<ms-table-button :is-tester-permission="true" icon="el-icon-delete" :content="$t('test_track.case.delete')" @click="handleBatch('delete')"/> <ms-table-button :is-tester-permission="true" icon="el-icon-download"
: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')"
@click="handleBatch('move')"/>
<ms-table-button :is-tester-permission="true" icon="el-icon-delete" :content="$t('test_track.case.delete')"
@click="handleBatch('delete')"/>
<!--<test-case-export/>--> <!--<test-case-export/>-->
</template> </template>
</ms-table-header> </ms-table-header>
</template> </template>
<test-case-import :projectId="currentProject == null? null : currentProject.id" @refresh="refresh" ref="testCaseImport"/> <test-case-import :projectId="currentProject == null? null : currentProject.id" @refresh="refresh"
ref="testCaseImport"/>
<el-table <el-table
:data="tableData" :data="tableData"
@ -85,9 +91,11 @@
<el-table-column <el-table-column
:label="$t('commons.operating')"> :label="$t('commons.operating')">
<template v-slot:default="scope"> <template v-slot:default="scope">
<ms-table-operator :is-tester-permission="true" @editClick="handleEdit(scope.row)" @deleteClick="handleDelete(scope.row)"> <ms-table-operator :is-tester-permission="true" @editClick="handleEdit(scope.row)"
@deleteClick="handleDelete(scope.row)">
<template v-slot:middle> <template v-slot:middle>
<ms-table-operator-button :is-tester-permission="true" :tip="$t('commons.copy')" icon="el-icon-document-copy" <ms-table-operator-button :is-tester-permission="true" :tip="$t('commons.copy')"
icon="el-icon-document-copy"
type="success" @exec="handleCopy(scope.row)"/> type="success" @exec="handleCopy(scope.row)"/>
</template> </template>
</ms-table-operator> </ms-table-operator>
@ -116,7 +124,7 @@
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, humpToLine} from "../../../../../common/js/utils"; import {_filter, _sort, downloadFile, humpToLine} from "../../../../../common/js/utils";
export default { export default {
name: "TestCaseList", name: "TestCaseList",
@ -127,163 +135,186 @@
MethodTableItem, MethodTableItem,
TypeTableItem, TypeTableItem,
PriorityTableItem, PriorityTableItem,
MsCreateBox, TestCaseImport, TestCaseExport, MsTablePagination, NodeBreadcrumb, MsTableHeader}, MsCreateBox, TestCaseImport, TestCaseExport, MsTablePagination, NodeBreadcrumb, MsTableHeader
data() { },
return { data() {
result: {}, return {
deletePath: "/test/case/delete", result: {},
condition: {}, deletePath: "/test/case/delete",
tableData: [], condition: {},
currentPage: 1, tableData: [],
pageSize: 10, currentPage: 1,
total: 0, pageSize: 10,
selectIds: new Set(), total: 0,
priorityFilters: [ selectIds: new Set(),
{text: 'P0', value: 'P0'}, priorityFilters: [
{text: 'P1', value: 'P1'}, {text: 'P0', value: 'P0'},
{text: 'P2', value: 'P2'}, {text: 'P1', value: 'P1'},
{text: 'P3', value: 'P3'} {text: 'P2', value: 'P2'},
], {text: 'P3', value: 'P3'}
methodFilters: [ ],
{text: this.$t('test_track.case.manual'), value: 'manual'}, methodFilters: [
{text: this.$t('test_track.case.auto'), value: 'auto'} {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'}, typeFilters: [
{text: this.$t('commons.performance'), value: 'performance'}, {text: this.$t('commons.functional'), value: 'functional'},
{text: this.$t('commons.api'), value: 'api'} {text: this.$t('commons.performance'), value: 'performance'},
] {text: this.$t('commons.api'), value: 'api'}
} ]
}
},
props: {
currentProject: {
type: Object
}, },
props: { selectNodeIds: {
currentProject: { type: Array
type: Object
},
selectNodeIds: {
type: Array
},
selectParentNodes: {
type: Array
}
}, },
created: function () { selectParentNodes: {
type: Array
}
},
created: function () {
this.initTableData();
},
watch: {
currentProject() {
this.initTableData(); this.initTableData();
}, },
watch: { selectNodeIds() {
currentProject() { this.initTableData();
this.initTableData(); }
}, },
selectNodeIds() { methods: {
this.initTableData(); initTableData() {
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();
});
} }
}, },
methods: { search() {
initTableData() { this.initTableData();
this.condition.nodeIds = this.selectNodeIds; },
if (this.currentProject) { buildPagePath(path) {
this.condition.projectId = this.currentProject.id; return path + "/" + this.currentPage + "/" + this.pageSize;
this.result = this.$post(this.buildPagePath('/test/case/list'), this.condition, response => { },
let data = response.data; testCaseCreate() {
this.total = data.itemCount; this.$emit('testCaseEdit');
this.tableData = data.listObject; },
this.selectIds.clear(); 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);
}
} }
}, });
search() { },
handleDeleteBatch() {
this.$alert(this.$t('test_track.case.delete_confirm') + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this.$post('/test/case/batch/delete', {ids: [...this.selectIds]}, () => {
this.selectIds.clear();
this.$emit("refresh");
this.$success(this.$t('commons.delete_success'));
});
}
}
});
},
_handleDelete(testCase) {
let testCaseId = testCase.id;
this.$post('/test/case/delete/' + testCaseId, {}, () => {
this.initTableData(); this.initTableData();
}, this.$success(this.$t('commons.delete_success'));
buildPagePath(path) { });
return path + "/" + this.currentPage + "/" + this.pageSize; },
}, refresh() {
testCaseCreate() { this.condition = {};
this.$emit('testCaseEdit'); this.selectIds.clear();
}, this.$emit('refresh');
handleEdit(testCase) { },
this.$emit('testCaseEdit', testCase); showDetail(row, event, column) {
}, this.$emit('testCaseDetail', row);
handleCopy(testCase) { },
this.$emit('testCaseCopy', testCase); handleSelectAll(selection) {
}, if (selection.length > 0) {
handleDelete(testCase) { this.tableData.forEach(item => {
this.$alert(this.$t('test_track.case.delete_confirm') + '\'' + testCase.name + '\'' + "", '', { this.selectIds.add(item.id);
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this._handleDelete(testCase);
}
}
}); });
}, } else {
handleDeleteBatch() {
this.$alert(this.$t('test_track.case.delete_confirm') + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this.$post('/test/case/batch/delete', {ids: [...this.selectIds]}, () => {
this.selectIds.clear();
this.$emit("refresh");
this.$success(this.$t('commons.delete_success'));
});
}
}
});
},
_handleDelete(testCase) {
let testCaseId = testCase.id;
this.$post('/test/case/delete/' + testCaseId, {}, () => {
this.initTableData();
this.$success(this.$t('commons.delete_success'));
});
},
refresh() {
this.condition = {};
this.selectIds.clear(); this.selectIds.clear();
this.$emit('refresh');
},
showDetail(row, event, column) {
this.$emit('testCaseDetail', row);
},
handleSelectAll(selection) {
if(selection.length > 0) {
this.tableData.forEach(item => {
this.selectIds.add(item.id);
});
} else {
this.selectIds.clear();
}
},
handleSelectionChange(selection, row) {
if(this.selectIds.has(row.id)){
this.selectIds.delete(row.id);
} else {
this.selectIds.add(row.id);
}
},
importTestCase() {
this.$refs.testCaseImport.open();
},
handleBatch(type){
if (this.selectIds.size < 1) {
this.$warning(this.$t('test_track.plan_view.select_manipulate'));
return;
}
if (type === 'move'){
this.$emit('moveToNode', this.selectIds);
} else if (type === 'delete'){
this.handleDeleteBatch();
}
},
filter(filters) {
_filter(filters, this.condition);
this.initTableData();
},
sort(column) {
_sort(column, this.condition);
this.initTableData();
} }
},
handleSelectionChange(selection, row) {
if (this.selectIds.has(row.id)) {
this.selectIds.delete(row.id);
} else {
this.selectIds.add(row.id);
}
},
importTestCase() {
this.$refs.testCaseImport.open();
},
exportTestCase() {
let config = {
url: '/test/case/export/testCase/' + [...this.selectIds],
method: 'get',
responseType: 'blob'
};
this.result = this.$request(config).then(response => {
const filename = '测试用例.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.selectIds.size < 1) {
this.$warning(this.$t('test_track.plan_view.select_manipulate'));
return;
}
if (type === 'move') {
this.$emit('moveToNode', this.selectIds);
} else if (type === 'delete') {
this.handleDeleteBatch();
} else {
this.exportTestCase();
}
},
filter(filters) {
_filter(filters, this.condition);
this.initTableData();
},
sort(column) {
_sort(column, this.condition);
this.initTableData();
} }
} }
}
</script> </script>
<style scoped> <style scoped>
@ -309,7 +340,7 @@
} }
.el-table { .el-table {
cursor:pointer; cursor: pointer;
} }
</style> </style>

View File

@ -19,6 +19,7 @@
<el-container> <el-container>
<el-main class="case-content" v-loading="result.loading"> <el-main class="case-content" v-loading="result.loading">
<ms-table-header :condition.sync="condition" @search="getCaseNames" title="" :show-create="false"/>
<el-table <el-table
:data="testCases" :data="testCases"
@filter-change="filter" @filter-change="filter"
@ -80,10 +81,22 @@
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 {_filter} from "../../../../../../common/js/utils"; import {_filter} from "../../../../../../common/js/utils";
import MsTableSearchBar from "../../../../common/components/MsTableSearchBar";
import MsTableAdvSearchBar from "../../../../common/components/search/MsTableAdvSearchBar";
import MsTableHeader from "../../../../common/components/MsTableHeader";
import {TEST_CASE_CONFIGS} from "../../../../common/components/search/search-components";
export default { export default {
name: "TestCaseRelevance", name: "TestCaseRelevance",
components: {NodeTree, MsDialogFooter, PriorityTableItem, TypeTableItem}, components: {
NodeTree,
MsDialogFooter,
PriorityTableItem,
TypeTableItem,
MsTableSearchBar,
MsTableAdvSearchBar,
MsTableHeader
},
data() { data() {
return { return {
result: {}, result: {},
@ -94,7 +107,9 @@
treeNodes: [], treeNodes: [],
selectNodeIds: [], selectNodeIds: [],
selectNodeNames: [], selectNodeNames: [],
condition: {}, condition: {
components: TEST_CASE_CONFIGS
},
priorityFilters: [ priorityFilters: [
{text: 'P0', value: 'P0'}, {text: 'P0', value: 'P0'},
{text: 'P1', value: 'P1'}, {text: 'P1', value: 'P1'},
@ -137,17 +152,19 @@
this.$emit('refresh'); this.$emit('refresh');
}); });
}, },
getCaseNames() { getCaseNames(combine) {
let param = {}; let param = {};
// combine
let condition = combine ? {combine: combine} : this.condition;
if (this.planId) { if (this.planId) {
// param.planId = this.planId; // param.planId = this.planId;
this.condition.planId = this.planId; condition.planId = this.planId;
} }
if (this.selectNodeIds && this.selectNodeIds.length > 0) { if (this.selectNodeIds && this.selectNodeIds.length > 0) {
// param.nodeIds = this.selectNodeIds; // param.nodeIds = this.selectNodeIds;
this.condition.nodeIds = this.selectNodeIds; condition.nodeIds = this.selectNodeIds;
} }
this.result = this.$post('/test/case/name', this.condition, response => { this.result = this.$post('/test/case/name', condition, response => {
this.testCases = response.data; this.testCases = response.data;
this.testCases.forEach(item => { this.testCases.forEach(item => {
item.checked = false; item.checked = false;

View File

@ -1,289 +1,326 @@
export default { export default {
commons: { commons: {
'delete_cancelled': 'Delete cancelled', delete_cancelled: 'Delete cancelled',
'workspace': 'Workspace', workspace: 'Workspace',
'organization': 'Organization', organization: 'Organization',
'setting': 'Setting', setting: 'Setting',
'project': 'Project', project: 'Project',
'about_us': 'About Us', about_us: 'About Us',
current_project: 'Current Project', current_project: 'Current Project',
'name': 'Name', name: 'Name',
'description': 'Description', description: 'Description',
'clear': 'Clear', clear: 'Clear',
'save': 'Save', save: 'Save',
'save_success': 'Saved successfully', save_success: 'Saved successfully',
'delete_success': 'Deleted successfully', delete_success: 'Deleted successfully',
'modify_success': 'Modify Success', modify_success: 'Modify Success',
'copy_success': 'Copy Success', copy_success: 'Copy Success',
'delete_cancel': 'Deleted Cancel', delete_cancel: 'Deleted Cancel',
'confirm': 'Confirm', confirm: 'Confirm',
'cancel': 'Cancel', cancel: 'Cancel',
'prompt': 'Prompt', prompt: 'Prompt',
'operating': 'Operating', operating: 'Operating',
'input_limit': 'Within {0} and {1} characters', input_limit: 'Within {0} and {1} characters',
'login': 'Sign In', login: 'Sign In',
'welcome': 'Welcome back, please enter username and password to log in to MeterSphere', welcome: 'Welcome back, please enter username and password to log in to MeterSphere',
'username': 'Username', username: 'Username',
'password': 'Password', password: 'Password',
'input_username': 'Please enter username', input_username: 'Please enter username',
'input_password': 'Please enter password', input_password: 'Please enter password',
'test': 'Test', test: 'Test',
'create_time': 'Created Time', create_time: 'Created Time',
'update_time': 'Updated Time', update_time: 'Updated Time',
'add': 'Add', add: 'Add',
'member': 'Member', member: 'Member',
'email': 'Email', email: 'Email',
'phone': 'Phone', phone: 'Phone',
'role': 'Role', role: 'Role',
'personal_info': 'Personal Info', personal_info: 'Personal Info',
'status': 'Status', status: 'Status',
'show_all': 'Show All', show_all: 'Show All',
'show': 'Show', show: 'Show',
'report': 'Report', report: 'Report',
'user': 'User', user: 'User',
'system': 'System', system: 'System',
'personal_setting': 'Personal Setting', personal_setting: 'Personal Setting',
'test_resource_pool': 'Resource Pool', test_resource_pool: 'Resource Pool',
'system_setting': 'Settings', system_setting: 'Settings',
'api': 'API', api: 'API',
'performance': 'Performance', performance: 'Performance',
'functional': 'Functional test', functional: 'Functional test',
'input_content': 'Please enter content', input_content: 'Please enter content',
'create': 'Create', create: 'Create',
'edit': 'Edit', edit: 'Edit',
'copy': 'Copy', copy: 'Copy',
'refresh': 'Refresh', refresh: 'Refresh',
'remark': 'Remark', remark: 'Remark',
'delete': 'Delete', delete: 'Delete',
'not_filled': 'Not filled', not_filled: 'Not filled',
'please_select': 'Please select', please_select: 'Please select',
'search_by_name': 'Search by name', search_by_name: 'Search by name',
'personal_information': 'Personal Information', personal_information: 'Personal Information',
'exit_system': 'Exit System', exit_system: 'Exit System',
'verification': 'Verification', verification: 'Verification',
'system_parameter_setting': 'System Parameter Setting', system_parameter_setting: 'System Parameter Setting',
'connection_successful': 'Connection successful', connection_successful: 'Connection successful',
'connection_failed': 'Connection failed', connection_failed: 'Connection failed',
'save_failed': 'Saved failed', save_failed: 'Saved failed',
'host_cannot_be_empty': 'Host cannot be empty', host_cannot_be_empty: 'Host cannot be empty',
'port_cannot_be_empty': 'Port cannot be empty', port_cannot_be_empty: 'Port cannot be empty',
'account_cannot_be_empty': 'Account cannot be empty', account_cannot_be_empty: 'Account cannot be empty',
'title': 'Title', title: 'Title',
'custom': 'Custom', custom: 'Custom',
'select_date': 'Select date', select_date: 'Select date',
'calendar_heatmap': 'Calendar Heatmap', calendar_heatmap: 'Calendar Heatmap',
'months_1': 'Jan', months_1: 'Jan',
'months_2': 'Feb', months_2: 'Feb',
'months_3': 'Mar', months_3: 'Mar',
'months_4': 'Apr', months_4: 'Apr',
'months_5': 'May', months_5: 'May',
'months_6': 'Jun', months_6: 'Jun',
'months_7': 'Jul', months_7: 'Jul',
'months_8': 'Aug', months_8: 'Aug',
'months_9': 'Sep', months_9: 'Sep',
'months_10': 'Oct', months_10: 'Oct',
'months_11': 'Nov', months_11: 'Nov',
'months_12': 'Dec', months_12: 'Dec',
'weeks_0': 'Sun', weeks_0: 'Sun',
'weeks_1': 'Mon', weeks_1: 'Mon',
'weeks_2': 'Tues', weeks_2: 'Tues',
'weeks_3': 'Wed', weeks_3: 'Wed',
'weeks_4': 'Thur', weeks_4: 'Thur',
'weeks_5': 'Fri', weeks_5: 'Fri',
'weeks_6': 'Sat', weeks_6: 'Sat',
'test_unit': 'tests', test_unit: 'tests',
'remove': 'Remove', remove: 'Remove',
'remove_cancel': 'Remove Cancel', remove_cancel: 'Remove Cancel',
'remove_success': 'Remove Success', remove_success: 'Remove Success',
'tips': 'The authentication information has expired, please login again', tips: 'The authentication information has expired, please login again',
'not_performed_yet': 'Not performed yet', not_performed_yet: 'Not performed yet',
'incorrect_input': 'Incorrect input', incorrect_input: 'Incorrect input',
'delete_confirm': 'Please enter the following to confirm deletion:', delete_confirm: 'Please enter the following to confirm deletion:',
'login_username': 'ID or email', login_username: 'ID or email',
'input_login_username': 'Please input the user ID or email', input_login_username: 'Please input the user ID or email',
'input_name': 'Please enter name', input_name: 'Please enter name',
'formatErr': 'Format Error' formatErr: 'Format Error',
date: {
select_date: 'Select date',
start_date: 'Start date',
end_date: 'End date',
select_date_time: 'Select date and time',
start_date_time: 'Start date and time',
end_date_time: 'End date time',
range_separator: "To",
},
trigger_mode: {
name: "Trigger Mode",
manual: "Manual trigger",
schedule: "Scheduled Task",
api: "API call"
},
adv_search: {
title: 'Advanced Search',
combine: 'Combined query',
test: "Test",
project: "Project",
search: "Query",
reset: "Reset",
and: 'All',
or: 'any one',
operators: {
like: "Contains",
not_like: "Not included",
in: "Belong to",
not_in: "Not belonging",
gt: ">",
ge: ">=",
lt: "<",
le: "<=",
equals: "=",
between: "Between",
current_user: "Current user"
}
}
}, },
workspace: { workspace: {
'create': 'Create Workspace', create: 'Create Workspace',
'update': 'Update Workspace', update: 'Update Workspace',
'delete': 'Delete Workspace', delete: 'Delete Workspace',
'delete_confirm': 'Deleting the workspace will delete all resources (such as related projects, test cases, etc.) under the workspace. Are you sure you want to delete?', delete_confirm: 'Deleting the workspace will delete all resources (such as related projects, test cases, etc.) under the workspace. Are you sure you want to delete?',
'add': 'Add Workspace', add: 'Add Workspace',
'input_name': 'Please enter a workspace name', input_name: 'Please enter a workspace name',
'search_by_name': 'Search by name', search_by_name: 'Search by name',
'organization_name': 'Organization Name', organization_name: 'Organization Name',
'please_choose_organization': 'Please Choose Organization', please_choose_organization: 'Please Choose Organization',
'please_select_a_workspace_first': 'Please select a workspace first!', please_select_a_workspace_first: 'Please select a workspace first!',
'none': 'None Workspace', none: 'None Workspace',
'select': 'Select Workspace', select: 'Select Workspace',
'special_characters_are_not_supported': 'Incorrect format (special characters are not supported and cannot end with \'-\')', special_characters_are_not_supported: 'Incorrect format (special characters are not supported and cannot end with \'-\')',
}, },
organization: { organization: {
'create': 'Create Organization', create: 'Create Organization',
'modify': 'Modify', modify: 'Modify',
'delete': 'Delete Organization', delete: 'Delete Organization',
'delete_confirm': 'Deleting this organization will delete all resources (such as related workspaces, projects, test cases, etc.) under this organization. Are you sure you want to delete?', delete_confirm: 'Deleting this organization will delete all resources (such as related workspaces, projects, test cases, etc.) under this organization. Are you sure you want to delete?',
'input_name': 'Please enter a organization name', input_name: 'Please enter a organization name',
'select_organization': 'Please select organization', select_organization: 'Please select organization',
'search_by_name': 'Search by name', search_by_name: 'Search by name',
'special_characters_are_not_supported': 'Incorrect format (special characters are not supported and cannot end with \'-\')', special_characters_are_not_supported: 'Incorrect format (special characters are not supported and cannot end with \'-\')',
'none': 'None Organization', none: 'None Organization',
'select': 'Select Organization', select: 'Select Organization',
}, },
project: { project: {
'name': 'Project name', name: 'Project name',
'recent': 'Recent Projects', recent: 'Recent Projects',
'create': 'Create Project', create: 'Create Project',
'edit': 'Edit Project', edit: 'Edit Project',
'delete': 'Delete project', delete: 'Delete project',
'delete_confirm': 'Deleting this project will delete all test resources under this project. Are you sure you want to delete?', delete_confirm: 'Deleting this project will delete all test resources under this project. Are you sure you want to delete?',
'delete_tip': 'Deleting this project will delete all test resources under this project. Are you sure you want to delete?', delete_tip: 'Deleting this project will delete all test resources under this project. Are you sure you want to delete?',
'search_by_name': 'Search by name', search_by_name: 'Search by name',
'input_name': 'Please enter a workspace name', input_name: 'Please enter a workspace name',
'owning_workspace': 'Owning Workspace', owning_workspace: 'Owning Workspace',
'please_choose_workspace': 'Please select Workspace', please_choose_workspace: 'Please select Workspace',
'special_characters_are_not_supported': 'Incorrect format (special characters are not supported and cannot end with \'-\')', special_characters_are_not_supported: 'Incorrect format (special characters are not supported and cannot end with \'-\')',
}, },
member: { member: {
'create': 'Create', create: 'Create',
'modify': 'Modify', modify: 'Modify',
'delete_confirm': 'Are you sure you want to delete this Member?', delete_confirm: 'Are you sure you want to delete this Member?',
'please_choose_member': 'Please Choose Member', please_choose_member: 'Please Choose Member',
'search_by_name': 'Search by name', search_by_name: 'Search by name',
'modify_personal_info': 'Modify Personal Information', modify_personal_info: 'Modify Personal Information',
'edit_password': 'Edit Password', edit_password: 'Edit Password',
'edit_information': 'Edit Information', edit_information: 'Edit Information',
'input_name': 'Please enter a user name', input_name: 'Please enter a user name',
'input_email': 'Please enter a email', input_email: 'Please enter a email',
'special_characters_are_not_supported': 'Special characters are not supported', special_characters_are_not_supported: 'Special characters are not supported',
'mobile_number_format_is_incorrect': 'Mobile number format is incorrect', mobile_number_format_is_incorrect: 'Mobile number format is incorrect',
'email_format_is_incorrect': 'Email format is incorrect', email_format_is_incorrect: 'Email format is incorrect',
'password_format_is_incorrect': 'Valid password: 8-16 digits, English upper and lower case letters + numbers + special characters (optional)', password_format_is_incorrect: 'Valid password: 8-16 digits, English upper and lower case letters + numbers + special characters (optional)',
'old_password': 'Old Password', old_password: 'Old Password',
'new_password': 'New Password', new_password: 'New Password',
'remove_member': 'Are you sure you want to remove this member', remove_member: 'Are you sure you want to remove this member',
'input_id_or_email': 'Please enter user ID, or user Email', input_id_or_email: 'Please enter user ID, or user Email',
'no_such_user': 'Without this user information, please enter the correct user ID or user Email!', no_such_user: 'Without this user information, please enter the correct user ID or user Email!',
}, },
user: { user: {
'create': 'Create', create: 'Create',
'modify': 'Modify', modify: 'Modify',
'input_name': 'Please enter a user name', input_name: 'Please enter a user name',
'input_id': 'Please enter a ID', input_id: 'Please enter a ID',
'input_email': 'Please enter a email', input_email: 'Please enter a email',
'input_password': 'Please enter a password', input_password: 'Please enter a password',
'input_phone': 'Please enter phone number', input_phone: 'Please enter phone number',
'special_characters_are_not_supported': 'Special characters are not supported', special_characters_are_not_supported: 'Special characters are not supported',
'mobile_number_format_is_incorrect': 'Mobile number format is incorrect', mobile_number_format_is_incorrect: 'Mobile number format is incorrect',
'email_format_is_incorrect': 'Email format is incorrect', email_format_is_incorrect: 'Email format is incorrect',
'delete_confirm': 'Are you sure you want to delete this User?', delete_confirm: 'Are you sure you want to delete this User?',
'apikey_delete_confirm': 'Are you sure you want to delete this API Key?', apikey_delete_confirm: 'Are you sure you want to delete this API Key?',
'input_id_placeholder': 'Please enter ID (only supports numbers and English letters)' input_id_placeholder: 'Please enter ID (only supports numbers and English letters)'
}, },
role: { role: {
'please_choose_role': 'Please Choose Role', please_choose_role: 'Please Choose Role',
'admin': 'Admin', admin: 'Admin',
'org_admin': 'Org_Admin', org_admin: 'Org_Admin',
'test_manager': 'Test Manager', test_manager: 'Test Manager',
'test_user': 'Test User', test_user: 'Test User',
'test_viewer': 'Test Viewer', test_viewer: 'Test Viewer',
'add': 'Add Role', add: 'Add Role',
}, },
report: { report: {
'recent': 'Recent Report', recent: 'Recent Report',
'search_by_name': 'Search by Name', search_by_name: 'Search by Name',
'test_name': 'Test', test_name: 'Test',
'test_overview': 'Test Overview', test_overview: 'Test Overview',
'test_request_statistics': 'Test Request Statistics', test_request_statistics: 'Test Request Statistics',
'test_error_log': 'Test Error Log', test_error_log: 'Test Error Log',
'test_log_details': 'Test Log Details', test_log_details: 'Test Log Details',
'test_details': 'Test Details', test_details: 'Test Details',
'test_duration': 'Test Duration{0} minutes {1} seconds', test_duration: 'Test Duration{0} minutes {1} seconds',
'test_start_time': 'Test Start Time', test_start_time: 'Test Start Time',
'test_end_time': 'Test End Time', test_end_time: 'Test End Time',
'test_stop_now': 'Test Stop Now', test_stop_now: 'Test Stop Now',
'test_stop_now_confirm': 'Are you sure you want to stop the current test immediately?', test_stop_now_confirm: 'Are you sure you want to stop the current test immediately?',
'test_rerun_confirm': 'Are you sure you want to rerun the current test immediately?', test_rerun_confirm: 'Are you sure you want to rerun the current test immediately?',
'test_stop_success': 'Test stop successfully', test_stop_success: 'Test stop successfully',
'test_execute_again': 'Test Execute Again', test_execute_again: 'Test Execute Again',
'export': 'Export', export: 'Export',
'compare': 'Compare', compare: 'Compare',
'generation_error': 'Report generation error, cannot be viewed!', generation_error: 'Report generation error, cannot be viewed!',
'being_generated': 'Report is being generated...', being_generated: 'Report is being generated...',
'delete_confirm': 'Confirm delete: ', delete_confirm: 'Confirm delete: ',
'start_status': 'The test is starting, please check the report later!', start_status: 'The test is starting, please check the report later!',
'run_status': 'The test is running, please check the report later', run_status: 'The test is running, please check the report later',
'user_name': 'Creator', user_name: 'Creator',
'project_name': 'Project Name' project_name: 'Project Name'
}, },
load_test: { load_test: {
'operating': 'Operating', operating: 'Operating',
'pressure_prediction_chart': 'Pressure Prediction Chart', pressure_prediction_chart: 'Pressure Prediction Chart',
'recent': 'Recent Tests', recent: 'Recent Tests',
'search_by_name': 'Search by name', search_by_name: 'Search by name',
'project_name': 'Project', project_name: 'Project',
'delete_confirm': 'Are you sure want to delete test: ', delete_confirm: 'Are you sure want to delete test: ',
'input_name': 'Please enter name', input_name: 'Please enter name',
'select_project': 'Please select project', select_project: 'Please select project',
'save_and_run': 'Save and execute', save_and_run: 'Save and execute',
'basic_config': 'Scene Configuration', basic_config: 'Scene Configuration',
'pressure_config': 'Pressure configuration', pressure_config: 'Pressure configuration',
'advanced_config': 'Advanced Configuration', advanced_config: 'Advanced Configuration',
'runtime_config': 'Runtime Configuration', runtime_config: 'Runtime Configuration',
'is_running': 'Test is running! ', is_running: 'Test is running! ',
'test_name_is_null': 'Test name cannot be empty! ', test_name_is_null: 'Test name cannot be empty! ',
'project_is_null': 'Project cannot be empty! ', project_is_null: 'Project cannot be empty! ',
'jmx_is_null': 'Must contain a JMX file, and can only contain a JMX file!', jmx_is_null: 'Must contain a JMX file, and can only contain a JMX file!',
'file_name': 'File name', file_name: 'File name',
'file_size': 'File size', file_size: 'File size',
'file_type': 'File Type', file_type: 'File Type',
'file_status': 'File Status', file_status: 'File Status',
'last_modify_time': 'Modify time', last_modify_time: 'Modify time',
'upload_tips': 'Drag files here, or <em> click to upload </em>', upload_tips: 'Drag files here, or <em> click to upload </em>',
'upload_type': 'Only JMX/CSV files can be uploaded', upload_type: 'Only JMX/CSV files can be uploaded',
'related_file_not_found': "No related test file found!", related_file_not_found: "No related test file found!",
'delete_file_confirm': 'Confirm delete file:', delete_file_confirm: 'Confirm delete file:',
'file_size_limit': "The number of files exceeds the limit", file_size_limit: "The number of files exceeds the limit",
'delete_file': "The file already exists, please delete the file with the same name first!", delete_file: "The file already exists, please delete the file with the same name first!",
'thread_num': 'Concurrent users:', thread_num: 'Concurrent users:',
'input_thread_num': 'Please enter the number of threads', input_thread_num: 'Please enter the number of threads',
'duration': 'Duration time (minutes):', duration: 'Duration time (minutes):',
'input_duration': 'Please enter a duration', input_duration: 'Please enter a duration',
'rps_limit': 'RPS Limit:', rps_limit: 'RPS Limit:',
'input_rps_limit': 'Please enter a limit', input_rps_limit: 'Please enter a limit',
'ramp_up_time_within': 'In', ramp_up_time_within: 'In',
'ramp_up_time_minutes': 'minutes, separate', ramp_up_time_minutes: 'minutes, separate',
'ramp_up_time_times': 'add concurrent users', ramp_up_time_times: 'add concurrent users',
'advanced_config_error': 'Advanced configuration verification failed', advanced_config_error: 'Advanced configuration verification failed',
'domain_bind': 'Domain bind', domain_bind: 'Domain bind',
'domain': 'Domain', domain: 'Domain',
'enable': 'Enable', enable: 'Enable',
'ip': 'IP', ip: 'IP',
'params': 'Parameters', params: 'Parameters',
'param_name': 'Name', param_name: 'Name',
'param_value': 'Value', param_value: 'Value',
'domain_is_duplicate': 'Domain is duplicated', domain_is_duplicate: 'Domain is duplicated',
'param_is_duplicate': 'Parameter name is duplicate', param_is_duplicate: 'Parameter name is duplicate',
'domain_ip_is_empty': 'Domain and IP cannot be empty', domain_ip_is_empty: 'Domain and IP cannot be empty',
'param_name_value_is_empty': 'Parameters cannot be empty', param_name_value_is_empty: 'Parameters cannot be empty',
'connect_timeout': 'Timeout to establish a connection', connect_timeout: 'Timeout to establish a connection',
'custom_http_code': 'Custom HTTP response success status code', custom_http_code: 'Custom HTTP response success status code',
'separated_by_commas': 'Separated by commas', separated_by_commas: 'Separated by commas',
'create': 'Create Test', create: 'Create Test',
'select_resource_pool': 'Please Select Resource Pool', select_resource_pool: 'Please Select Resource Pool',
'resource_pool_is_null': 'Resource Pool is empty', resource_pool_is_null: 'Resource Pool is empty',
'download_log_file': 'Download', download_log_file: 'Download',
'user_name': 'Creator', user_name: 'Creator',
'special_characters_are_not_supported': 'Test name does not support special characters', special_characters_are_not_supported: 'Test name does not support special characters',
'pressure_config_params_is_empty': 'Pressure configuration parameters cannot be empty!' pressure_config_params_is_empty: 'Pressure configuration parameters cannot be empty!'
}, },
api_test: { api_test: {
creator: "Creator", creator: "Creator",
title: "Test",
save_and_run: "Save and Run", save_and_run: "Save and Run",
run: "Run", run: "Run",
running: "Running", running: "Running",
@ -564,66 +601,66 @@ export default {
} }
}, },
test_resource_pool: { test_resource_pool: {
'type': 'type', type: 'type',
'enable_disable': 'Enable / disable', enable_disable: 'Enable / disable',
'search_by_name': 'Search by name', search_by_name: 'Search by name',
'create_resource_pool': 'Create resource pool', create_resource_pool: 'Create resource pool',
'update_resource_pool': 'Create resource pool', update_resource_pool: 'Create resource pool',
'select_pool_type': 'Select resource type', select_pool_type: 'Select resource type',
'max_threads': 'Maximum concurrent number', max_threads: 'Maximum concurrent number',
'input_pool_name': 'Please enter the resource pool name', input_pool_name: 'Please enter the resource pool name',
'pool_name_valid': 'Resource pool name does not support special characters', pool_name_valid: 'Resource pool name does not support special characters',
'cannot_remove_all_node': 'Cannot delete all independent nodes', cannot_remove_all_node: 'Cannot delete all independent nodes',
'cannot_empty': 'Resource pool cannot be empty', cannot_empty: 'Resource pool cannot be empty',
'fill_the_data': 'Please complete the data', fill_the_data: 'Please complete the data',
'delete_prompt': 'This operation will permanently delete the resource pool, continue?', delete_prompt: 'This operation will permanently delete the resource pool, continue?',
'status_change_success': 'Successfully changed the status!', status_change_success: 'Successfully changed the status!',
'status_change_failed': 'Failed to change the status, resource pool is invalid!', status_change_failed: 'Failed to change the status, resource pool is invalid!',
'check_in': 'Check in', check_in: 'Check in',
}, },
system_parameter_setting: { system_parameter_setting: {
'mailbox_service_settings': 'Mailbox Settings', mailbox_service_settings: 'Mailbox Settings',
'ldap_setting': 'LDAP Setting', ldap_setting: 'LDAP Setting',
'test_connection': 'Test connection', test_connection: 'Test connection',
'SMTP_host': 'SMTP host', SMTP_host: 'SMTP host',
'SMTP_port': 'SMTP port', SMTP_port: 'SMTP port',
'SMTP_account': 'SMTP account', SMTP_account: 'SMTP account',
'SMTP_password': 'SMTP password', SMTP_password: 'SMTP password',
'SSL': 'Turn on SSL (if the SMTP port is 465, you usually need to enable SSL)', SSL: 'Turn on SSL (if the SMTP port is 465, you usually need to enable SSL)',
'TLS': 'Turn on TLS (if the SMTP port is 587, you usually need to enable TLS)', TLS: 'Turn on TLS (if the SMTP port is 587, you usually need to enable TLS)',
'SMTP': 'Anonymous SMTP or not', SMTP: 'Anonymous SMTP or not',
}, },
i18n: { i18n: {
'home': 'Home' home: 'Home'
}, },
ldap: { ldap: {
'url': 'LDAP URL', url: 'LDAP URL',
'dn': 'Bind DN', dn: 'Bind DN',
'password': 'Password', password: 'Password',
'ou': 'User OU', ou: 'User OU',
'filter': 'User Filter', filter: 'User Filter',
'mapping': 'LDAP Mapping', mapping: 'LDAP Mapping',
'open': 'Enable LDAP Authentication', open: 'Enable LDAP Authentication',
'input_url': 'Please enter LDAP url', input_url: 'Please enter LDAP url',
'input_dn': 'Please enter DN', input_dn: 'Please enter DN',
'input_password': 'Please enter the password', input_password: 'Please enter the password',
'input_ou': 'Please enter user OU', input_ou: 'Please enter user OU',
'input_filter': 'Please enter a user filter', input_filter: 'Please enter a user filter',
'input_mapping': 'Please enter LDAP attribute mapping', input_mapping: 'Please enter LDAP attribute mapping',
'input_username': 'please enter user name', input_username: 'please enter user name',
'input_url_placeholder': 'Please enter the LDAP address (eg ldap://localhost:389)', input_url_placeholder: 'Please enter the LDAP address (eg ldap://localhost:389)',
'input_ou_placeholder': 'Enter user OU (use | to separate each OU)', input_ou_placeholder: 'Enter user OU (use | to separate each OU)',
'input_filter_placeholder': 'Input filter [Possible options are cn or uid or sAMAccountName={0}, eg: (uid={0})]', input_filter_placeholder: 'Input filter [Possible options are cn or uid or sAMAccountName={0}, eg: (uid={0})]',
'test_connect': 'Test Connection', test_connect: 'Test Connection',
'test_login': 'Test Login', test_login: 'Test Login',
'edit': 'Edit', edit: 'Edit',
'login_success': 'login success', login_success: 'login success',
'url_cannot_be_empty': 'LDAP address cannot be empty', url_cannot_be_empty: 'LDAP address cannot be empty',
'dn_cannot_be_empty': 'LDAP DN cannot be empty', dn_cannot_be_empty: 'LDAP DN cannot be empty',
'ou_cannot_be_empty': 'LDAP OU cannot be empty', ou_cannot_be_empty: 'LDAP OU cannot be empty',
'filter_cannot_be_empty': 'LDAP user filter cannot be empty', filter_cannot_be_empty: 'LDAP user filter cannot be empty',
'password_cannot_be_empty': 'LDAP password cannot be empty', password_cannot_be_empty: 'LDAP password cannot be empty',
}, },
schedule: { schedule: {
not_set: "Not Set", not_set: "Not Set",

View File

@ -1,284 +1,322 @@
export default { export default {
commons: { commons: {
'delete_cancelled': '已取消删除', delete_cancelled: '已取消删除',
'workspace': '工作空间', workspace: '工作空间',
'organization': '组织', organization: '组织',
'setting': '设置', setting: '设置',
'project': '项目', project: '项目',
'about_us': '关于', about_us: '关于',
current_project: '当前项目', current_project: '当前项目',
'name': '名称', name: '名称',
'description': '描述', description: '描述',
'clear': '清空', clear: '清空',
'save': '保存', save: '保存',
'save_success': '保存成功', save_success: '保存成功',
'delete_success': '删除成功', delete_success: '删除成功',
'copy_success': '复制成功', copy_success: '复制成功',
'modify_success': '修改成功', modify_success: '修改成功',
'delete_cancel': '已取消删除', delete_cancel: '已取消删除',
'confirm': '确定', confirm: '确定',
'cancel': '取消', cancel: '取消',
'prompt': '提示', prompt: '提示',
'operating': '操作', operating: '操作',
'input_limit': '长度在 {0} 到 {1} 个字符', input_limit: '长度在 {0} 到 {1} 个字符',
'login': '登录', login: '登录',
'welcome': '欢迎回来请输入用户名和密码登录MeterSphere', welcome: '欢迎回来请输入用户名和密码登录MeterSphere',
'username': '姓名', username: '姓名',
'password': '密码', password: '密码',
'input_username': '请输入用户姓名', input_username: '请输入用户姓名',
'input_password': '请输入密码', input_password: '请输入密码',
'test': '测试', test: '测试',
'create_time': '创建时间', create_time: '创建时间',
'update_time': '更新时间', update_time: '更新时间',
'add': '添加', add: '添加',
'member': '成员', member: '成员',
'email': '邮箱', email: '邮箱',
'phone': '电话', phone: '电话',
'role': '角色', role: '角色',
'personal_info': '个人信息', personal_info: '个人信息',
'status': '状态', status: '状态',
'show_all': '显示全部', show_all: '显示全部',
'show': '显示', show: '显示',
'report': '报告', report: '报告',
'user': '用户', user: '用户',
'system': '系统', system: '系统',
'personal_setting': '个人设置', personal_setting: '个人设置',
'test_resource_pool': '测试资源池', test_resource_pool: '测试资源池',
'system_setting': '系统设置', system_setting: '系统设置',
'api': '接口测试', api: '接口测试',
'performance': '性能测试', performance: '性能测试',
'functional': '功能测试', functional: '功能测试',
'input_content': '请输入内容', input_content: '请输入内容',
'create': '新建', create: '新建',
'edit': '编辑', edit: '编辑',
'copy': '复制', copy: '复制',
'refresh': '刷新', refresh: '刷新',
'remark': '备注', remark: '备注',
'delete': '删除', delete: '删除',
'not_filled': '未填写', not_filled: '未填写',
'please_select': '请选择', please_select: '请选择',
'search_by_name': '根据名称搜索', search_by_name: '根据名称搜索',
'personal_information': '个人信息', personal_information: '个人信息',
'exit_system': '退出系统', exit_system: '退出系统',
'verification': '验证', verification: '验证',
'title': '标题', title: '标题',
'custom': '自定义', custom: '自定义',
'select_date': '选择日期', select_date: '选择日期',
'calendar_heatmap': '测试日历', calendar_heatmap: '测试日历',
'months_1': '一月', months_1: '一月',
'months_2': '二月', months_2: '二月',
'months_3': '三月', months_3: '三月',
'months_4': '四月', months_4: '四月',
'months_5': '五月', months_5: '五月',
'months_6': '六月', months_6: '六月',
'months_7': '七月', months_7: '七月',
'months_8': '八月', months_8: '八月',
'months_9': '九月', months_9: '九月',
'months_10': '十月', months_10: '十月',
'months_11': '十一月', months_11: '十一月',
'months_12': '十二月', months_12: '十二月',
'weeks_0': '周日', weeks_0: '周日',
'weeks_1': '周一', weeks_1: '周一',
'weeks_2': '周二', weeks_2: '周二',
'weeks_3': '周三', weeks_3: '周三',
'weeks_4': '周四', weeks_4: '周四',
'weeks_5': '周五', weeks_5: '周五',
'weeks_6': '周六', weeks_6: '周六',
'test_unit': '测试', test_unit: '测试',
'system_parameter_setting': '系统参数设置', system_parameter_setting: '系统参数设置',
'connection_successful': '连接成功', connection_successful: '连接成功',
'connection_failed': '连接失败', connection_failed: '连接失败',
'save_failed': '保存失败', save_failed: '保存失败',
'host_cannot_be_empty': '主机不能为空', host_cannot_be_empty: '主机不能为空',
'port_cannot_be_empty': '端口号不能为空', port_cannot_be_empty: '端口号不能为空',
'account_cannot_be_empty': '帐户不能为空', account_cannot_be_empty: '帐户不能为空',
'remove': '移除', remove: '移除',
'remove_cancel': '移除取消', remove_cancel: '移除取消',
'remove_success': '移除成功', remove_success: '移除成功',
'tips': '认证信息已过期,请重新登录', tips: '认证信息已过期,请重新登录',
'not_performed_yet': '尚未执行', not_performed_yet: '尚未执行',
'incorrect_input': '输入内容不正确', incorrect_input: '输入内容不正确',
'delete_confirm': '请输入以下内容,确认删除:', delete_confirm: '请输入以下内容,确认删除:',
'login_username': 'ID 或 邮箱', login_username: 'ID 或 邮箱',
'input_login_username': '请输入用户 ID 或 邮箱', input_login_username: '请输入用户 ID 或 邮箱',
'input_name': '请输入名称', input_name: '请输入名称',
'formatErr': '格式错误' formatErr: '格式错误',
date: {
select_date: '选择日期',
start_date: '开始日期',
end_date: '结束日期',
select_date_time: '选择日期时间',
start_date_time: '开始日期时间',
end_date_time: '结束日期时间',
range_separator: "至",
},
trigger_mode: {
name: "触发方式",
manual: "手动触发",
schedule: "定时任务",
api: "API调用"
},
adv_search: {
title: '高级搜索',
combine: '组合查询',
test: "所属测试",
project: "所属项目",
search: "查询",
reset: "重置",
and: '所有',
or: '任意一个',
operators: {
like: "包含",
not_like: "不包含",
in: "属于",
not_in: "不属于",
gt: "大于",
ge: "大于等于",
lt: "小于",
le: "小于等于",
equals: "等于",
between: "之间",
current_user: "是当前用户"
}
}
}, },
workspace: { workspace: {
'create': '创建工作空间', create: '创建工作空间',
'update': '修改工作空间', update: '修改工作空间',
'delete': '删除工作空间', delete: '删除工作空间',
'delete_confirm': '删除该工作空间会关联删除该工作空间下的所有资源(如:相关项目,测试用例等),确定要删除吗?', delete_confirm: '删除该工作空间会关联删除该工作空间下的所有资源(如:相关项目,测试用例等),确定要删除吗?',
'add': '添加工作空间', add: '添加工作空间',
'input_name': '请输入工作空间名称', input_name: '请输入工作空间名称',
'search_by_name': '根据名称搜索', search_by_name: '根据名称搜索',
'organization_name': '所属组织', organization_name: '所属组织',
'please_choose_organization': '请选择组织', please_choose_organization: '请选择组织',
'please_select_a_workspace_first': '请先选择工作空间!', please_select_a_workspace_first: '请先选择工作空间!',
'none': '无工作空间', none: '无工作空间',
'select': '选择工作空间', select: '选择工作空间',
'special_characters_are_not_supported': '格式错误(不支持特殊字符,且不能以\'-\'开头结尾)', special_characters_are_not_supported: '格式错误(不支持特殊字符,且不能以\'-\'开头结尾)',
'delete_warning': '删除该工作空间将同步删除该工作空间下所有项目,以及项目中的所有用例、接口测试、性能测试等,确定要删除吗?', delete_warning: '删除该工作空间将同步删除该工作空间下所有项目,以及项目中的所有用例、接口测试、性能测试等,确定要删除吗?',
}, },
organization: { organization: {
'create': '创建组织', create: '创建组织',
'modify': '修改组织', modify: '修改组织',
'delete': '删除组织', delete: '删除组织',
'delete_confirm': '删除该组织会关联删除该组织下的所有资源(如:相关工作空间,项目,测试用例等),确定要删除吗?', delete_confirm: '删除该组织会关联删除该组织下的所有资源(如:相关工作空间,项目,测试用例等),确定要删除吗?',
'input_name': '请输入组织名称', input_name: '请输入组织名称',
'select_organization': '请选择组织', select_organization: '请选择组织',
'search_by_name': '根据名称搜索', search_by_name: '根据名称搜索',
'special_characters_are_not_supported': '格式错误(不支持特殊字符,且不能以\'-\'开头结尾)', special_characters_are_not_supported: '格式错误(不支持特殊字符,且不能以\'-\'开头结尾)',
'none': '无组织', none: '无组织',
'select': '选择组织', select: '选择组织',
'delete_warning': '删除该组织将同步删除该组织下所有相关工作空间和相关工作空间下的所有项目,以及项目中的所有用例、接口测试、性能测试等,确定要删除吗?', delete_warning: '删除该组织将同步删除该组织下所有相关工作空间和相关工作空间下的所有项目,以及项目中的所有用例、接口测试、性能测试等,确定要删除吗?',
}, },
project: { project: {
'recent': '最近的项目', recent: '最近的项目',
'create': '创建项目', create: '创建项目',
'edit': '编辑项目', edit: '编辑项目',
'delete': '删除项目', delete: '删除项目',
'delete_confirm': '确定要删除这个项目吗?', delete_confirm: '确定要删除这个项目吗?',
'delete_tip': '删除该项目,会删除该项目下所有测试资源,确定要删除吗?', delete_tip: '删除该项目,会删除该项目下所有测试资源,确定要删除吗?',
'search_by_name': '根据名称搜索', search_by_name: '根据名称搜索',
'input_name': '请输入项目名称', input_name: '请输入项目名称',
'owning_workspace': '所属工作空间', owning_workspace: '所属工作空间',
'please_choose_workspace': '请选择工作空间', please_choose_workspace: '请选择工作空间',
'special_characters_are_not_supported': '格式错误(不支持特殊字符,且不能以\'-\'开头结尾)', special_characters_are_not_supported: '格式错误(不支持特殊字符,且不能以\'-\'开头结尾)',
}, },
member: { member: {
'create': '添加成员', create: '添加成员',
'modify': '修改成员', modify: '修改成员',
'delete_confirm': '这个用户确定要删除吗?', delete_confirm: '这个用户确定要删除吗?',
'please_choose_member': '请选择成员', please_choose_member: '请选择成员',
'search_by_name': '根据名称搜索', search_by_name: '根据名称搜索',
'modify_personal_info': '修改个人信息', modify_personal_info: '修改个人信息',
'edit_password': '修改密码', edit_password: '修改密码',
'edit_information': '编辑信息', edit_information: '编辑信息',
'input_name': '请输入名称', input_name: '请输入名称',
'input_email': '请输入邮箱', input_email: '请输入邮箱',
'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': '有效密码8-16位英文大小写字母+数字+特殊字符(可选)', password_format_is_incorrect: '有效密码8-16位英文大小写字母+数字+特殊字符(可选)',
'old_password': '旧密码', old_password: '旧密码',
'new_password': '新密码', new_password: '新密码',
'remove_member': '确定要移除该成员吗', remove_member: '确定要移除该成员吗',
'input_id_or_email': '请输入用户 ID, 或者 用户邮箱', input_id_or_email: '请输入用户 ID, 或者 用户邮箱',
'no_such_user': '无此用户信息, 请输入正确的用户 ID 或者 用户邮箱!', no_such_user: '无此用户信息, 请输入正确的用户 ID 或者 用户邮箱!',
}, },
user: { user: {
'create': '创建用户', create: '创建用户',
'modify': '修改用户', modify: '修改用户',
'input_name': '请输入用户姓名', input_name: '请输入用户姓名',
'input_id': '请输入ID', input_id: '请输入ID',
'input_email': '请输入邮箱', input_email: '请输入邮箱',
'input_password': '请输入密码', input_password: '请输入密码',
'input_phone': '请输入电话号码', input_phone: '请输入电话号码',
'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: '邮箱格式不正确',
'delete_confirm': '这个用户确定要删除吗?', delete_confirm: '这个用户确定要删除吗?',
'apikey_delete_confirm': '这个 API Key 确定要删除吗?', apikey_delete_confirm: '这个 API Key 确定要删除吗?',
'input_id_placeholder': '请输入ID (只支持数字、英文字母)' input_id_placeholder: '请输入ID (只支持数字、英文字母)'
}, },
role: { role: {
'please_choose_role': '请选择角色', please_choose_role: '请选择角色',
'admin': '系统管理员', admin: '系统管理员',
'org_admin': '组织管理员', org_admin: '组织管理员',
'test_manager': '测试经理', test_manager: '测试经理',
'test_user': '测试人员', test_user: '测试人员',
'test_viewer': 'Viewer', test_viewer: 'Viewer',
'add': '添加角色', add: '添加角色',
}, },
report: { report: {
'recent': '最近的报告', recent: '最近的报告',
'search_by_name': '根据名称搜索', search_by_name: '根据名称搜索',
'test_name': '所属测试', test_name: '所属测试',
'test_overview': '测试概览', test_overview: '测试概览',
'test_request_statistics': '请求统计', test_request_statistics: '请求统计',
'test_error_log': '错误记录', test_error_log: '错误记录',
'test_log_details': '日志详情', test_log_details: '日志详情',
'test_details': '测试详情', test_details: '测试详情',
'test_duration': '持续时间:{0} 分钟 {1} 秒', test_duration: '持续时间:{0} 分钟 {1} 秒',
'test_start_time': '开始时间', test_start_time: '开始时间',
'test_end_time': '结束时间', test_end_time: '结束时间',
'test_stop_now': '立即停止', test_stop_now: '立即停止',
'test_stop_now_confirm': '确定要立即停止当前测试吗?', test_stop_now_confirm: '确定要立即停止当前测试吗?',
'test_rerun_confirm': '确定要再次执行当前测试吗?', test_rerun_confirm: '确定要再次执行当前测试吗?',
'test_stop_success': '停止成功', test_stop_success: '停止成功',
'test_execute_again': '再次执行', test_execute_again: '再次执行',
'export': '导出', export: '导出',
'compare': '比较', compare: '比较',
'generation_error': '报告生成错误,无法查看!', generation_error: '报告生成错误,无法查看!',
'being_generated': '报告正在生成中...', being_generated: '报告正在生成中...',
'delete_confirm': '确认删除报告: ', delete_confirm: '确认删除报告: ',
'start_status': '测试处于开始状态,请稍后查看报告!', start_status: '测试处于开始状态,请稍后查看报告!',
'run_status': '测试处于运行状态,请稍后查看报告!', run_status: '测试处于运行状态,请稍后查看报告!',
'user_name': '创建人', user_name: '创建人',
'project_name': '所属项目', project_name: '所属项目',
}, },
load_test: { load_test: {
'operating': '操作', operating: '操作',
'recent': '最近的测试', recent: '最近的测试',
'search_by_name': '根据名称搜索', search_by_name: '根据名称搜索',
'project_name': '所属项目', project_name: '所属项目',
'delete_confirm': '确认删除测试: ', delete_confirm: '确认删除测试: ',
'input_name': '请输入名称', input_name: '请输入名称',
'select_project': '请选择项目', select_project: '请选择项目',
'save_and_run': '保存并执行', save_and_run: '保存并执行',
'basic_config': '场景配置', basic_config: '场景配置',
'pressure_config': '压力配置', pressure_config: '压力配置',
'advanced_config': '高级配置', advanced_config: '高级配置',
'runtime_config': '运行配置', runtime_config: '运行配置',
'is_running': '正在运行!', is_running: '正在运行!',
'test_name_is_null': '测试名称不能为空!', test_name_is_null: '测试名称不能为空!',
'project_is_null': '项目不能为空!', project_is_null: '项目不能为空!',
'jmx_is_null': '必需包含一个JMX文件且只能包含一个JMX文件', jmx_is_null: '必需包含一个JMX文件且只能包含一个JMX文件',
'file_name': '文件名', file_name: '文件名',
'file_size': '文件大小', file_size: '文件大小',
'file_type': '文件类型', file_type: '文件类型',
'file_status': '文件状态', file_status: '文件状态',
'last_modify_time': '修改时间', last_modify_time: '修改时间',
'upload_tips': '将文件拖到此处,或<em>点击上传</em>', upload_tips: '将文件拖到此处,或<em>点击上传</em>',
'upload_type': '只能上传JMX/CSV文件', upload_type: '只能上传JMX/CSV文件',
'related_file_not_found': "未找到关联的测试文件!", related_file_not_found: "未找到关联的测试文件!",
'delete_file_confirm': '确认删除文件: ', delete_file_confirm: '确认删除文件: ',
'file_size_limit': "文件个数超出限制!", file_size_limit: "文件个数超出限制!",
'delete_file': "文件已存在,请先删除同名文件!", delete_file: "文件已存在,请先删除同名文件!",
'thread_num': '并发用户数:', thread_num: '并发用户数:',
'input_thread_num': '请输入线程数', input_thread_num: '请输入线程数',
'duration': '压测时长(分钟):', duration: '压测时长(分钟):',
'input_duration': '请输入时长', input_duration: '请输入时长',
'rps_limit': 'RPS上限', rps_limit: 'RPS上限',
'input_rps_limit': '请输入限制', input_rps_limit: '请输入限制',
'ramp_up_time_within': '在', ramp_up_time_within: '在',
'ramp_up_time_minutes': '分钟内,分', ramp_up_time_minutes: '分钟内,分',
'ramp_up_time_times': '次增加并发用户', ramp_up_time_times: '次增加并发用户',
'advanced_config_error': '高级配置校验失败', advanced_config_error: '高级配置校验失败',
'domain_bind': '域名绑定', domain_bind: '域名绑定',
'domain': '域名', domain: '域名',
'enable': '是否启用', enable: '是否启用',
'ip': 'IP地址', ip: 'IP地址',
'params': '自定义属性', params: '自定义属性',
'param_name': '属性名', param_name: '属性名',
'param_value': '属性值', param_value: '属性值',
'domain_is_duplicate': '域名不能重复', domain_is_duplicate: '域名不能重复',
'param_is_duplicate': '参数名不能重复', param_is_duplicate: '参数名不能重复',
'domain_ip_is_empty': '域名和IP不能为空', domain_ip_is_empty: '域名和IP不能为空',
'param_name_value_is_empty': '参数名和参数值不能为空', param_name_value_is_empty: '参数名和参数值不能为空',
'connect_timeout': '建立连接超时时间', connect_timeout: '建立连接超时时间',
'custom_http_code': '自定义 HTTP 响应成功状态码', custom_http_code: '自定义 HTTP 响应成功状态码',
'separated_by_commas': '按逗号分隔', separated_by_commas: '按逗号分隔',
'create': '创建测试', create: '创建测试',
'select_resource_pool': '请选择资源池', select_resource_pool: '请选择资源池',
'resource_pool_is_null': '资源池为空', resource_pool_is_null: '资源池为空',
'download_log_file': '下载完整日志文件', download_log_file: '下载完整日志文件',
'pressure_prediction_chart': '压力预估图', pressure_prediction_chart: '压力预估图',
'user_name': '创建人', user_name: '创建人',
'special_characters_are_not_supported': '测试名称不支持特殊字符', special_characters_are_not_supported: '测试名称不支持特殊字符',
'pressure_config_params_is_empty': '压力配置参数不能为空!' pressure_config_params_is_empty: '压力配置参数不能为空!'
}, },
api_test: { api_test: {
creator: "创建人", creator: "创建人",
@ -562,65 +600,65 @@ export default {
} }
}, },
test_resource_pool: { test_resource_pool: {
'type': '类型', type: '类型',
'enable_disable': '启用/禁用', enable_disable: '启用/禁用',
'search_by_name': '根据名称搜索', search_by_name: '根据名称搜索',
'create_resource_pool': '创建资源池', create_resource_pool: '创建资源池',
'update_resource_pool': '修改资源池', update_resource_pool: '修改资源池',
'select_pool_type': '选择资源类型', select_pool_type: '选择资源类型',
'max_threads': '最大并发数', max_threads: '最大并发数',
'input_pool_name': '请输入资源池名称', input_pool_name: '请输入资源池名称',
'pool_name_valid': '资源池名称不支持特殊字符', pool_name_valid: '资源池名称不支持特殊字符',
'cannot_remove_all_node': '不能删除所有独立节点', cannot_remove_all_node: '不能删除所有独立节点',
'cannot_empty': '资源池不能为空', cannot_empty: '资源池不能为空',
'fill_the_data': '请完善数据', fill_the_data: '请完善数据',
'delete_prompt': '此操作将永久删除该资源池, 是否继续?', delete_prompt: '此操作将永久删除该资源池, 是否继续?',
'status_change_success': '状态修改成功!', status_change_success: '状态修改成功!',
'status_change_failed': '状态修改失败, 校验不通过!', status_change_failed: '状态修改失败, 校验不通过!',
'check_in': '校验中', check_in: '校验中',
}, },
system_parameter_setting: { system_parameter_setting: {
'mailbox_service_settings': '邮件设置', mailbox_service_settings: '邮件设置',
'ldap_setting': 'LDAP设置', ldap_setting: 'LDAP设置',
'test_connection': '测试连接', test_connection: '测试连接',
'SMTP_host': 'SMTP主机', SMTP_host: 'SMTP主机',
'SMTP_port': 'SMTP端口', SMTP_port: 'SMTP端口',
'SMTP_account': 'SMTP账户', SMTP_account: 'SMTP账户',
'SMTP_password': 'SMTP密码', SMTP_password: 'SMTP密码',
'SSL': '开启SSL(如果SMTP端口是465通常需要启用SSL)', SSL: '开启SSL(如果SMTP端口是465通常需要启用SSL)',
'TLS': '开启TLS(如果SMTP端口是587通常需要启用TLS)', TLS: '开启TLS(如果SMTP端口是587通常需要启用TLS)',
'SMTP': '是否匿名 SMTP', SMTP: '是否匿名 SMTP',
}, },
i18n: { i18n: {
'home': '首页' home: '首页'
}, },
ldap: { ldap: {
'url': 'LDAP地址', url: 'LDAP地址',
'dn': '绑定DN', dn: '绑定DN',
'password': '密码', password: '密码',
'ou': '用户OU', ou: '用户OU',
'filter': '用户过滤器', filter: '用户过滤器',
'mapping': 'LDAP属性映射', mapping: 'LDAP属性映射',
'open': '启用LDAP认证', open: '启用LDAP认证',
'input_url': '请输入LDAP地址', input_url: '请输入LDAP地址',
'input_dn': '请输入DN', input_dn: '请输入DN',
'input_password': '请输入密码', input_password: '请输入密码',
'input_ou': '请输入用户OU', input_ou: '请输入用户OU',
'input_filter': '请输入用户过滤器', input_filter: '请输入用户过滤器',
'input_mapping': '请输入LDAP属性映射', input_mapping: '请输入LDAP属性映射',
'input_username': '请输入用户名', input_username: '请输入用户名',
'input_url_placeholder': '请输入LDAP地址 (如 ldap://localhost:389)', input_url_placeholder: '请输入LDAP地址 (如 ldap://localhost:389)',
'input_ou_placeholder': '输入用户OU (使用|分隔各OU)', input_ou_placeholder: '输入用户OU (使用|分隔各OU)',
'input_filter_placeholder': '输入过滤器 [可能的选项是cn或uid或sAMAccountName={0}, 如:(uid={0})]', input_filter_placeholder: '输入过滤器 [可能的选项是cn或uid或sAMAccountName={0}, 如:(uid={0})]',
'test_connect': '测试连接', test_connect: '测试连接',
'test_login': '测试登录', test_login: '测试登录',
'edit': '编辑', edit: '编辑',
'login_success': '登录成功', login_success: '登录成功',
'url_cannot_be_empty': 'LDAP 地址不能为空', url_cannot_be_empty: 'LDAP 地址不能为空',
'dn_cannot_be_empty': 'LDAP DN不能为空', dn_cannot_be_empty: 'LDAP DN不能为空',
'ou_cannot_be_empty': 'LDAP OU不能为空', ou_cannot_be_empty: 'LDAP OU不能为空',
'filter_cannot_be_empty': 'LDAP 用户过滤器不能为空', filter_cannot_be_empty: 'LDAP 用户过滤器不能为空',
'password_cannot_be_empty': 'LDAP 密码不能为空', password_cannot_be_empty: 'LDAP 密码不能为空',
}, },
schedule: { schedule: {
not_set: "未设置", not_set: "未设置",

View File

@ -1,286 +1,324 @@
export default { export default {
commons: { commons: {
'delete_cancelled': '已取消删除', delete_cancelled: '已取消删除',
'workspace': '工作空間', workspace: '工作空間',
'organization': '組織', organization: '組織',
'setting': '設置', setting: '設置',
'project': '項目', project: '項目',
'about_us': '關於', about_us: '關於',
current_project: '當前項目', current_project: '當前項目',
'name': '名稱', name: '名稱',
'description': '描述', description: '描述',
'clear': '清空', clear: '清空',
'save': '保存', save: '保存',
'save_success': '保存成功', save_success: '保存成功',
'delete_success': '刪除成功', delete_success: '刪除成功',
'copy_success': '複製成功', copy_success: '複製成功',
'modify_success': '修改成功', modify_success: '修改成功',
'delete_cancel': '已取消刪除', delete_cancel: '已取消刪除',
'confirm': '確定', confirm: '確定',
'cancel': '取消', cancel: '取消',
'prompt': '提示', prompt: '提示',
'operating': '操作', operating: '操作',
'input_limit': '長度在 {0} 到 {1} 個字符', input_limit: '長度在 {0} 到 {1} 個字符',
'login': '登錄', login: '登錄',
'welcome': '歡迎回來,請輸入用戶名和密碼登錄MeterSphere', welcome: '歡迎回來,請輸入用戶名和密碼登錄MeterSphere',
'username': '用戶名', username: '用戶名',
'password': '密碼', password: '密碼',
'input_username': '請輸入用戶名', input_username: '請輸入用戶名',
'input_password': '請輸入密碼', input_password: '請輸入密碼',
'test': '測試', test: '測試',
'create_time': '創建時間', create_time: '創建時間',
'update_time': '更新時間', update_time: '更新時間',
'add': '添加', add: '添加',
'member': '成員', member: '成員',
'email': '郵箱', email: '郵箱',
'phone': '電話', phone: '電話',
'role': '角色', role: '角色',
'personal_info': '個人信息', personal_info: '個人信息',
'status': '狀態', status: '狀態',
'show_all': '顯示全部', show_all: '顯示全部',
'show': '顯示', show: '顯示',
'report': '報告', report: '報告',
'user': '用戶', user: '用戶',
'system': '系統', system: '系統',
'personal_setting': '個人設置', personal_setting: '個人設置',
'test_resource_pool': '測試資源池', test_resource_pool: '測試資源池',
'system_setting': '系統設置', system_setting: '系統設置',
'api': '接口測試', api: '接口測試',
'performance': '性能測試', performance: '性能測試',
'functional': '功能測試', functional: '功能測試',
'input_content': '請輸入內容', input_content: '請輸入內容',
'create': '新建', create: '新建',
'edit': '編輯', edit: '編輯',
'copy': '複製', copy: '複製',
'refresh': '刷新', refresh: '刷新',
'remark': '備註', remark: '備註',
'delete': '刪除', delete: '刪除',
'not_filled': '未填寫', not_filled: '未填寫',
'please_select': '請選擇', please_select: '請選擇',
'search_by_name': '根據名稱搜索', search_by_name: '根據名稱搜索',
'personal_information': '個人信息', personal_information: '個人信息',
'exit_system': '退出系統', exit_system: '退出系統',
'verification': '驗證', verification: '驗證',
'title': '標題', title: '標題',
'custom': '自定義', custom: '自定義',
'select_date': '選擇日期', select_date: '選擇日期',
'calendar_heatmap': '測試日曆', calendar_heatmap: '測試日曆',
'months_1': '一月', months_1: '一月',
'months_2': '二月', months_2: '二月',
'months_3': '三月', months_3: '三月',
'months_4': '四月', months_4: '四月',
'months_5': '五月', months_5: '五月',
'months_6': '六月', months_6: '六月',
'months_7': '七月', months_7: '七月',
'months_8': '八月', months_8: '八月',
'months_9': '九月', months_9: '九月',
'months_10': '十月', months_10: '十月',
'months_11': '十一月', months_11: '十一月',
'months_12': '十二月', months_12: '十二月',
'weeks_0': '周日', weeks_0: '周日',
'weeks_1': '周一', weeks_1: '周一',
'weeks_2': '周二', weeks_2: '周二',
'weeks_3': '周三', weeks_3: '周三',
'weeks_4': '周四', weeks_4: '周四',
'weeks_5': '周五', weeks_5: '周五',
'weeks_6': '周六', weeks_6: '周六',
'test_unit': '測試', test_unit: '測試',
'system_parameter_setting': '系統參數設置', system_parameter_setting: '系統參數設置',
'connection_successful': '連接成功', connection_successful: '連接成功',
'connection_failed': '連接失敗', connection_failed: '連接失敗',
'save_failed': '保存失敗', save_failed: '保存失敗',
'host_cannot_be_empty': '主機不能為空', host_cannot_be_empty: '主機不能為空',
'port_cannot_be_empty': '埠號不能為空', port_cannot_be_empty: '埠號不能為空',
'account_cannot_be_empty': '帳戶不能為空', account_cannot_be_empty: '帳戶不能為空',
'remove': '移除', remove: '移除',
'remove_cancel': '移除取消', remove_cancel: '移除取消',
'remove_success': '移除成功', remove_success: '移除成功',
'tips': '认認證資訊已過期,請重新登入', tips: '认認證資訊已過期,請重新登入',
'not_performed_yet': '尚未執行', not_performed_yet: '尚未執行',
'incorrect_input': '輸入內容不正確', incorrect_input: '輸入內容不正確',
'delete_confirm': '請輸入以下內容,確認刪除:', delete_confirm: '請輸入以下內容,確認刪除:',
'input_name': '請輸入名稱', input_name: '請輸入名稱',
'formatErr': '格式錯誤' formatErr: '格式錯誤',
date: {
select_date: '選擇日期',
start_date: '開始日期',
end_date: '結束日期',
select_date_time: '選擇日期時間',
start_date_time: '開始日期時間',
end_date_time: '結束日期時間',
range_separator: "至",
},
trigger_mode: {
name: "觸發方式",
manual: "手動觸發",
schedule: "定時任務",
api: "API調用"
},
adv_search: {
title: '高級搜索',
combine: '組合查詢',
test: "所屬測試",
project: "所屬項目",
search: "查詢",
reset: "重置",
and: '所有',
or: '任意一個',
operators: {
like: "包含",
not_like: "不包含",
in: "屬於",
not_in: "不屬於",
gt: "大於",
ge: "大於等於",
lt: "小於",
le: "小於等於",
equals: "等於",
between: "之間",
current_user: "是當前用戶"
}
}
}, },
workspace: { workspace: {
'create': '創建工作空間', create: '創建工作空間',
'update': '修改工作空間', update: '修改工作空間',
'delete': '刪除工作空間', delete: '刪除工作空間',
'delete_confirm': '删除該工作空間會關聯删除該工作空間下的所有資源(如:相關項目,測試用例等),確定要删除嗎?', delete_confirm: '删除該工作空間會關聯删除該工作空間下的所有資源(如:相關項目,測試用例等),確定要删除嗎?',
'add': '添加工作空間', add: '添加工作空間',
'input_name': '請輸入工作空間名稱', input_name: '請輸入工作空間名稱',
'search_by_name': '根據名稱搜索', search_by_name: '根據名稱搜索',
'organization_name': '所屬組織', organization_name: '所屬組織',
'please_choose_organization': '請選擇組織', please_choose_organization: '請選擇組織',
'please_select_a_workspace_first': '請先選擇工作空間! ', please_select_a_workspace_first: '請先選擇工作空間! ',
'none': '無工作空間', none: '無工作空間',
'select': '選擇工作空間', select: '選擇工作空間',
'special_characters_are_not_supported': '格式錯誤(不支持特殊字符,且不能以\'-\'開頭結尾)', special_characters_are_not_supported: '格式錯誤(不支持特殊字符,且不能以\'-\'開頭結尾)',
'delete_warning': '删除该工作空间将同步删除该工作空间下所有项目,以及项目中的所有用例、接口测试、性能测试等,确定要删除吗?', delete_warning: '删除该工作空间将同步删除该工作空间下所有项目,以及项目中的所有用例、接口测试、性能测试等,确定要删除吗?',
}, },
organization: { organization: {
'create': '創建組織', create: '創建組織',
'modify': '修改組織', modify: '修改組織',
'delete': '刪除組織', delete: '刪除組織',
'delete_confirm': '删除該組織會關聯删除該組織下的所有資源(如:相關工作空間,項目,測試用例等),確定要删除嗎?', delete_confirm: '删除該組織會關聯删除該組織下的所有資源(如:相關工作空間,項目,測試用例等),確定要删除嗎?',
'input_name': '請輸入組織名稱', input_name: '請輸入組織名稱',
'select_organization': '請選擇組織', select_organization: '請選擇組織',
'search_by_name': '根據名稱搜索', search_by_name: '根據名稱搜索',
'special_characters_are_not_supported': 'Incorrect format (special characters are not supported and cannot end with \'-\')', special_characters_are_not_supported: 'Incorrect format (special characters are not supported and cannot end with \'-\')',
'none': '無組織', none: '無組織',
'select': '選擇組織', select: '選擇組織',
'delete_warning': '删除该组织将同步删除该组织下所有相关工作空间和相关工作空间下的所有项目,以及项目中的所有用例、接口测试、性能测试等,确定要删除吗?', delete_warning: '删除该组织将同步删除该组织下所有相关工作空间和相关工作空间下的所有项目,以及项目中的所有用例、接口测试、性能测试等,确定要删除吗?',
}, },
project: { project: {
'recent': '最近的項目', recent: '最近的項目',
'create': '創建項目', create: '創建項目',
'edit': '編輯項目', edit: '編輯項目',
'delete': '刪除項目', delete: '刪除項目',
'delete_confirm': '確定要刪除這個項目嗎?', delete_confirm: '確定要刪除這個項目嗎?',
'delete_tip': '删除該項目,會删除該項目下所有測試資源,確定要删除嗎?', delete_tip: '删除該項目,會删除該項目下所有測試資源,確定要删除嗎?',
'search_by_name': '根據名稱搜索', search_by_name: '根據名稱搜索',
'input_name': '請輸入項目名稱', input_name: '請輸入項目名稱',
'owning_workspace': '所屬工作空間', owning_workspace: '所屬工作空間',
'please_choose_workspace': '請選擇工作空間', please_choose_workspace: '請選擇工作空間',
'special_characters_are_not_supported': '格式錯誤(不支持特殊字符,且不能以\'-\'開頭結尾)', special_characters_are_not_supported: '格式錯誤(不支持特殊字符,且不能以\'-\'開頭結尾)',
}, },
member: { member: {
'create': '添加成員', create: '添加成員',
'modify': '修改成員', modify: '修改成員',
'delete_confirm': '這個用戶確定要刪除嗎?', delete_confirm: '這個用戶確定要刪除嗎?',
'please_choose_member': '請選擇成員', please_choose_member: '請選擇成員',
'search_by_name': '根據名稱搜索', search_by_name: '根據名稱搜索',
'modify_personal_info': '修改個人信息', modify_personal_info: '修改個人信息',
'edit_password': '修改密碼', edit_password: '修改密碼',
'edit_information': '編輯信息', edit_information: '編輯信息',
'input_name': '請輸入名稱', input_name: '請輸入名稱',
'input_email': '請輸入郵箱', input_email: '請輸入郵箱',
'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': '有效密碼8-16比特英文大小寫字母+數位+特殊字元(可選)', password_format_is_incorrect: '有效密碼8-16比特英文大小寫字母+數位+特殊字元(可選)',
'old_password': '舊密碼', old_password: '舊密碼',
'new_password': '新密碼', new_password: '新密碼',
'remove_member': '確定要移除該成員嗎', remove_member: '確定要移除該成員嗎',
'input_id_or_email': '請輸入用戶 ID, 或者 用戶郵箱', input_id_or_email: '請輸入用戶 ID, 或者 用戶郵箱',
'no_such_user': '無此用戶信息, 請輸入正確的用戶 ID 或者 用戶郵箱!', no_such_user: '無此用戶信息, 請輸入正確的用戶 ID 或者 用戶郵箱!',
}, },
user: { user: {
'create': '創建用戶', create: '創建用戶',
'modify': '修改用戶', modify: '修改用戶',
'input_name': '請輸入用戶名', input_name: '請輸入用戶名',
'input_id': '請輸入ID', input_id: '請輸入ID',
'input_email': '請輸入郵箱', input_email: '請輸入郵箱',
'input_password': '請輸入密碼', input_password: '請輸入密碼',
'input_phone': '請輸入電話號碼', input_phone: '請輸入電話號碼',
'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: '郵箱格式不正確',
'delete_confirm': '這個用戶確定要刪除嗎?', delete_confirm: '這個用戶確定要刪除嗎?',
'apikey_delete_confirm': '這個 API Key 確定要刪除嗎?', apikey_delete_confirm: '這個 API Key 確定要刪除嗎?',
'input_id_placeholder': '請輸入ID (只支持數字、英文字母)' input_id_placeholder: '請輸入ID (只支持數字、英文字母)'
}, },
role: { role: {
'please_choose_role': '請選擇角色', please_choose_role: '請選擇角色',
'admin': '系統管理員', admin: '系統管理員',
'org_admin': '組織管理員', org_admin: '組織管理員',
'test_manager': '測試經理', test_manager: '測試經理',
'test_user': '測試人員', test_user: '測試人員',
'test_viewer': 'Viewer', test_viewer: 'Viewer',
'add': '添加角色', add: '添加角色',
}, },
report: { report: {
'name': '項目名稱', name: '項目名稱',
'recent': '最近的報告', recent: '最近的報告',
'search_by_name': '根據名稱搜索', search_by_name: '根據名稱搜索',
'test_name': '所屬測試', test_name: '所屬測試',
'test_overview': '測試概覽', test_overview: '測試概覽',
'test_request_statistics': '請求統計', test_request_statistics: '請求統計',
'test_error_log': '錯誤記錄', test_error_log: '錯誤記錄',
'test_log_details': '日誌詳情', test_log_details: '日誌詳情',
'test_details': '測試詳情', test_details: '測試詳情',
'test_duration': '持續時間:{0} 分鐘 {1} 秒', test_duration: '持續時間:{0} 分鐘 {1} 秒',
'test_start_time': '開始時間', test_start_time: '開始時間',
'test_end_time': '結束時間', test_end_time: '結束時間',
'test_stop_now': '立即停止', test_stop_now: '立即停止',
'test_stop_now_confirm': '確定要立即停止當前測試嗎?', test_stop_now_confirm: '確定要立即停止當前測試嗎?',
'test_rerun_confirm': '確定要再次執行當前測試嗎?', test_rerun_confirm: '確定要再次執行當前測試嗎?',
'test_stop_success': '停止成功', test_stop_success: '停止成功',
'test_execute_again': '再次執行', test_execute_again: '再次執行',
'export': '導出', export: '導出',
'compare': '比較', compare: '比較',
'generation_error': '報告生成錯誤,無法查看!', generation_error: '報告生成錯誤,無法查看!',
'being_generated': '報告正在生成中...', being_generated: '報告正在生成中...',
'delete_confirm': '確認刪除報告: ', delete_confirm: '確認刪除報告: ',
'start_status': '測試處於開始狀態,請稍後查看報告!', start_status: '測試處於開始狀態,請稍後查看報告!',
'run_status': '測試處於運行狀態,請稍後查看報告!', run_status: '測試處於運行狀態,請稍後查看報告!',
'user_name': '創建人', user_name: '創建人',
'project_name': '所屬項目' project_name: '所屬項目'
}, },
load_test: { load_test: {
'operating': '操作', operating: '操作',
'recent': '最近的測試', recent: '最近的測試',
'search_by_name': '根據名稱搜索', search_by_name: '根據名稱搜索',
'project_name': '所屬項目', project_name: '所屬項目',
'delete_confirm': '確認刪除測試: ', delete_confirm: '確認刪除測試: ',
'input_name': '請輸入名稱', input_name: '請輸入名稱',
'select_project': '請選擇項目', select_project: '請選擇項目',
'save_and_run': '保存並執行', save_and_run: '保存並執行',
'basic_config': '場景配置', basic_config: '場景配置',
'pressure_config': '壓力配置', pressure_config: '壓力配置',
'advanced_config': '高級配置', advanced_config: '高級配置',
'runtime_config': '運行配置', runtime_config: '運行配置',
'is_running': '正在運行! ', is_running: '正在運行! ',
'test_name_is_null': '測試名稱不能為空! ', test_name_is_null: '測試名稱不能為空! ',
'project_is_null': '項目不能為空! ', project_is_null: '項目不能為空! ',
'jmx_is_null': '必需包含一個JMX文件且只能包含一個JMX文件', jmx_is_null: '必需包含一個JMX文件且只能包含一個JMX文件',
'file_name': '文件名', file_name: '文件名',
'file_size': '文件大小', file_size: '文件大小',
'file_type': '文件類型', file_type: '文件類型',
'file_status': '文件狀態', file_status: '文件狀態',
'last_modify_time': '修改時間', last_modify_time: '修改時間',
'upload_tips': '將文件拖到此處,或<em>點擊上傳</em>', upload_tips: '將文件拖到此處,或<em>點擊上傳</em>',
'upload_type': '只能上傳JMX/CSV文件', upload_type: '只能上傳JMX/CSV文件',
'related_file_not_found': "未找到關聯的測試文件!", related_file_not_found: "未找到關聯的測試文件!",
'delete_file_confirm': '確認刪除文件: ', delete_file_confirm: '確認刪除文件: ',
'file_size_limit': "文件個數超出限制!", file_size_limit: "文件個數超出限制!",
'delete_file': "文件已存在,請先刪除同名文件!", delete_file: "文件已存在,請先刪除同名文件!",
'thread_num': '並髮用戶數:', thread_num: '並髮用戶數:',
'input_thread_num': '請輸入線程數', input_thread_num: '請輸入線程數',
'duration': '壓測時長(分鐘):', duration: '壓測時長(分鐘):',
'input_duration': '請輸入時長', input_duration: '請輸入時長',
'rps_limit': 'RPS上限', rps_limit: 'RPS上限',
'input_rps_limit': '請輸入限制', input_rps_limit: '請輸入限制',
'ramp_up_time_within': '在', ramp_up_time_within: '在',
'ramp_up_time_minutes': '分鐘內,分', ramp_up_time_minutes: '分鐘內,分',
'ramp_up_time_times': '次增加並髮用戶', ramp_up_time_times: '次增加並髮用戶',
'advanced_config_error': '高級配置校驗失敗', advanced_config_error: '高級配置校驗失敗',
'domain_bind': '域名綁定', domain_bind: '域名綁定',
'domain': '域名', domain: '域名',
'enable': '是否啟用', enable: '是否啟用',
'ip': 'IP地址', ip: 'IP地址',
'params': '自定義屬性', params: '自定義屬性',
'param_name': '屬性名', param_name: '屬性名',
'param_value': '屬性值', param_value: '屬性值',
'domain_is_duplicate': '域名不能重複', domain_is_duplicate: '域名不能重複',
'param_is_duplicate': '參數名不能重複', param_is_duplicate: '參數名不能重複',
'domain_ip_is_empty': '域名和IP不能為空', domain_ip_is_empty: '域名和IP不能為空',
'param_name_value_is_empty': '參數名和參數值不能為空', param_name_value_is_empty: '參數名和參數值不能為空',
'connect_timeout': '建立連接超時時間', connect_timeout: '建立連接超時時間',
'custom_http_code': '自定義 HTTP 響應成功狀態碼', custom_http_code: '自定義 HTTP 響應成功狀態碼',
'separated_by_commas': '按逗號分隔', separated_by_commas: '按逗號分隔',
'create': '創建測試', create: '創建測試',
'select_resource_pool': '請選擇資源池', select_resource_pool: '請選擇資源池',
'resource_pool_is_null': '資源池為空', resource_pool_is_null: '資源池為空',
'download_log_file': '下載完整日誌文件', download_log_file: '下載完整日誌文件',
'pressure_prediction_chart': '壓力預估圖', pressure_prediction_chart: '壓力預估圖',
'user_name': '創建人', user_name: '創建人',
'special_characters_are_not_supported': '測試名稱不支持特殊字符', special_characters_are_not_supported: '測試名稱不支持特殊字符',
'pressure_config_params_is_empty': '壓力配置參數不能為空!' pressure_config_params_is_empty: '壓力配置參數不能為空!'
}, },
api_test: { api_test: {
title: "測試", creator: "創建人",
save_and_run: "保存並執行", save_and_run: "保存並執行",
run: "執行", run: "執行",
running: "正在執行", running: "正在執行",
@ -562,65 +600,65 @@ export default {
} }
}, },
test_resource_pool: { test_resource_pool: {
'type': '類型', type: '類型',
'enable_disable': '啟用/禁用', enable_disable: '啟用/禁用',
'search_by_name': '根據名稱搜索', search_by_name: '根據名稱搜索',
'create_resource_pool': '創建資源池', create_resource_pool: '創建資源池',
'update_resource_pool': '修改資源池', update_resource_pool: '修改資源池',
'select_pool_type': '選擇資源類型', select_pool_type: '選擇資源類型',
'max_threads': '最大並發數', max_threads: '最大並發數',
'input_pool_name': '請輸入資源池名稱', input_pool_name: '請輸入資源池名稱',
'pool_name_valid': '資源池名稱不支持特殊字符', pool_name_valid: '資源池名稱不支持特殊字符',
'cannot_remove_all_node': '不能刪除所有獨立節點', cannot_remove_all_node: '不能刪除所有獨立節點',
'cannot_empty': '資源池不能為空', cannot_empty: '資源池不能為空',
'fill_the_data': '請完善數據', fill_the_data: '請完善數據',
'delete_prompt': '此操作將永久刪除該資源池, 是否繼續?', delete_prompt: '此操作將永久刪除該資源池, 是否繼續?',
'status_change_success': '狀態修改成功!', status_change_success: '狀態修改成功!',
'status_change_failed': '狀態修改失敗, 校驗不通過!', status_change_failed: '狀態修改失敗, 校驗不通過!',
'check_in': '校驗中', check_in: '校驗中',
}, },
system_parameter_setting: { system_parameter_setting: {
'mailbox_service_settings': '郵件設置', mailbox_service_settings: '郵件設置',
'ldap_setting': 'LDAP設置', ldap_setting: 'LDAP設置',
'test_connection': '測試連結', test_connection: '測試連結',
'SMTP_host': 'SMTP主機', SMTP_host: 'SMTP主機',
'SMTP_port': 'SMTP埠', SMTP_port: 'SMTP埠',
'SMTP_account': 'SMTP帳戶', SMTP_account: 'SMTP帳戶',
'SMTP_password': 'SMTP密碼', SMTP_password: 'SMTP密碼',
'SSL': '開啟SSL如果SMTP埠是465通常需要啟用SSL', SSL: '開啟SSL如果SMTP埠是465通常需要啟用SSL',
'TLS': '開啟TLS如果SMTP埠是587通常需要啟用TLS', TLS: '開啟TLS如果SMTP埠是587通常需要啟用TLS',
'SMTP': '是否匿名 SMTP', SMTP: '是否匿名 SMTP',
}, },
i18n: { i18n: {
'home': '首頁' home: '首頁'
}, },
ldap: { ldap: {
'url': 'LDAP地址', url: 'LDAP地址',
'dn': '綁定DN', dn: '綁定DN',
'password': '密碼', password: '密碼',
'ou': '用戶OU', ou: '用戶OU',
'filter': '用戶過濾器', filter: '用戶過濾器',
'mapping': 'LDAP屬性映射', mapping: 'LDAP屬性映射',
'open': '啟用LDAP認證', open: '啟用LDAP認證',
'input_url': '請輸入LDAP地址', input_url: '請輸入LDAP地址',
'input_dn': '請輸入DN', input_dn: '請輸入DN',
'input_password': '請輸入密碼', input_password: '請輸入密碼',
'input_ou': '請輸入用戶OU', input_ou: '請輸入用戶OU',
'input_filter': '請輸入用戶過濾器', input_filter: '請輸入用戶過濾器',
'input_mapping': '請輸入LDAP屬性映射', input_mapping: '請輸入LDAP屬性映射',
'input_username': '請輸入用戶名', input_username: '請輸入用戶名',
'input_url_placeholder': '請輸入LDAP地址 (如 ldap://localhost:389)', input_url_placeholder: '請輸入LDAP地址 (如 ldap://localhost:389)',
'input_ou_placeholder': '輸入用戶OU (使用|分隔各OU)', input_ou_placeholder: '輸入用戶OU (使用|分隔各OU)',
'input_filter_placeholder': '輸入過濾器 [可能的選項是cn或uid或sAMAccountName={0}, 如:(uid={0})]', input_filter_placeholder: '輸入過濾器 [可能的選項是cn或uid或sAMAccountName={0}, 如:(uid={0})]',
'test_connect': '測試連接', test_connect: '測試連接',
'test_login': '測試登錄', test_login: '測試登錄',
'edit': '編輯', edit: '編輯',
'login_success': '登錄成功', login_success: '登錄成功',
'url_cannot_be_empty': 'LDAP 地址不能為空', url_cannot_be_empty: 'LDAP 地址不能為空',
'dn_cannot_be_empty': 'LDAP DN不能為空', dn_cannot_be_empty: 'LDAP DN不能為空',
'ou_cannot_be_empty': 'LDAP OU不能為空', ou_cannot_be_empty: 'LDAP OU不能為空',
'filter_cannot_be_empty': 'LDAP 用戶過濾器不能為空', filter_cannot_be_empty: 'LDAP 用戶過濾器不能為空',
'password_cannot_be_empty': 'LDAP 密碼不能為空', password_cannot_be_empty: 'LDAP 密碼不能為空',
}, },
schedule: { schedule: {
not_set: "未設置", not_set: "未設置",

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="container" v-if="ready"> <div class="container" v-loading="result.loading" v-if="ready">
<el-row type="flex"> <el-row type="flex">
<el-col :span="12"> <el-col :span="12">
<el-form :model="form" :rules="rules" ref="form"> <el-form :model="form" :rules="rules" ref="form">
@ -17,12 +17,13 @@
<div class="form"> <div class="form">
<el-form-item v-slot:default> <el-form-item v-slot:default>
<el-radio-group v-model="form.authenticate"> <el-radio-group v-model="form.authenticate">
<el-radio label="ldap" size="mini">LDAP</el-radio> <el-radio label="LDAP" size="mini">LDAP</el-radio>
<el-radio label="normal" size="mini">普通登录</el-radio> <el-radio label="LOCAL" size="mini">普通登录</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item prop="username"> <el-form-item prop="username">
<el-input v-model="form.username" :placeholder="$t('commons.login_username')" autofocus autocomplete="off"/> <el-input v-model="form.username" :placeholder="$t('commons.login_username')" autofocus
autocomplete="off"/>
</el-form-item> </el-form-item>
<el-form-item prop="password"> <el-form-item prop="password">
<el-input v-model="form.password" :placeholder="$t('commons.password')" show-password autocomplete="off" <el-input v-model="form.password" :placeholder="$t('commons.password')" show-password autocomplete="off"
@ -64,10 +65,11 @@
} }
};*/ };*/
return { return {
result: {},
form: { form: {
username: '', username: '',
password: '', password: '',
authenticate: 'normal' authenticate: 'LOCAL'
}, },
rules: { rules: {
username: [ username: [
@ -113,10 +115,10 @@
this.$refs[form].validate((valid) => { this.$refs[form].validate((valid) => {
if (valid) { if (valid) {
switch (this.form.authenticate) { switch (this.form.authenticate) {
case "normal": case "LOCAL":
this.normalLogin(); this.normalLogin();
break; break;
case "ldap": case "LDAP":
this.ldapLogin(); this.ldapLogin();
break; break;
default: default:
@ -128,13 +130,13 @@
}); });
}, },
normalLogin() { normalLogin() {
this.$post("signin", this.form, response => { this.result = this.$post("signin", this.form, response => {
saveLocalStorage(response); saveLocalStorage(response);
this.getLanguage(response.data.language); this.getLanguage(response.data.language);
}); });
}, },
ldapLogin() { ldapLogin() {
this.$post("ldap/signin", this.form, response => { this.result = this.$post("ldap/signin", this.form, response => {
saveLocalStorage(response); saveLocalStorage(response);
this.getLanguage(response.data.language); this.getLanguage(response.data.language);
}); });

View File

@ -1,26 +1,27 @@
module.exports = { module.exports = {
productionSourceMap: true, productionSourceMap: true,
configureWebpack: { configureWebpack: {
devtool: 'source-map' devtool: 'source-map'
}, },
devServer: { devServer: {
proxy: { port: 8080,
['^(?!/login)']: { proxy: {
target: 'http://localhost:8081', ['^(?!/login)']: {
ws: true, target: 'http://localhost:8081',
} ws: true,
} }
},
pages: {
business: {
entry: "src/business/main.js",
template: "src/business/index.html",
filename: "index.html"
},
login: {
entry: "src/login/login.js",
template: "src/login/login.html",
filename: "login.html"
}
} }
},
pages: {
business: {
entry: "src/business/main.js",
template: "src/business/index.html",
filename: "index.html"
},
login: {
entry: "src/login/login.js",
template: "src/login/login.html",
filename: "login.html"
}
}
}; };