Merge branch 'v1.1'
This commit is contained in:
commit
15798a7726
|
@ -44,6 +44,11 @@
|
||||||
<artifactId>spring-boot-starter</artifactId>
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
@ -126,10 +131,6 @@
|
||||||
<version>1.2.72</version>
|
<version>1.2.72</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-simple</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<!-- openapi -->
|
<!-- openapi -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springdoc</groupId>
|
<groupId>org.springdoc</groupId>
|
||||||
|
|
|
@ -4,13 +4,17 @@ import io.metersphere.config.JmeterProperties;
|
||||||
import io.metersphere.config.KafkaProperties;
|
import io.metersphere.config.KafkaProperties;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
|
import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.boot.web.servlet.ServletComponentScan;
|
import org.springframework.boot.web.servlet.ServletComponentScan;
|
||||||
import org.springframework.context.annotation.PropertySource;
|
import org.springframework.context.annotation.PropertySource;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
@SpringBootApplication(exclude = {QuartzAutoConfiguration.class})
|
@SpringBootApplication(exclude = {
|
||||||
|
QuartzAutoConfiguration.class,
|
||||||
|
LdapAutoConfiguration.class
|
||||||
|
})
|
||||||
@ServletComponentScan
|
@ServletComponentScan
|
||||||
@EnableConfigurationProperties({
|
@EnableConfigurationProperties({
|
||||||
KafkaProperties.class,
|
KafkaProperties.class,
|
||||||
|
|
|
@ -48,6 +48,7 @@ public class ShiroConfig implements EnvironmentAware {
|
||||||
filterChainDefinitionMap.put("/", "anon");
|
filterChainDefinitionMap.put("/", "anon");
|
||||||
filterChainDefinitionMap.put("/signin", "anon");
|
filterChainDefinitionMap.put("/signin", "anon");
|
||||||
filterChainDefinitionMap.put("/ldap/signin", "anon");
|
filterChainDefinitionMap.put("/ldap/signin", "anon");
|
||||||
|
filterChainDefinitionMap.put("/ldap/open", "anon");
|
||||||
filterChainDefinitionMap.put("/isLogin", "anon");
|
filterChainDefinitionMap.put("/isLogin", "anon");
|
||||||
filterChainDefinitionMap.put("/css/**", "anon");
|
filterChainDefinitionMap.put("/css/**", "anon");
|
||||||
filterChainDefinitionMap.put("/js/**", "anon");
|
filterChainDefinitionMap.put("/js/**", "anon");
|
||||||
|
|
|
@ -7,6 +7,7 @@ import com.alibaba.excel.exception.ExcelAnalysisException;
|
||||||
import com.alibaba.excel.util.StringUtils;
|
import com.alibaba.excel.util.StringUtils;
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
import io.metersphere.excel.domain.ExcelErrData;
|
import io.metersphere.excel.domain.ExcelErrData;
|
||||||
|
import io.metersphere.excel.domain.TestCaseExcelData;
|
||||||
import io.metersphere.excel.utils.EasyExcelI18nTranslator;
|
import io.metersphere.excel.utils.EasyExcelI18nTranslator;
|
||||||
import io.metersphere.excel.utils.ExcelValidateHelper;
|
import io.metersphere.excel.utils.ExcelValidateHelper;
|
||||||
import io.metersphere.i18n.Translator;
|
import io.metersphere.i18n.Translator;
|
||||||
|
@ -24,6 +25,8 @@ public abstract class EasyExcelListener<T> extends AnalysisEventListener<T> {
|
||||||
|
|
||||||
protected EasyExcelI18nTranslator easyExcelI18nTranslator;
|
protected EasyExcelI18nTranslator easyExcelI18nTranslator;
|
||||||
|
|
||||||
|
protected List<TestCaseExcelData> excelDataList = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 每隔2000条存储数据库,然后清理list ,方便内存回收
|
* 每隔2000条存储数据库,然后清理list ,方便内存回收
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -10,10 +10,7 @@ import io.metersphere.i18n.Translator;
|
||||||
import io.metersphere.track.service.TestCaseService;
|
import io.metersphere.track.service.TestCaseService;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -57,10 +54,35 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
|
||||||
if (!userIds.contains(data.getMaintainer())) {
|
if (!userIds.contains(data.getMaintainer())) {
|
||||||
stringBuilder.append(Translator.get("user_not_exists") + ":" + data.getMaintainer() + "; ");
|
stringBuilder.append(Translator.get("user_not_exists") + ":" + data.getMaintainer() + "; ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (testCaseNames.contains(data.getName())) {
|
if (testCaseNames.contains(data.getName())) {
|
||||||
stringBuilder.append(Translator.get("test_case_already_exists_excel") + ":" + data.getName() + "; ");
|
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
||||||
|
BeanUtils.copyBean(testCase, data);
|
||||||
|
testCase.setProjectId(projectId);
|
||||||
|
String steps = getSteps(data);
|
||||||
|
testCase.setSteps(steps);
|
||||||
|
|
||||||
|
boolean dbExist = testCaseService.exist(testCase);
|
||||||
|
boolean excelExist = false;
|
||||||
|
|
||||||
|
if (dbExist) {
|
||||||
|
// db exist
|
||||||
|
stringBuilder.append(Translator.get("test_case_already_exists_excel") + ":" + data.getName() + "; ");
|
||||||
|
} else {
|
||||||
|
// @Data 重写了 equals 和 hashCode 方法
|
||||||
|
excelExist = excelDataList.contains(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (excelExist) {
|
||||||
|
// excel exist
|
||||||
|
stringBuilder.append(Translator.get("test_case_already_exists_excel") + ":" + data.getName() + "; ");
|
||||||
|
} else {
|
||||||
|
excelDataList.add(data);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
testCaseNames.add(data.getName());
|
testCaseNames.add(data.getName());
|
||||||
|
excelDataList.add(data);
|
||||||
}
|
}
|
||||||
return stringBuilder.toString();
|
return stringBuilder.toString();
|
||||||
}
|
}
|
||||||
|
@ -103,6 +125,13 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
|
||||||
testCase.setNodePath(nodePath);
|
testCase.setNodePath(nodePath);
|
||||||
|
|
||||||
|
|
||||||
|
String steps = getSteps(data);
|
||||||
|
testCase.setSteps(steps);
|
||||||
|
|
||||||
|
return testCase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSteps(TestCaseExcelData data) {
|
||||||
JSONArray jsonArray = new JSONArray();
|
JSONArray jsonArray = new JSONArray();
|
||||||
|
|
||||||
String[] stepDesc = new String[1];
|
String[] stepDesc = new String[1];
|
||||||
|
@ -124,7 +153,8 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
|
||||||
|
|
||||||
for (int i = 0; i < index; i++) {
|
for (int i = 0; i < index; i++) {
|
||||||
|
|
||||||
JSONObject step = new JSONObject();
|
// 保持插入顺序,判断用例是否有相同的steps
|
||||||
|
JSONObject step = new JSONObject(true);
|
||||||
step.put("num", i + 1);
|
step.put("num", i + 1);
|
||||||
|
|
||||||
Pattern descPattern = Pattern.compile(pattern);
|
Pattern descPattern = Pattern.compile(pattern);
|
||||||
|
@ -150,10 +180,7 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
|
||||||
|
|
||||||
jsonArray.add(step);
|
jsonArray.add(step);
|
||||||
}
|
}
|
||||||
|
return jsonArray.toJSONString();
|
||||||
testCase.setSteps(jsonArray.toJSONString());
|
|
||||||
|
|
||||||
return testCase;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,7 @@ 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.ldap.core.DirContextOperations;
|
import org.springframework.ldap.core.DirContextOperations;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
@ -82,4 +79,9 @@ public class LdapController {
|
||||||
ldapService.authenticate(request);
|
ldapService.authenticate(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/open")
|
||||||
|
public boolean isOpen() {
|
||||||
|
return ldapService.isOpen();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,9 +92,7 @@ public class LdapService {
|
||||||
if (result.size() == 1) {
|
if (result.size() == 1) {
|
||||||
return result.get(0);
|
return result.get(0);
|
||||||
}
|
}
|
||||||
} catch (NameNotFoundException e) {
|
} catch (NameNotFoundException | InvalidNameException e) {
|
||||||
MSException.throwException(Translator.get("login_fail_ou_error"));
|
|
||||||
} catch (InvalidNameException e) {
|
|
||||||
MSException.throwException(Translator.get("login_fail_ou_error"));
|
MSException.throwException(Translator.get("login_fail_ou_error"));
|
||||||
} catch (InvalidSearchFilterException e) {
|
} catch (InvalidSearchFilterException e) {
|
||||||
MSException.throwException(Translator.get("login_fail_filter_error"));
|
MSException.throwException(Translator.get("login_fail_filter_error"));
|
||||||
|
@ -125,9 +123,7 @@ public class LdapService {
|
||||||
MSException.throwException(Translator.get("ldap_ou_is_null"));
|
MSException.throwException(Translator.get("ldap_ou_is_null"));
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] arr = ou.split("\\|");
|
return ou.split("\\|");
|
||||||
|
|
||||||
return arr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MsContextMapper extends AbstractContextMapper<DirContextOperations> {
|
private static class MsContextMapper extends AbstractContextMapper<DirContextOperations> {
|
||||||
|
@ -217,4 +213,11 @@ public class LdapService {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isOpen() {
|
||||||
|
String open = service.getValue(ParamConstants.LDAP.OPEN.getValue());
|
||||||
|
if (StringUtils.isBlank(open)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return StringUtils.equals(Boolean.TRUE.toString(), open);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,9 +102,9 @@ public class PerformanceTestController {
|
||||||
return performanceTestService.run(request);
|
return performanceTestService.run(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("stop/{reportId}")
|
@GetMapping("stop/{reportId}/{forceStop}")
|
||||||
public void stopTest(@PathVariable String reportId) {
|
public void stopTest(@PathVariable String reportId, @PathVariable boolean forceStop) {
|
||||||
performanceTestService.stopTest(reportId);
|
performanceTestService.stopTest(reportId, forceStop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/file/metadata/{testId}")
|
@GetMapping("/file/metadata/{testId}")
|
||||||
|
|
|
@ -401,7 +401,19 @@ public class PerformanceTestService {
|
||||||
scheduleService.addOrUpdateCronJob(request, PerformanceTestJob.getJobKey(request.getResourceId()), PerformanceTestJob.getTriggerKey(request.getResourceId()), PerformanceTestJob.class);
|
scheduleService.addOrUpdateCronJob(request, PerformanceTestJob.getJobKey(request.getResourceId()), PerformanceTestJob.getTriggerKey(request.getResourceId()), PerformanceTestJob.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopTest(String reportId) {
|
public void stopTest(String reportId, boolean forceStop) {
|
||||||
reportService.deleteReport(reportId);
|
if (forceStop) {
|
||||||
|
reportService.deleteReport(reportId);
|
||||||
|
} else {
|
||||||
|
LoadTestReport loadTestReport = loadTestReportMapper.selectByPrimaryKey(reportId);
|
||||||
|
LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(loadTestReport.getTestId());
|
||||||
|
final Engine engine = EngineFactory.createEngine(loadTest);
|
||||||
|
if (engine == null) {
|
||||||
|
MSException.throwException(String.format("Stop report fail. create engine fail,report ID:%s", reportId));
|
||||||
|
}
|
||||||
|
reportService.stopEngine(loadTest, engine);
|
||||||
|
// 停止测试之后设置报告的状态
|
||||||
|
reportService.updateStatus(reportId, PerformanceTestStatus.Completed.name());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ public class ReportService {
|
||||||
loadTestReportMapper.deleteByPrimaryKey(reportId);
|
loadTestReportMapper.deleteByPrimaryKey(reportId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopEngine(LoadTestWithBLOBs loadTest, Engine engine) {
|
public void stopEngine(LoadTestWithBLOBs loadTest, Engine engine) {
|
||||||
engine.stop();
|
engine.stop();
|
||||||
loadTest.setStatus(PerformanceTestStatus.Saved.name());
|
loadTest.setStatus(PerformanceTestStatus.Saved.name());
|
||||||
loadTestMapper.updateByPrimaryKeySelective(loadTest);
|
loadTestMapper.updateByPrimaryKeySelective(loadTest);
|
||||||
|
@ -239,4 +239,11 @@ public class ReportService {
|
||||||
public LoadTestReport getReport(String reportId) {
|
public LoadTestReport getReport(String reportId) {
|
||||||
return loadTestReportMapper.selectByPrimaryKey(reportId);
|
return loadTestReportMapper.selectByPrimaryKey(reportId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateStatus(String reportId, String status) {
|
||||||
|
LoadTestReport report = new LoadTestReport();
|
||||||
|
report.setId(reportId);
|
||||||
|
report.setStatus(status);
|
||||||
|
loadTestReportMapper.updateByPrimaryKeySelective(report);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,13 +106,16 @@ public class TestCaseService {
|
||||||
TestCaseExample.Criteria criteria = example.createCriteria();
|
TestCaseExample.Criteria criteria = example.createCriteria();
|
||||||
criteria.andNameEqualTo(testCase.getName())
|
criteria.andNameEqualTo(testCase.getName())
|
||||||
.andProjectIdEqualTo(testCase.getProjectId())
|
.andProjectIdEqualTo(testCase.getProjectId())
|
||||||
.andNodeIdEqualTo(testCase.getNodeId())
|
|
||||||
.andNodePathEqualTo(testCase.getNodePath())
|
.andNodePathEqualTo(testCase.getNodePath())
|
||||||
.andTypeEqualTo(testCase.getType())
|
.andTypeEqualTo(testCase.getType())
|
||||||
.andMaintainerEqualTo(testCase.getMaintainer())
|
.andMaintainerEqualTo(testCase.getMaintainer())
|
||||||
.andPriorityEqualTo(testCase.getPriority())
|
.andPriorityEqualTo(testCase.getPriority())
|
||||||
.andMethodEqualTo(testCase.getMethod());
|
.andMethodEqualTo(testCase.getMethod());
|
||||||
|
|
||||||
|
// if (StringUtils.isNotBlank(testCase.getNodeId())) {
|
||||||
|
// criteria.andNodeIdEqualTo(testCase.getTestId());
|
||||||
|
// }
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(testCase.getTestId())) {
|
if (StringUtils.isNotBlank(testCase.getTestId())) {
|
||||||
criteria.andTestIdEqualTo(testCase.getTestId());
|
criteria.andTestIdEqualTo(testCase.getTestId());
|
||||||
}
|
}
|
||||||
|
@ -371,8 +374,8 @@ public class TestCaseService {
|
||||||
JSONArray jsonArray = JSON.parseArray(steps);
|
JSONArray jsonArray = JSON.parseArray(steps);
|
||||||
for (int j = 0; j < jsonArray.size(); j++) {
|
for (int j = 0; j < jsonArray.size(); j++) {
|
||||||
int num = j + 1;
|
int num = j + 1;
|
||||||
step.append(num + ":" + jsonArray.getJSONObject(j).getString("desc") + "\n");
|
step.append(num + "." + jsonArray.getJSONObject(j).getString("desc") + "\n");
|
||||||
result.append(num + ":" + jsonArray.getJSONObject(j).getString("result") + "\n");
|
result.append(num + "." + jsonArray.getJSONObject(j).getString("result") + "\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
data.setStepDesc(step.toString());
|
data.setStepDesc(step.toString());
|
||||||
|
@ -471,4 +474,21 @@ public class TestCaseService {
|
||||||
return Optional.ofNullable(testCase.getNum() + 1).orElse(100001);
|
return Optional.ofNullable(testCase.getNum() + 1).orElse(100001);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入用例前,检查数据库是否存在此用例
|
||||||
|
* @param testCaseWithBLOBs
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean exist(TestCaseWithBLOBs testCaseWithBLOBs) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
checkTestCaseExist(testCaseWithBLOBs);
|
||||||
|
} catch (MSException e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,9 @@ public class ReportWebSocket {
|
||||||
session.close();
|
session.close();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (!session.isOpen()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (PerformanceTestStatus.Running.name().equals(report.getStatus())) {
|
if (PerformanceTestStatus.Running.name().equals(report.getStatus())) {
|
||||||
session.getBasicRemote().sendText("refresh-" + this.refresh++);
|
session.getBasicRemote().sendText("refresh-" + this.refresh++);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,3 +74,7 @@ quartz.scheduler-name=msServerJob
|
||||||
spring.servlet.multipart.max-file-size=30MB
|
spring.servlet.multipart.max-file-size=30MB
|
||||||
spring.servlet.multipart.max-request-size=30MB
|
spring.servlet.multipart.max-request-size=30MB
|
||||||
|
|
||||||
|
# actuator
|
||||||
|
management.server.port=8083
|
||||||
|
management.endpoints.web.exposure.include=*
|
||||||
|
|
||||||
|
|
|
@ -146,14 +146,17 @@
|
||||||
</root>
|
</root>
|
||||||
|
|
||||||
<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="infoAsyncAppender" />
|
<appender-ref ref="infoAsyncAppender"/>
|
||||||
<appender-ref ref="warnAsyncAppender" />
|
<appender-ref ref="warnAsyncAppender"/>
|
||||||
<appender-ref ref="errorAsyncAppender" />
|
<appender-ref ref="errorAsyncAppender"/>
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
<logger name="io.metersphere.Application" additivity="false" level="${logger.level:INFO}">
|
<logger name="io.metersphere.Application" additivity="false" level="${logger.level:INFO}">
|
||||||
<appender-ref ref="infoAsyncAppender" />
|
<appender-ref ref="infoAsyncAppender"/>
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
|
<logger name="com.alibaba.nacos.naming.client.listener" additivity="false" level="ERROR"/>
|
||||||
|
<logger name="org.apache.dubbo" additivity="false" level="ERROR"/>
|
||||||
|
|
||||||
</configuration>
|
</configuration>
|
|
@ -34,7 +34,8 @@
|
||||||
"babel-eslint": "^10.0.3",
|
"babel-eslint": "^10.0.3",
|
||||||
"eslint": "^5.16.0",
|
"eslint": "^5.16.0",
|
||||||
"eslint-plugin-vue": "^5.0.0",
|
"eslint-plugin-vue": "^5.0.0",
|
||||||
"vue-template-compiler": "^2.6.10"
|
"vue-template-compiler": "^2.6.10",
|
||||||
|
"vue2-ace-editor": "0.0.15"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"root": true,
|
"root": true,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="container" v-loading="loading">
|
<div class="container" v-loading="loading" :element-loading-text="$t('api_report.running')">
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<el-card>
|
<el-card>
|
||||||
<section class="report-container" v-if="this.report.testId">
|
<section class="report-container" v-if="this.report.testId">
|
||||||
<header class="report-header">
|
<header class="report-header">
|
||||||
<span>{{report.projectName}} / </span>
|
<span>{{ report.projectName }} / </span>
|
||||||
<router-link :to="path">{{report.testName}}</router-link>
|
<router-link :to="path">{{ report.testName }}</router-link>
|
||||||
<span class="time">{{report.createTime | timestampFormatDate}}</span>
|
<span class="time">{{ report.createTime | timestampFormatDate }}</span>
|
||||||
</header>
|
</header>
|
||||||
<main v-if="this.isNotRunning">
|
<main v-if="this.isNotRunning">
|
||||||
<ms-metric-chart :content="content"/>
|
<ms-metric-chart :content="content"/>
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane name="fail">
|
<el-tab-pane name="fail">
|
||||||
<template slot="label">
|
<template slot="label">
|
||||||
<span class="fail">{{$t('api_report.fail')}}</span>
|
<span class="fail">{{ $t('api_report.fail') }}</span>
|
||||||
</template>
|
</template>
|
||||||
<ms-scenario-results :scenarios="fails"/>
|
<ms-scenario-results :scenarios="fails"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
@ -30,126 +30,126 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import MsRequestResult from "./components/RequestResult";
|
import MsRequestResult from "./components/RequestResult";
|
||||||
import MsScenarioResult from "./components/ScenarioResult";
|
import MsScenarioResult from "./components/ScenarioResult";
|
||||||
import MsMetricChart from "./components/MetricChart";
|
import MsMetricChart from "./components/MetricChart";
|
||||||
import MsScenarioResults from "./components/ScenarioResults";
|
import MsScenarioResults from "./components/ScenarioResults";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsApiReportView",
|
name: "MsApiReportView",
|
||||||
components: {MsScenarioResults, MsMetricChart, MsScenarioResult, MsRequestResult},
|
components: {MsScenarioResults, MsMetricChart, MsScenarioResult, MsRequestResult},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
activeName: "total",
|
activeName: "total",
|
||||||
content: {},
|
content: {},
|
||||||
report: {},
|
report: {},
|
||||||
loading: true,
|
loading: true,
|
||||||
fails: []
|
fails: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
this.loading = true;
|
||||||
|
this.report = {};
|
||||||
|
this.content = {};
|
||||||
|
this.fails = [];
|
||||||
|
},
|
||||||
|
getReport() {
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
if (this.reportId) {
|
||||||
|
let url = "/api/report/get/" + this.reportId;
|
||||||
|
this.$get(url, response => {
|
||||||
|
this.report = response.data || {};
|
||||||
|
if (this.isNotRunning) {
|
||||||
|
try {
|
||||||
|
this.content = JSON.parse(this.report.content);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(this.report.content)
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
this.getFails();
|
||||||
|
this.loading = false;
|
||||||
|
} else {
|
||||||
|
setTimeout(this.getReport, 2000)
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getFails() {
|
||||||
methods: {
|
if (this.isNotRunning) {
|
||||||
init() {
|
|
||||||
this.loading = true;
|
|
||||||
this.report = {};
|
|
||||||
this.content = {};
|
|
||||||
this.fails = [];
|
this.fails = [];
|
||||||
},
|
this.content.scenarios.forEach((scenario) => {
|
||||||
getReport() {
|
let failScenario = Object.assign({}, scenario);
|
||||||
this.init();
|
if (scenario.error > 0) {
|
||||||
|
this.fails.push(failScenario);
|
||||||
if (this.reportId) {
|
failScenario.requestResults = [];
|
||||||
let url = "/api/report/get/" + this.reportId;
|
scenario.requestResults.forEach((request) => {
|
||||||
this.$get(url, response => {
|
if (!request.success) {
|
||||||
this.report = response.data || {};
|
let failRequest = Object.assign({}, request);
|
||||||
if (this.isNotRunning) {
|
failScenario.requestResults.push(failRequest);
|
||||||
try {
|
|
||||||
this.content = JSON.parse(this.report.content);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(this.report.content)
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
this.getFails();
|
})
|
||||||
this.loading = false;
|
|
||||||
} else {
|
|
||||||
setTimeout(this.getReport, 2000)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getFails() {
|
|
||||||
if (this.isNotRunning) {
|
|
||||||
this.fails = [];
|
|
||||||
this.content.scenarios.forEach((scenario) => {
|
|
||||||
let failScenario = Object.assign({}, scenario);
|
|
||||||
if (scenario.error > 0) {
|
|
||||||
this.fails.push(failScenario);
|
|
||||||
failScenario.requestResults = [];
|
|
||||||
scenario.requestResults.forEach((request) => {
|
|
||||||
if (!request.success) {
|
|
||||||
let failRequest = Object.assign({}, request);
|
|
||||||
failScenario.requestResults.push(failRequest);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
'$route': 'getReport',
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
|
||||||
this.getReport();
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
reportId: function () {
|
|
||||||
return this.$route.params.reportId;
|
|
||||||
},
|
|
||||||
path() {
|
|
||||||
return "/api/test/edit?id=" + this.report.testId;
|
|
||||||
},
|
|
||||||
isNotRunning() {
|
|
||||||
return "Running" !== this.report.status;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
'$route': 'getReport',
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
this.getReport();
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
reportId: function () {
|
||||||
|
return this.$route.params.reportId;
|
||||||
|
},
|
||||||
|
path() {
|
||||||
|
return "/api/test/edit?id=" + this.report.testId;
|
||||||
|
},
|
||||||
|
isNotRunning() {
|
||||||
|
return "Running" !== this.report.status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
.report-container .el-tabs__header {
|
.report-container .el-tabs__header {
|
||||||
margin-bottom: 1px;
|
margin-bottom: 1px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.report-container {
|
.report-container {
|
||||||
height: calc(100vh - 150px);
|
height: calc(100vh - 150px);
|
||||||
min-height: 600px;
|
min-height: 600px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-header {
|
.report-header {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-header a {
|
.report-header a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-header .time {
|
.report-header .time {
|
||||||
color: #909399;
|
color: #909399;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-container .fail {
|
.report-container .fail {
|
||||||
color: #F56C6C;
|
color: #F56C6C;
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-container .is-active .fail {
|
.report-container .is-active .fail {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<el-collapse-transition>
|
<el-collapse-transition>
|
||||||
<el-tabs v-model="activeName" v-show="isActive">
|
<el-tabs v-model="activeName" v-show="isActive">
|
||||||
<el-tab-pane label="Body" name="body" class="pane">
|
<el-tab-pane label="Body" name="body" class="pane">
|
||||||
<div>{{response.body}}</div>
|
<ms-code-edit :read-only="true" :data="response.body" :modes="modes" ref="codeEdit"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="Headers" name="headers" class="pane">
|
<el-tab-pane label="Headers" name="headers" class="pane">
|
||||||
<pre>{{response.headers}}</pre>
|
<pre>{{response.headers}}</pre>
|
||||||
|
@ -15,6 +15,13 @@
|
||||||
<el-tab-pane :label="$t('api_report.assertions')" name="assertions" class="pane assertions">
|
<el-tab-pane :label="$t('api_report.assertions')" name="assertions" class="pane assertions">
|
||||||
<ms-assertion-results :assertions="response.assertions"/>
|
<ms-assertion-results :assertions="response.assertions"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
|
<el-tab-pane v-if="activeName == 'body'" :disabled="true" name="mode" class="pane assertions">
|
||||||
|
<template v-slot:label>
|
||||||
|
<ms-dropdown :commands="modes" @command="modeChange"/>
|
||||||
|
</template>
|
||||||
|
</el-tab-pane>
|
||||||
|
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</el-collapse-transition>
|
</el-collapse-transition>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,11 +29,17 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MsAssertionResults from "./AssertionResults";
|
import MsAssertionResults from "./AssertionResults";
|
||||||
|
import MsCodeEdit from "../../../common/components/MsCodeEdit";
|
||||||
|
import MsDropdown from "../../../common/components/MsDropdown";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsResponseText",
|
name: "MsResponseText",
|
||||||
|
|
||||||
components: {MsAssertionResults},
|
components: {
|
||||||
|
MsDropdown,
|
||||||
|
MsCodeEdit,
|
||||||
|
MsAssertionResults,
|
||||||
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
response: Object
|
response: Object
|
||||||
|
@ -36,12 +49,16 @@
|
||||||
return {
|
return {
|
||||||
isActive: false,
|
isActive: false,
|
||||||
activeName: "body",
|
activeName: "body",
|
||||||
|
modes: ['text', 'json', 'xml', 'html'],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
active() {
|
active() {
|
||||||
this.isActive = !this.isActive;
|
this.isActive = !this.isActive;
|
||||||
|
},
|
||||||
|
modeChange(mode) {
|
||||||
|
this.$refs.codeEdit.setMode(mode);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<el-form :model="config" :rules="rules" ref="config" label-width="100px" size="small" :disabled="isReadOnly">
|
<el-form :model="config" :rules="rules" ref="config" label-width="100px" size="small" :disabled="isReadOnly">
|
||||||
<div class="dubbo-form-description" v-if="description">
|
<div class="dubbo-form-description" v-if="description">
|
||||||
{{description}}
|
{{ description }}
|
||||||
</div>
|
</div>
|
||||||
<el-form-item label="Protocol" prop="protocol" class="dubbo-form-item">
|
<el-form-item label="Protocol" prop="protocol" class="dubbo-form-item">
|
||||||
<el-select v-model="config.protocol" class="select-100">
|
<el-select v-model="config.protocol" class="select-100" clearable>
|
||||||
<el-option v-for="p in protocols" :key="p" :label="p" :value="p"/>
|
<el-option v-for="p in protocols" :key="p" :label="p" :value="p"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -43,41 +43,41 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import './dubbo.css'
|
import './dubbo.css'
|
||||||
import {ConfigCenter} from "@/business/components/api/test/model/ScenarioModel";
|
import {ConfigCenter} from "@/business/components/api/test/model/ScenarioModel";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsDubboConfigCenter",
|
name: "MsDubboConfigCenter",
|
||||||
props: {
|
props: {
|
||||||
description: String,
|
description: String,
|
||||||
config: ConfigCenter,
|
config: ConfigCenter,
|
||||||
isReadOnly: {
|
isReadOnly: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
protocols: ConfigCenter.PROTOCOLS,
|
protocols: ConfigCenter.PROTOCOLS,
|
||||||
methods: [],
|
methods: [],
|
||||||
rules: {
|
rules: {
|
||||||
group: [
|
group: [
|
||||||
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
||||||
],
|
],
|
||||||
namespace: [
|
namespace: [
|
||||||
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
||||||
],
|
],
|
||||||
username: [
|
username: [
|
||||||
{max: 100, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
{max: 100, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
||||||
],
|
],
|
||||||
password: [
|
password: [
|
||||||
{max: 30, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
{max: 30, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
||||||
],
|
],
|
||||||
address: [
|
address: [
|
||||||
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
||||||
]
|
]
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<el-form :model="consumer" :rules="rules" ref="consumer" label-width="100px" size="small" :disabled="isReadOnly">
|
<el-form :model="consumer" :rules="rules" ref="consumer" label-width="100px" size="small" :disabled="isReadOnly">
|
||||||
<div class="dubbo-form-description" v-if="description">
|
<div class="dubbo-form-description" v-if="description">
|
||||||
{{description}}
|
{{ description }}
|
||||||
</div>
|
</div>
|
||||||
<el-form-item label="Timeout" prop="timeout" class="dubbo-form-item">
|
<el-form-item label="Timeout" prop="timeout" class="dubbo-form-item">
|
||||||
<el-input type="number" v-model="consumer.timeout" :placeholder="$t('commons.input_content')"/>
|
<el-input type="number" v-model="consumer.timeout" :placeholder="$t('commons.input_content')"/>
|
||||||
|
@ -32,13 +32,13 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Async" prop="async" class="dubbo-form-item">
|
<el-form-item label="Async" prop="async" class="dubbo-form-item">
|
||||||
<el-select v-model="consumer.async" class="select-100">
|
<el-select v-model="consumer.async" class="select-100" clearable>
|
||||||
<el-option v-for="option in asyncOptions" :key="option" :label="option" :value="option"/>
|
<el-option v-for="option in asyncOptions" :key="option" :label="option" :value="option"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="LoadBalance" prop="loadBalance" class="dubbo-form-item">
|
<el-form-item label="LoadBalance" prop="loadBalance" class="dubbo-form-item">
|
||||||
<el-select v-model="consumer.loadBalance" class="select-100">
|
<el-select v-model="consumer.loadBalance" class="select-100" clearable>
|
||||||
<el-option v-for="option in loadBalances" :key="option" :label="option" :value="option"/>
|
<el-option v-for="option in loadBalances" :key="option" :label="option" :value="option"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -47,36 +47,36 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import './dubbo.css'
|
import './dubbo.css'
|
||||||
import {ConsumerAndService, RegistryCenter} from "@/business/components/api/test/model/ScenarioModel";
|
import {ConsumerAndService, RegistryCenter} from "@/business/components/api/test/model/ScenarioModel";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsDubboConsumerService",
|
name: "MsDubboConsumerService",
|
||||||
props: {
|
props: {
|
||||||
description: String,
|
description: String,
|
||||||
consumer: ConsumerAndService,
|
consumer: ConsumerAndService,
|
||||||
isReadOnly: {
|
isReadOnly: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
asyncOptions: ConsumerAndService.ASYNC_OPTIONS,
|
asyncOptions: ConsumerAndService.ASYNC_OPTIONS,
|
||||||
loadBalances: ConsumerAndService.LOAD_BALANCE_OPTIONS,
|
loadBalances: ConsumerAndService.LOAD_BALANCE_OPTIONS,
|
||||||
methods: [],
|
methods: [],
|
||||||
rules: {
|
rules: {
|
||||||
version: [
|
version: [
|
||||||
{max: 30, message: this.$t('commons.input_limit', [0, 30]), trigger: 'blur'}
|
{max: 30, message: this.$t('commons.input_limit', [0, 30]), trigger: 'blur'}
|
||||||
],
|
],
|
||||||
cluster: [
|
cluster: [
|
||||||
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
||||||
],
|
],
|
||||||
group: [
|
group: [
|
||||||
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
||||||
]
|
]
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<el-form :model="registry" :rules="rules" ref="registry" label-width="100px" size="small" :disabled="isReadOnly">
|
<el-form :model="registry" :rules="rules" ref="registry" label-width="100px" size="small" :disabled="isReadOnly">
|
||||||
<div class="dubbo-form-description" v-if="description">
|
<div class="dubbo-form-description" v-if="description">
|
||||||
{{description}}
|
{{ description }}
|
||||||
</div>
|
</div>
|
||||||
<el-form-item label="Protocol" prop="protocol" class="dubbo-form-item">
|
<el-form-item label="Protocol" prop="protocol" class="dubbo-form-item">
|
||||||
<el-select v-model="registry.protocol" class="select-100">
|
<el-select v-model="registry.protocol" class="select-100" clearable>
|
||||||
<el-option v-for="p in protocols" :key="p" :label="p" :value="p"/>
|
<el-option v-for="p in protocols" :key="p" :label="p" :value="p"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -36,38 +36,38 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import './dubbo.css'
|
import './dubbo.css'
|
||||||
import {RegistryCenter} from "@/business/components/api/test/model/ScenarioModel";
|
import {RegistryCenter} from "@/business/components/api/test/model/ScenarioModel";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsDubboRegistryCenter",
|
name: "MsDubboRegistryCenter",
|
||||||
props: {
|
props: {
|
||||||
description: String,
|
description: String,
|
||||||
registry: RegistryCenter,
|
registry: RegistryCenter,
|
||||||
isReadOnly: {
|
isReadOnly: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
protocols: RegistryCenter.PROTOCOLS,
|
protocols: RegistryCenter.PROTOCOLS,
|
||||||
methods: [],
|
methods: [],
|
||||||
rules: {
|
rules: {
|
||||||
group: [
|
group: [
|
||||||
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
||||||
],
|
],
|
||||||
username: [
|
username: [
|
||||||
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
||||||
],
|
],
|
||||||
password: [
|
password: [
|
||||||
{max: 30, message: this.$t('commons.input_limit', [0, 30]), trigger: 'blur'}
|
{max: 30, message: this.$t('commons.input_limit', [0, 30]), trigger: 'blur'}
|
||||||
],
|
],
|
||||||
address: [
|
address: [
|
||||||
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
|
||||||
]
|
]
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
|
<el-aside :width="width" class="ms-aside-container"
|
||||||
<el-aside :width="width" class="ms-aside-container">
|
:style="{'margin-left': asideHidden ? '0' : '-' + width}">
|
||||||
|
<div class="hiddenBottom" @click="asideHidden = !asideHidden" :style="{'left': width}">
|
||||||
|
<i v-if="asideHidden" class="el-icon-arrow-left"/>
|
||||||
|
<i v-if="!asideHidden" class="el-icon-arrow-right"/>
|
||||||
|
</div>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</el-aside>
|
</el-aside>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -14,6 +17,11 @@
|
||||||
type: String,
|
type: String,
|
||||||
default: '300px'
|
default: '300px'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
asideHidden: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -27,6 +35,31 @@
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
background-color: #FFF;
|
background-color: #FFF;
|
||||||
height: calc(100vh - 80px);
|
height: calc(100vh - 80px);
|
||||||
|
position: relative;
|
||||||
|
overflow: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hiddenBottom {
|
||||||
|
z-index: 199;
|
||||||
|
width: 8px;
|
||||||
|
height: 50px;
|
||||||
|
top: calc((100vh - 80px)/2);
|
||||||
|
line-height: 50px;
|
||||||
|
border-radius: 0 15px 15px 0;
|
||||||
|
background-color: #acb7c1;
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0.2;
|
||||||
|
font-size: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hiddenBottom i {
|
||||||
|
margin-left: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hiddenBottom:hover {
|
||||||
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
<template>
|
||||||
|
<editor v-model="formatData" :lang="mode" @init="editorInit" theme="chrome"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "MsCodeEdit",
|
||||||
|
components: { editor: require('vue2-ace-editor')},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
mode: 'text',
|
||||||
|
formatData: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
init: {
|
||||||
|
type: Function
|
||||||
|
},
|
||||||
|
readOnly: {
|
||||||
|
type: Boolean,
|
||||||
|
default() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modes: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return ['text', 'json', 'xml', 'html'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.format();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
editorInit: function (editor) {
|
||||||
|
require('brace/ext/language_tools') //language extension prerequsite...
|
||||||
|
this.modes.forEach(mode => {
|
||||||
|
require('brace/mode/' + mode); //language
|
||||||
|
});
|
||||||
|
require('brace/theme/chrome')
|
||||||
|
require('brace/snippets/javascript') //snippet
|
||||||
|
if (this.readOnly) {
|
||||||
|
editor.setReadOnly(true);
|
||||||
|
}
|
||||||
|
if (this.init) {
|
||||||
|
this.init(editor);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
format() {
|
||||||
|
if (this.mode === 'json') {
|
||||||
|
try {
|
||||||
|
this.formatData = JSON.stringify(JSON.parse(this.data), null, '\t');
|
||||||
|
} catch (e) {
|
||||||
|
this.formatData = this.data;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.formatData = this.data;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setMode(mode) {
|
||||||
|
this.mode = mode;
|
||||||
|
this.format();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,55 @@
|
||||||
|
<template>
|
||||||
|
<el-dropdown @command="handleCommand">
|
||||||
|
<slot>
|
||||||
|
<span class="el-dropdown-link">
|
||||||
|
{{currentCommand}}
|
||||||
|
<i class="el-icon-arrow-down el-icon--right"></i>
|
||||||
|
</span>
|
||||||
|
</slot>
|
||||||
|
<el-dropdown-menu slot="dropdown" chang>
|
||||||
|
<el-dropdown-item v-for="(command, index) in commands" :key="index" :command="command">
|
||||||
|
{{command}}
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "MsDropdown",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentCommand: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
commands: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (this.commands && this.commands.length > 0) {
|
||||||
|
this.currentCommand = this.commands [0];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleCommand(command) {
|
||||||
|
this.currentCommand = command;
|
||||||
|
this.$emit('command', command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
.el-dropdown-link {
|
||||||
|
cursor: pointer;
|
||||||
|
color: #409EFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-icon-arrow-down {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -14,11 +14,11 @@
|
||||||
</el-breadcrumb>
|
</el-breadcrumb>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row class="ms-report-view-btns">
|
<el-row class="ms-report-view-btns">
|
||||||
<el-button :disabled="isReadOnly || status !== 'Running'" type="primary" plain size="mini"
|
<el-button :disabled="isReadOnly || report.status !== 'Running'" type="primary" plain size="mini"
|
||||||
@click="stopTest(reportId)">
|
@click="dialogFormVisible=true">
|
||||||
{{$t('report.test_stop_now')}}
|
{{$t('report.test_stop_now')}}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button :disabled="isReadOnly || status !== 'Completed'" type="success" plain size="mini"
|
<el-button :disabled="isReadOnly || report.status !== 'Completed'" type="success" plain size="mini"
|
||||||
@click="rerun(testId)">
|
@click="rerun(testId)">
|
||||||
{{$t('report.test_execute_again')}}
|
{{$t('report.test_execute_again')}}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
@ -62,6 +62,16 @@
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
|
||||||
</el-card>
|
</el-card>
|
||||||
|
<el-dialog :title="$t('report.test_stop_now_confirm')" :visible.sync="dialogFormVisible" width="30%">
|
||||||
|
<p v-html="$t('report.force_stop_tips')"></p>
|
||||||
|
<p v-html="$t('report.stop_tips')"></p>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="danger" size="small" @click="stopTest(true)">{{$t('report.force_stop_btn')}}
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" size="small" @click="stopTest(false)">{{$t('report.stop_btn')}}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</ms-main-container>
|
</ms-main-container>
|
||||||
</ms-container>
|
</ms-container>
|
||||||
</template>
|
</template>
|
||||||
|
@ -103,7 +113,8 @@
|
||||||
title: 'Logging',
|
title: 'Logging',
|
||||||
report: {},
|
report: {},
|
||||||
isReadOnly: false,
|
isReadOnly: false,
|
||||||
websocket: null
|
websocket: null,
|
||||||
|
dialogFormVisible: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -156,7 +167,7 @@
|
||||||
this.$warning(this.$t('report.generation_error'));
|
this.$warning(this.$t('report.generation_error'));
|
||||||
break;
|
break;
|
||||||
case 'Starting':
|
case 'Starting':
|
||||||
this.$warning(this.$t('report.start_status'));
|
this.$alert(this.$t('report.start_status'));
|
||||||
break;
|
break;
|
||||||
case 'Reporting':
|
case 'Reporting':
|
||||||
case 'Running':
|
case 'Running':
|
||||||
|
@ -171,18 +182,16 @@
|
||||||
this.minutes = '0';
|
this.minutes = '0';
|
||||||
this.seconds = '0';
|
this.seconds = '0';
|
||||||
},
|
},
|
||||||
stopTest(reportId) {
|
stopTest(forceStop) {
|
||||||
this.$confirm(this.$t('report.test_stop_now_confirm'), '', {
|
this.result = this.$get('/performance/stop/' + this.reportId + '/' + forceStop, () => {
|
||||||
confirmButtonText: this.$t('commons.confirm'),
|
this.$success(this.$t('report.test_stop_success'));
|
||||||
cancelButtonText: this.$t('commons.cancel'),
|
if (forceStop) {
|
||||||
type: 'warning'
|
|
||||||
}).then(() => {
|
|
||||||
this.result = this.$get('/performance/stop/' + reportId, () => {
|
|
||||||
this.$success(this.$t('report.test_stop_success'));
|
|
||||||
this.$router.push('/performance/report/all');
|
this.$router.push('/performance/report/all');
|
||||||
})
|
} else {
|
||||||
}).catch(() => {
|
this.report.status = 'Completed';
|
||||||
});
|
}
|
||||||
|
})
|
||||||
|
this.dialogFormVisible = false;
|
||||||
},
|
},
|
||||||
rerun(testId) {
|
rerun(testId) {
|
||||||
this.$confirm(this.$t('report.test_rerun_confirm'), '', {
|
this.$confirm(this.$t('report.test_rerun_confirm'), '', {
|
||||||
|
@ -190,26 +199,32 @@
|
||||||
cancelButtonText: this.$t('commons.cancel'),
|
cancelButtonText: this.$t('commons.cancel'),
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.result = this.$post('/performance/run', {id: testId, triggerMode: 'MANUAL'}, () => {
|
this.result = this.$post('/performance/run', {id: testId, triggerMode: 'MANUAL'}, (response) => {
|
||||||
this.$success(this.$t('load_test.is_running'))
|
this.reportId = response.data;
|
||||||
this.$router.push({path: '/performance/report/all'})
|
this.$router.push({path: '/performance/report/view/' + this.reportId})
|
||||||
|
// 注册 socket
|
||||||
|
this.initWebSocket();
|
||||||
})
|
})
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onOpen() {
|
onOpen() {
|
||||||
window.console.log("open WebSocket");
|
window.console.log("socket opening.");
|
||||||
},
|
},
|
||||||
onError(e) {
|
onError(e) {
|
||||||
window.console.error(e)
|
window.console.error(e)
|
||||||
},
|
},
|
||||||
onMessage(e) {
|
onMessage(e) {
|
||||||
this.$set(this.report, "refresh", e.data); // 触发刷新
|
this.$set(this.report, "refresh", e.data); // 触发刷新
|
||||||
|
this.$set(this.report, "status", 'Running');
|
||||||
this.initReportTimeInfo();
|
this.initReportTimeInfo();
|
||||||
|
window.console.log('receive a message:', e.data);
|
||||||
},
|
},
|
||||||
onClose(e) {
|
onClose(e) {
|
||||||
this.$set(this.report, "refresh", e.data); // 触发刷新
|
this.$set(this.report, "refresh", Math.random()); // 触发刷新
|
||||||
|
this.$set(this.report, "status", 'Completed');
|
||||||
this.initReportTimeInfo();
|
this.initReportTimeInfo();
|
||||||
|
window.console.log("socket closed.");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
|
|
@ -153,6 +153,9 @@
|
||||||
watch: {
|
watch: {
|
||||||
report: {
|
report: {
|
||||||
handler(val) {
|
handler(val) {
|
||||||
|
if (!val.status || !val.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let status = val.status;
|
let status = val.status;
|
||||||
this.id = val.id;
|
this.id = val.id;
|
||||||
if (status === "Completed" || status === "Running") {
|
if (status === "Completed" || status === "Running") {
|
||||||
|
|
|
@ -80,6 +80,9 @@
|
||||||
watch: {
|
watch: {
|
||||||
report: {
|
report: {
|
||||||
handler(val) {
|
handler(val) {
|
||||||
|
if (!val.status || !val.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let status = val.status;
|
let status = val.status;
|
||||||
this.id = val.id;
|
this.id = val.id;
|
||||||
if (status === "Completed" || status === "Running") {
|
if (status === "Completed" || status === "Running") {
|
||||||
|
|
|
@ -162,6 +162,9 @@
|
||||||
watch: {
|
watch: {
|
||||||
report: {
|
report: {
|
||||||
handler(val){
|
handler(val){
|
||||||
|
if (!val.status || !val.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let status = val.status;
|
let status = val.status;
|
||||||
this.id = val.id;
|
this.id = val.id;
|
||||||
if (status === "Completed" || status === "Running") {
|
if (status === "Completed" || status === "Running") {
|
||||||
|
|
|
@ -325,6 +325,9 @@
|
||||||
watch: {
|
watch: {
|
||||||
report: {
|
report: {
|
||||||
handler(val) {
|
handler(val) {
|
||||||
|
if (!val.status || !val.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let status = val.status;
|
let status = val.status;
|
||||||
this.id = val.id;
|
this.id = val.id;
|
||||||
if (status === "Completed" || status === "Running") {
|
if (status === "Completed" || status === "Running") {
|
||||||
|
|
|
@ -4,11 +4,13 @@
|
||||||
<el-card v-loading="result.loading">
|
<el-card v-loading="result.loading">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="10">
|
<el-col :span="10">
|
||||||
<el-input :disabled="isReadOnly" :placeholder="$t('load_test.input_name')" v-model="testPlan.name" class="input-with-select"
|
<el-input :disabled="isReadOnly" :placeholder="$t('load_test.input_name')" v-model="testPlan.name"
|
||||||
|
class="input-with-select"
|
||||||
maxlength="30" show-word-limit
|
maxlength="30" show-word-limit
|
||||||
>
|
>
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
<el-select :disabled="isReadOnly" v-model="testPlan.projectId" :placeholder="$t('load_test.select_project')">
|
<el-select :disabled="isReadOnly" v-model="testPlan.projectId"
|
||||||
|
:placeholder="$t('load_test.select_project')">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in projects"
|
v-for="item in projects"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
|
@ -21,10 +23,13 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" :offset="2">
|
<el-col :span="12" :offset="2">
|
||||||
<el-button :disabled="isReadOnly" type="primary" plain @click="save">{{$t('commons.save')}}</el-button>
|
<el-button :disabled="isReadOnly" type="primary" plain @click="save">{{$t('commons.save')}}</el-button>
|
||||||
<el-button :disabled="isReadOnly" type="primary" plain @click="saveAndRun">{{$t('load_test.save_and_run')}}</el-button>
|
<el-button :disabled="isReadOnly" type="primary" plain @click="saveAndRun">
|
||||||
|
{{$t('load_test.save_and_run')}}
|
||||||
|
</el-button>
|
||||||
<el-button :disabled="isReadOnly" type="warning" plain @click="cancel">{{$t('commons.cancel')}}</el-button>
|
<el-button :disabled="isReadOnly" type="warning" plain @click="cancel">{{$t('commons.cancel')}}</el-button>
|
||||||
|
|
||||||
<ms-schedule-config :schedule="testPlan.schedule" :save="saveCronExpression" @scheduleChange="saveSchedule" :check-open="checkScheduleEdit" :custom-validate="durationValidate"/>
|
<ms-schedule-config :schedule="testPlan.schedule" :save="saveCronExpression" @scheduleChange="saveSchedule"
|
||||||
|
:check-open="checkScheduleEdit" :custom-validate="durationValidate"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
|
@ -34,7 +39,8 @@
|
||||||
<performance-basic-config :is-read-only="isReadOnly" :test-plan="testPlan" ref="basicConfig"/>
|
<performance-basic-config :is-read-only="isReadOnly" :test-plan="testPlan" ref="basicConfig"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('load_test.pressure_config')">
|
<el-tab-pane :label="$t('load_test.pressure_config')">
|
||||||
<performance-pressure-config :is-read-only="isReadOnly" :test-plan="testPlan" :test-id="testId" ref="pressureConfig" @changeActive="changeTabActive"/>
|
<performance-pressure-config :is-read-only="isReadOnly" :test-plan="testPlan" :test-id="testId"
|
||||||
|
ref="pressureConfig" @changeActive="changeTabActive"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('load_test.advanced_config')" class="advanced-config">
|
<el-tab-pane :label="$t('load_test.advanced_config')" class="advanced-config">
|
||||||
<performance-advanced-config :read-only="isReadOnly" :test-id="testId" ref="advancedConfig"/>
|
<performance-advanced-config :read-only="isReadOnly" :test-id="testId" ref="advancedConfig"/>
|
||||||
|
@ -67,7 +73,7 @@
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
result: {},
|
result: {},
|
||||||
testPlan: {schedule:{}},
|
testPlan: {schedule: {}},
|
||||||
listProjectPath: "/project/listAll",
|
listProjectPath: "/project/listAll",
|
||||||
savePath: "/performance/save",
|
savePath: "/performance/save",
|
||||||
editPath: "/performance/edit",
|
editPath: "/performance/edit",
|
||||||
|
@ -177,9 +183,9 @@
|
||||||
this.result = this.$request(options, (response) => {
|
this.result = this.$request(options, (response) => {
|
||||||
this.testPlan.id = response.data;
|
this.testPlan.id = response.data;
|
||||||
this.$success(this.$t('commons.save_success'));
|
this.$success(this.$t('commons.save_success'));
|
||||||
this.result = this.$post(this.runPath, {id: this.testPlan.id, triggerMode: 'MANUAL'}, () => {
|
this.result = this.$post(this.runPath, {id: this.testPlan.id, triggerMode: 'MANUAL'}, (response) => {
|
||||||
this.$success(this.$t('load_test.is_running'))
|
let reportId = response.data;
|
||||||
this.$router.push({path: '/performance/report/all'})
|
this.$router.push({path: '/performance/report/view/' + reportId})
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -249,7 +255,7 @@
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
changeTabActive(activeName) {
|
changeTabActive(activeName) {
|
||||||
this.$nextTick(()=> {
|
this.$nextTick(() => {
|
||||||
this.active = activeName;
|
this.active = activeName;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -258,10 +258,14 @@ export default {
|
||||||
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 in the beginning state, we will automatically display it on the page after we generate the report!',
|
||||||
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',
|
||||||
|
force_stop_tips: '<strong>Terminating</strong> the servers will immediately kill the servers and the JTL files will be lost.',
|
||||||
|
stop_tips: 'A <strong>Graceful shutdown</strong> will archive the JTL files and then stop the servers.',
|
||||||
|
force_stop_btn: 'Terminating',
|
||||||
|
stop_btn: 'Graceful shutdown',
|
||||||
},
|
},
|
||||||
load_test: {
|
load_test: {
|
||||||
operating: 'Operating',
|
operating: 'Operating',
|
||||||
|
@ -470,6 +474,7 @@ export default {
|
||||||
sub_result: "Sub Result",
|
sub_result: "Sub Result",
|
||||||
detail: "Report detail",
|
detail: "Report detail",
|
||||||
delete: "Delete report",
|
delete: "Delete report",
|
||||||
|
running: "The test is running",
|
||||||
},
|
},
|
||||||
test_track: {
|
test_track: {
|
||||||
test_track: "Track",
|
test_track: "Track",
|
||||||
|
|
|
@ -256,11 +256,14 @@ export default {
|
||||||
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: '所属项目',
|
||||||
|
force_stop_tips: '<strong>强制停止</strong>测试会立刻结束当前测试并删除报告数据',
|
||||||
|
stop_tips: '<strong>停止</strong>测试会结束当前测试并保留报告数据',
|
||||||
|
force_stop_btn: '强制停止',
|
||||||
|
stop_btn: '停止',
|
||||||
},
|
},
|
||||||
load_test: {
|
load_test: {
|
||||||
operating: '操作',
|
operating: '操作',
|
||||||
|
@ -470,6 +473,7 @@ export default {
|
||||||
sub_result: "子请求",
|
sub_result: "子请求",
|
||||||
detail: "报告详情",
|
detail: "报告详情",
|
||||||
delete: "删除报告",
|
delete: "删除报告",
|
||||||
|
running: "测试执行中",
|
||||||
},
|
},
|
||||||
test_track: {
|
test_track: {
|
||||||
test_track: "测试跟踪",
|
test_track: "测试跟踪",
|
||||||
|
|
|
@ -256,10 +256,14 @@ export default {
|
||||||
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: '所屬項目',
|
||||||
|
force_stop_tips: '<strong>強制停止</strong>測試會立刻結束當前測試並刪除報告數據',
|
||||||
|
stop_tips: '<strong>停止</strong>測試會結束當前測試並保留報告數據',
|
||||||
|
force_stop_btn: '強制停止',
|
||||||
|
stop_btn: '停止',
|
||||||
},
|
},
|
||||||
load_test: {
|
load_test: {
|
||||||
operating: '操作',
|
operating: '操作',
|
||||||
|
@ -469,6 +473,7 @@ export default {
|
||||||
sub_result: "子請求",
|
sub_result: "子請求",
|
||||||
detail: "報告詳情",
|
detail: "報告詳情",
|
||||||
delete: "刪除報告",
|
delete: "刪除報告",
|
||||||
|
running: "測試執行中",
|
||||||
},
|
},
|
||||||
test_track: {
|
test_track: {
|
||||||
test_track: "測試跟踪",
|
test_track: "測試跟踪",
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
<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" v-if="openLdap">LDAP</el-radio>
|
||||||
<el-radio label="LOCAL" size="mini">普通登录</el-radio>
|
<el-radio label="LOCAL" size="mini" v-if="openLdap">普通登录</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="username">
|
<el-form-item prop="username">
|
||||||
|
@ -81,7 +81,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
msg: '',
|
msg: '',
|
||||||
ready: false
|
ready: false,
|
||||||
|
openLdap: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeCreate() {
|
beforeCreate() {
|
||||||
|
@ -92,6 +93,9 @@
|
||||||
window.location.href = "/"
|
window.location.href = "/"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
this.$get("/ldap/open", response => {
|
||||||
|
this.openLdap = response.data;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
created: function () {
|
created: function () {
|
||||||
// 主页添加键盘事件,注意,不能直接在焦点事件上添加回车
|
// 主页添加键盘事件,注意,不能直接在焦点事件上添加回车
|
||||||
|
@ -145,7 +149,7 @@
|
||||||
if (!language) {
|
if (!language) {
|
||||||
this.$get("language", response => {
|
this.$get("language", response => {
|
||||||
language = response.data;
|
language = response.data;
|
||||||
localStorage.setItem(DEFAULT_LANGUAGE, language)
|
localStorage.setItem(DEFAULT_LANGUAGE, language);
|
||||||
window.location.href = "/"
|
window.location.href = "/"
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue