feat(接口定义): 合并master 最新代码
This commit is contained in:
commit
22108b3048
|
@ -6,11 +6,11 @@ ARG MS_VERSION=dev
|
|||
|
||||
RUN mkdir -p /opt/apps && mkdir -p /opt/jmeter
|
||||
|
||||
COPY backend/target/backend-1.4.jar /opt/apps
|
||||
COPY backend/target/backend-1.5.jar /opt/apps
|
||||
|
||||
COPY backend/target/classes/jmeter/ /opt/jmeter/
|
||||
|
||||
ENV JAVA_APP_JAR=/opt/apps/backend-1.4.jar
|
||||
ENV JAVA_APP_JAR=/opt/apps/backend-1.5.jar
|
||||
|
||||
ENV AB_OFF=true
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@ MeterSphere is a one-stop open-source enterprise-class continuous testing platfo
|
|||
Only need two steps to install MeterSphere:
|
||||
|
||||
What you need:
|
||||
1. Prepare a 64-bit Linux host with no less than 8 G RAM
|
||||
2. Log into root user and execute the command down below to install MeterSphere
|
||||
1. Prepare a 64-bit Linux host with no less than 8 G RAM
|
||||
2. Log into root user and execute the command down below to install MeterSphere
|
||||
|
||||
```sh
|
||||
curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/quick_start.sh | sh
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<artifactId>metersphere-server</artifactId>
|
||||
<groupId>io.metersphere</groupId>
|
||||
<version>1.4</version>
|
||||
<version>1.5</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -156,7 +156,7 @@
|
|||
<dependency>
|
||||
<groupId>org.python</groupId>
|
||||
<artifactId>jython-standalone</artifactId>
|
||||
<version>2.7.2</version>
|
||||
<version>2.7.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
|
|
@ -138,7 +138,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
testResult.setTotal(queue.size());
|
||||
// 一个脚本里可能包含多个场景(MsThreadGroup),所以要区分开,key: 场景Id
|
||||
final Map<String, ScenarioResult> scenarios = new LinkedHashMap<>();
|
||||
queue.forEach(result -> {
|
||||
queue.forEach(result -> {
|
||||
// 线程名称: <场景名> <场景Index>-<请求Index>, 例如:Scenario 2-1
|
||||
String scenarioName = StringUtils.substringBeforeLast(result.getThreadName(), THREAD_SPLIT);
|
||||
String index = StringUtils.substringAfterLast(result.getThreadName(), THREAD_SPLIT);
|
||||
|
@ -146,7 +146,12 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
ScenarioResult scenarioResult;
|
||||
if (!scenarios.containsKey(scenarioId)) {
|
||||
scenarioResult = new ScenarioResult();
|
||||
scenarioResult.setId(scenarioId);
|
||||
try {
|
||||
scenarioResult.setId(Integer.parseInt(scenarioId));
|
||||
} catch (Exception e) {
|
||||
scenarioResult.setId(0);
|
||||
LogUtil.error("场景ID转换异常: " + e.getMessage());
|
||||
}
|
||||
scenarioResult.setName(scenarioName);
|
||||
scenarios.put(scenarioId, scenarioResult);
|
||||
} else {
|
||||
|
@ -203,13 +208,13 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
testPlanTestCaseService.updateTestCaseStates(ids, TestPlanTestCaseStatus.Failure.name());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
sendTask(report, testResult);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import java.util.List;
|
|||
@Data
|
||||
public class ScenarioResult {
|
||||
|
||||
private String id;
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ public class JmeterDocumentParser {
|
|||
}
|
||||
return documentToBytes(document);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
@ -161,7 +161,9 @@ public class JmeterDocumentParser {
|
|||
break;
|
||||
case "Argument.value":
|
||||
String textContent = ele.getTextContent();
|
||||
ele.setTextContent(ScriptEngineUtils.calculate(textContent));
|
||||
if (StringUtils.startsWith(textContent, "@")) {
|
||||
ele.setTextContent(ScriptEngineUtils.calculate(textContent));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -8,6 +8,7 @@ import io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter;
|
|||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.api.parse.ApiImportParser;
|
||||
import io.metersphere.api.parse.ApiImportParserFactory;
|
||||
import io.metersphere.api.parse.JmeterDocumentParser;
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.ApiTestFileMapper;
|
||||
import io.metersphere.base.mapper.ApiTestMapper;
|
||||
|
@ -85,9 +86,9 @@ public class APITestService {
|
|||
return extApiTestMapper.listByIds(request.getIds());
|
||||
}
|
||||
|
||||
public void create(SaveAPITestRequest request, List<MultipartFile> bodyFiles) {
|
||||
public void create(SaveAPITestRequest request, MultipartFile file, List<MultipartFile> bodyFiles) {
|
||||
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
|
||||
ApiTest test = createTest(request);
|
||||
ApiTest test = createTest(request, file);
|
||||
createBodyFiles(test, bodyUploadIds, bodyFiles);
|
||||
}
|
||||
private ApiTest createTest(SaveAPITestRequest request, MultipartFile file) {
|
||||
|
@ -101,13 +102,17 @@ public class APITestService {
|
|||
return test;
|
||||
}
|
||||
|
||||
public void update(SaveAPITestRequest request, List<MultipartFile> bodyFiles) {
|
||||
public void update(SaveAPITestRequest request, MultipartFile file, List<MultipartFile> bodyFiles) {
|
||||
if (file == null) {
|
||||
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
|
||||
}
|
||||
deleteFileByTestId(request.getId());
|
||||
|
||||
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
|
||||
request.setBodyUploadIds(null);
|
||||
ApiTest test = updateTest(request);
|
||||
createBodyFiles(test, bodyUploadIds, bodyFiles);
|
||||
saveFile(test.getId(), file);
|
||||
}
|
||||
|
||||
private void createBodyFiles(ApiTest test, List<String> bodyUploadIds, List<MultipartFile> bodyFiles) {
|
||||
|
@ -126,7 +131,7 @@ public class APITestService {
|
|||
file.createNewFile();
|
||||
FileUtil.copyStream(in, out);
|
||||
} catch (IOException e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
MSException.throwException(Translator.get("upload_fail"));
|
||||
}
|
||||
}
|
||||
|
@ -169,7 +174,7 @@ public class APITestService {
|
|||
try {
|
||||
FileUtil.copyDir(sourceFile, new File(targetDir));
|
||||
} catch (IOException e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
MSException.throwException(Translator.get("upload_fail"));
|
||||
}
|
||||
}
|
||||
|
@ -212,14 +217,27 @@ public class APITestService {
|
|||
}
|
||||
}
|
||||
|
||||
public String run(SaveAPITestRequest request,String runMode) {
|
||||
public String run(SaveAPITestRequest request) {
|
||||
ApiTestFile file = getFileByTestId(request.getId());
|
||||
if (file == null) {
|
||||
MSException.throwException(Translator.get("file_cannot_be_null"));
|
||||
}
|
||||
byte[] bytes = fileService.loadFileAsBytes(file.getFileId());
|
||||
// 解析 xml 处理 mock 数据
|
||||
bytes = JmeterDocumentParser.parse(bytes);
|
||||
InputStream is = new ByteArrayInputStream(bytes);
|
||||
|
||||
APITestResult apiTest = get(request.getId());
|
||||
if (SessionUtils.getUser() == null) {
|
||||
apiTest.setUserId(request.getUserId());
|
||||
}
|
||||
String reportId = apiReportService.create(apiTest, request.getTriggerMode());
|
||||
/*if (request.getTriggerMode().equals("SCHEDULE")) {
|
||||
List<Notice> notice = noticeService.queryNotice(request.getId());
|
||||
mailService.sendHtml(reportId,notice,"api");
|
||||
}*/
|
||||
changeStatus(request.getId(), APITestStatus.Running);
|
||||
jMeterService.run(request.getId(), request.getName(), request.getScenarioDefinition(), null,runMode);
|
||||
jMeterService.run(request.getId(), null, is);
|
||||
return reportId;
|
||||
}
|
||||
|
||||
|
@ -260,8 +278,6 @@ public class APITestService {
|
|||
}
|
||||
|
||||
private ApiTest createTest(SaveAPITestRequest request) {
|
||||
checkQuota();
|
||||
request.setBodyUploadIds(null);
|
||||
checkNameExist(request);
|
||||
final ApiTest test = new ApiTest();
|
||||
test.setId(request.getId());
|
||||
|
@ -276,6 +292,14 @@ public class APITestService {
|
|||
return test;
|
||||
}
|
||||
|
||||
private void saveFile(String testId, MultipartFile file) {
|
||||
final FileMetadata fileMetadata = fileService.saveFile(file);
|
||||
ApiTestFile apiTestFile = new ApiTestFile();
|
||||
apiTestFile.setTestId(testId);
|
||||
apiTestFile.setFileId(fileMetadata.getId());
|
||||
apiTestFileMapper.insert(apiTestFile);
|
||||
}
|
||||
|
||||
private void deleteFileByTestId(String testId) {
|
||||
ApiTestFileExample ApiTestFileExample = new ApiTestFileExample();
|
||||
ApiTestFileExample.createCriteria().andTestIdEqualTo(testId);
|
||||
|
@ -287,12 +311,17 @@ public class APITestService {
|
|||
fileService.deleteFileByIds(fileIds);
|
||||
}
|
||||
}
|
||||
private void saveFile(String testId, MultipartFile file) {
|
||||
final FileMetadata fileMetadata = fileService.saveFile(file);
|
||||
ApiTestFile apiTestFile = new ApiTestFile();
|
||||
apiTestFile.setTestId(testId);
|
||||
apiTestFile.setFileId(fileMetadata.getId());
|
||||
apiTestFileMapper.insert(apiTestFile);
|
||||
|
||||
private ApiTestFile getFileByTestId(String testId) {
|
||||
ApiTestFileExample ApiTestFileExample = new ApiTestFileExample();
|
||||
ApiTestFileExample.createCriteria().andTestIdEqualTo(testId);
|
||||
final List<ApiTestFile> ApiTestFiles = apiTestFileMapper.selectByExample(ApiTestFileExample);
|
||||
apiTestFileMapper.selectByExample(ApiTestFileExample);
|
||||
if (!CollectionUtils.isEmpty(ApiTestFiles)) {
|
||||
return ApiTestFiles.get(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateSchedule(Schedule request) {
|
||||
|
@ -312,17 +341,6 @@ public class APITestService {
|
|||
schedule.setType(ScheduleType.CRON.name());
|
||||
return schedule;
|
||||
}
|
||||
private ApiTestFile getFileByTestId(String testId) {
|
||||
ApiTestFileExample ApiTestFileExample = new ApiTestFileExample();
|
||||
ApiTestFileExample.createCriteria().andTestIdEqualTo(testId);
|
||||
final List<ApiTestFile> ApiTestFiles = apiTestFileMapper.selectByExample(ApiTestFileExample);
|
||||
apiTestFileMapper.selectByExample(ApiTestFileExample);
|
||||
if (!CollectionUtils.isEmpty(ApiTestFiles)) {
|
||||
return ApiTestFiles.get(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void addOrUpdateApiTestCronJob(Schedule request) {
|
||||
scheduleService.addOrUpdateCronJob(request, ApiTestJob.getJobKey(request.getResourceId()), ApiTestJob.getTriggerKey(request.getResourceId()), ApiTestJob.class);
|
||||
|
@ -398,7 +416,10 @@ public class APITestService {
|
|||
return schedules;
|
||||
}
|
||||
|
||||
public String runDebug(SaveAPITestRequest request, List<MultipartFile> bodyFiles,String runMode) {
|
||||
public String runDebug(SaveAPITestRequest request, MultipartFile file, List<MultipartFile> bodyFiles) {
|
||||
if (file == null) {
|
||||
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
|
||||
}
|
||||
updateTest(request);
|
||||
APITestResult apiTest = get(request.getId());
|
||||
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
|
||||
|
@ -409,7 +430,17 @@ public class APITestService {
|
|||
}
|
||||
String reportId = apiReportService.createDebugReport(apiTest);
|
||||
|
||||
jMeterService.run(request.getId(), request.getName(), request.getScenarioDefinition(), reportId,runMode);
|
||||
InputStream is = null;
|
||||
try {
|
||||
byte[] bytes = file.getBytes();
|
||||
// 解析 xml 处理 mock 数据
|
||||
bytes = JmeterDocumentParser.parse(bytes);
|
||||
is = new ByteArrayInputStream(bytes);
|
||||
} catch (IOException e) {
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
jMeterService.run(request.getId(), reportId, is);
|
||||
return reportId;
|
||||
}
|
||||
|
||||
|
@ -420,12 +451,10 @@ public class APITestService {
|
|||
}
|
||||
}
|
||||
|
||||
public void mergeCreate(SaveAPITestRequest request, List<String> selectIds) {
|
||||
ApiTest test = createTest(request);
|
||||
selectIds.forEach(sourceId -> copyBodyFiles(test.getId(), sourceId));
|
||||
}
|
||||
|
||||
public String getJMX(SaveAPITestRequest request) {
|
||||
return jMeterService.getJMX(jMeterService.getHashTree(request.getId(), request.getName(), request.getScenarioDefinition()));
|
||||
public void mergeCreate(SaveAPITestRequest request, MultipartFile file, List<String> selectIds) {
|
||||
ApiTest test = createTest(request, file);
|
||||
selectIds.forEach(sourceId -> {
|
||||
copyBodyFiles(test.getId(), sourceId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,6 +133,7 @@
|
|||
LEFT JOIN user ON user.id = r.user_id
|
||||
<where>
|
||||
r.test_id = #{testId}
|
||||
and r.status != 'Debug'
|
||||
</where>
|
||||
ORDER BY r.update_time DESC
|
||||
</select>
|
||||
|
|
|
@ -258,7 +258,8 @@
|
|||
</select>
|
||||
|
||||
<select id="list" resultType="io.metersphere.track.dto.TestCaseDTO">
|
||||
select test_case.* from test_case
|
||||
select <include refid="io.metersphere.base.mapper.TestCaseMapper.Base_Column_List"/>
|
||||
from test_case
|
||||
<where>
|
||||
<if test="request.combine != null">
|
||||
<include refid="combine">
|
||||
|
|
|
@ -95,8 +95,7 @@ public interface ParamConstants {
|
|||
PASSWORD("smtp.password", 4),
|
||||
SSL("smtp.ssl", 5),
|
||||
TLS("smtp.tls", 6),
|
||||
SMTP("smtp.smtp", 7);
|
||||
/* ANON("smtp.anon", 7);*/
|
||||
ANON("smtp.anon", 7);
|
||||
|
||||
private String key;
|
||||
private Integer value;
|
||||
|
|
|
@ -88,7 +88,7 @@ public class CompressUtils {
|
|||
gzip.finish();
|
||||
return obj.toByteArray();
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ public class CompressUtils {
|
|||
baos.flush();
|
||||
return baos.toByteArray();
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,10 +48,6 @@ public class JsonPathUtils {
|
|||
String o_json_path = "$" + jsonPath.next().replaceAll("/", ".");
|
||||
String value = JSONPath.eval(jsonObject, o_json_path).toString();
|
||||
|
||||
if(o_json_path.toLowerCase().contains("id")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(value.equals("") || value.equals("[]") || o_json_path.equals("")) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ public class ScriptEngineUtils {
|
|||
String script = IOUtils.toString(ScriptEngineUtils.class.getResource("/javascript/func.js"), StandardCharsets.UTF_8);
|
||||
engine.eval(script);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ public class ScriptEngineUtils {
|
|||
try {
|
||||
return engine.eval("calculate('" + input + "')").toString();
|
||||
} catch (ScriptException e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public class ShiroConfig implements EnvironmentAware {
|
|||
Map<String, String> filterChainDefinitionMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
|
||||
ShiroUtils.loadBaseFilterChain(filterChainDefinitionMap);
|
||||
filterChainDefinitionMap.put("/display/info", "anon");
|
||||
filterChainDefinitionMap.put("/display/file/*", "anon");
|
||||
filterChainDefinitionMap.put("/display/file/**", "anon");
|
||||
filterChainDefinitionMap.put("/**", "apikey, authc");
|
||||
return shiroFilterFactoryBean;
|
||||
}
|
||||
|
|
|
@ -53,13 +53,13 @@ public class TestResourcePoolController {
|
|||
|
||||
@GetMapping("list/all/valid")
|
||||
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER, RoleConstants.TEST_VIEWER}, logical = Logical.OR)
|
||||
public List<TestResourcePool> listValidResourcePools() {
|
||||
public List<TestResourcePoolDTO> listValidResourcePools() {
|
||||
return testResourcePoolService.listValidResourcePools();
|
||||
}
|
||||
|
||||
@GetMapping("list/quota/valid")
|
||||
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER, RoleConstants.TEST_VIEWER}, logical = Logical.OR)
|
||||
public List<TestResourcePool> listValidQuotaResourcePools() {
|
||||
public List<TestResourcePoolDTO> listValidQuotaResourcePools() {
|
||||
return testResourcePoolService.listValidQuotaResourcePools();
|
||||
}
|
||||
|
||||
|
|
|
@ -7,4 +7,5 @@ import lombok.Setter;
|
|||
@Setter
|
||||
public class QueryResourcePoolRequest {
|
||||
private String name;
|
||||
private String status;
|
||||
}
|
||||
|
|
|
@ -72,13 +72,15 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
|
|||
*/
|
||||
private void loadJars() {
|
||||
List<JarConfig> jars = jarConfigService.list();
|
||||
try {
|
||||
jars.forEach(jarConfig -> {
|
||||
|
||||
jars.forEach(jarConfig -> {
|
||||
try {
|
||||
NewDriverManager.loadJar(jarConfig.getPath());
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ public class DingTaskService {
|
|||
try {
|
||||
response = client.execute(request);
|
||||
} catch (ApiException e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
System.out.println(response.getErrcode());
|
||||
}
|
||||
|
|
|
@ -2,10 +2,7 @@ package io.metersphere.notice.service;
|
|||
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.UserMapper;
|
||||
import io.metersphere.commons.constants.APITestStatus;
|
||||
import io.metersphere.commons.constants.NoticeConstants;
|
||||
import io.metersphere.commons.constants.ParamConstants;
|
||||
import io.metersphere.commons.constants.PerformanceTestStatus;
|
||||
import io.metersphere.commons.constants.*;
|
||||
import io.metersphere.commons.user.SessionUser;
|
||||
import io.metersphere.commons.utils.EncryptUtils;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
|
@ -22,6 +19,7 @@ import io.metersphere.track.request.testreview.SaveTestCaseReviewRequest;
|
|||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.RegExUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.mail.MailException;
|
||||
|
@ -67,7 +65,7 @@ public class MailService {
|
|||
}
|
||||
sendApiOrLoadNotification(addresseeIdList(messageDetail, userIds, eventType), context, performanceTemplate, loadTestReport.getTriggerMode());
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,7 +86,7 @@ public class MailService {
|
|||
}
|
||||
sendApiOrLoadNotification(addresseeIdList(messageDetail, userIds, eventType), context, apiTemplate, apiTestReport.getTriggerMode());
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,7 +118,7 @@ public class MailService {
|
|||
try {
|
||||
javaMailSender.send(mimeMessage);
|
||||
} catch (MailException e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
//测试评审
|
||||
|
@ -131,7 +129,7 @@ public class MailService {
|
|||
String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/ReviewEnd.html"), StandardCharsets.UTF_8);
|
||||
sendReviewNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,7 +139,7 @@ public class MailService {
|
|||
String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/ReviewDelete.html"), StandardCharsets.UTF_8);
|
||||
sendReviewNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,7 +156,7 @@ public class MailService {
|
|||
String commentTemplate = IOUtils.toString(this.getClass().getResource("/mail/ReviewComments.html"), StandardCharsets.UTF_8);
|
||||
sendReviewNotice(addresseeIdList(messageDetail, userIds, eventType), context, commentTemplate);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,7 +166,7 @@ public class MailService {
|
|||
String reviewerTemplate = IOUtils.toString(this.getClass().getResource("/mail/ReviewInitiate.html"), StandardCharsets.UTF_8);
|
||||
sendReviewNotice(addresseeIdList(messageDetail, userIds, eventType), context, reviewerTemplate);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,7 +205,7 @@ public class MailService {
|
|||
String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/TestPlanStart.html"), StandardCharsets.UTF_8);
|
||||
sendTestPlanNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,7 +217,7 @@ public class MailService {
|
|||
String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/TestPlanEnd.html"), StandardCharsets.UTF_8);
|
||||
sendTestPlanNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -231,7 +229,7 @@ public class MailService {
|
|||
String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/TestPlanDelete.html"), StandardCharsets.UTF_8);
|
||||
sendTestPlanNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,7 +266,7 @@ public class MailService {
|
|||
String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/IssuesCreate.html"), StandardCharsets.UTF_8);
|
||||
sendIssuesNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -321,6 +319,15 @@ public class MailService {
|
|||
context.put("start", start);
|
||||
context.put("end", end);
|
||||
context.put("id", reviewRequest.getId());
|
||||
String status = "";
|
||||
if (StringUtils.equals(TestPlanStatus.Underway.name(), reviewRequest.getStatus())) {
|
||||
status = "进行中";
|
||||
} else if (StringUtils.equals(TestPlanStatus.Prepare.name(), reviewRequest.getStatus())) {
|
||||
status = "未开始";
|
||||
} else if (StringUtils.equals(TestPlanStatus.Completed.name(), reviewRequest.getStatus())) {
|
||||
status = "已完成";
|
||||
}
|
||||
context.put("status", status);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
@ -347,19 +354,29 @@ public class MailService {
|
|||
context.put("start", start);
|
||||
context.put("end", end);
|
||||
context.put("id", testPlan.getId());
|
||||
String status = "";
|
||||
if (StringUtils.equals(TestPlanStatus.Underway.name(), testPlan.getStatus())) {
|
||||
status = "进行中";
|
||||
} else if (StringUtils.equals(TestPlanStatus.Prepare.name(), testPlan.getStatus())) {
|
||||
status = "未开始";
|
||||
} else if (StringUtils.equals(TestPlanStatus.Completed.name(), testPlan.getStatus())) {
|
||||
status = "已完成";
|
||||
}
|
||||
context.put("status", status);
|
||||
User user = userMapper.selectByPrimaryKey(testPlan.getCreator());
|
||||
context.put("creator", user.getName());
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private JavaMailSenderImpl getMailSender() {
|
||||
Properties props = new Properties();
|
||||
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
|
||||
List<SystemParameter> paramList = systemParameterService.getParamList(ParamConstants.Classify.MAIL.getValue());
|
||||
javaMailSender.setDefaultEncoding("UTF-8");
|
||||
javaMailSender.setProtocol("smtps");
|
||||
javaMailSender.setProtocol("smtp");
|
||||
props.put("mail.smtp.auth", "true");
|
||||
|
||||
for (SystemParameter p : paramList) {
|
||||
switch (p.getParamKey()) {
|
||||
case "smtp.host":
|
||||
|
@ -374,14 +391,30 @@ public class MailService {
|
|||
case "smtp.password":
|
||||
javaMailSender.setPassword(EncryptUtils.aesDecrypt(p.getParamValue()).toString());
|
||||
break;
|
||||
case "smtp.ssl":
|
||||
javaMailSender.setProtocol("smtps");
|
||||
if (BooleanUtils.toBoolean(p.getParamValue())) {
|
||||
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
|
||||
}
|
||||
break;
|
||||
case "smtp.tls":
|
||||
String result = BooleanUtils.toString(BooleanUtils.toBoolean(p.getParamValue()), "true", "false");
|
||||
props.put("mail.smtp.starttls.enable", result);
|
||||
props.put("mail.smtp.starttls.required", result);
|
||||
break;
|
||||
case "smtp.anon":
|
||||
boolean isAnon = BooleanUtils.toBoolean(p.getParamValue());
|
||||
if (isAnon) {
|
||||
props.put("mail.smtp.auth", "false");
|
||||
javaMailSender.setUsername(null);
|
||||
javaMailSender.setPassword(null);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Properties props = new Properties();
|
||||
props.put("mail.smtp.auth", "true");
|
||||
props.put("mail.smtp.starttls.enable", "true");
|
||||
props.put("mail.smtp.starttls.required", "true");
|
||||
|
||||
props.put("mail.smtp.timeout", "30000");
|
||||
props.put("mail.smtp.connectiontimeout", "5000");
|
||||
javaMailSender.setJavaMailProperties(props);
|
||||
|
@ -396,6 +429,7 @@ public class MailService {
|
|||
} else {
|
||||
template = RegExUtils.replaceAll(template, "\\$\\{" + k + "}", "未设置");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return template;
|
||||
|
@ -405,7 +439,7 @@ public class MailService {
|
|||
List<String> addresseeIdList = new ArrayList<>();
|
||||
if (StringUtils.equals(eventType, messageDetail.getEvent())) {
|
||||
messageDetail.getUserIds().forEach(u -> {
|
||||
if (!StringUtils.equals(NoticeConstants.EXECUTOR, u) && !StringUtils.equals(NoticeConstants.EXECUTOR, u) && !StringUtils.equals(NoticeConstants.MAINTAINER, u)) {
|
||||
if (!StringUtils.equals(NoticeConstants.EXECUTOR, u) && !StringUtils.equals(NoticeConstants.FOUNDER, u) && !StringUtils.equals(NoticeConstants.MAINTAINER, u)) {
|
||||
addresseeIdList.add(u);
|
||||
}
|
||||
if (StringUtils.equals(NoticeConstants.CREATE, eventType) && StringUtils.equals(NoticeConstants.EXECUTOR, u)) {
|
||||
|
|
|
@ -13,6 +13,7 @@ import io.metersphere.notice.controller.request.MessageRequest;
|
|||
import io.metersphere.notice.domain.MessageDetail;
|
||||
import io.metersphere.notice.domain.MessageSettingDetail;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
@ -51,7 +52,7 @@ public class NoticeService {
|
|||
long time = System.currentTimeMillis();
|
||||
String identification = UUID.randomUUID().toString();
|
||||
list.getUserIds().forEach(m -> {
|
||||
checkUserIdExist(m, list);
|
||||
checkUserIdExist(m, list,orgId);
|
||||
MessageTask message = new MessageTask();
|
||||
message.setId(UUID.randomUUID().toString());
|
||||
message.setEvent(list.getEvent());
|
||||
|
@ -68,9 +69,13 @@ public class NoticeService {
|
|||
});
|
||||
}
|
||||
|
||||
private void checkUserIdExist(String userId, MessageDetail list) {
|
||||
private void checkUserIdExist(String userId, MessageDetail list,String orgId) {
|
||||
MessageTaskExample example = new MessageTaskExample();
|
||||
example.createCriteria().andUserIdEqualTo(userId).andEventEqualTo(list.getEvent()).andTypeEqualTo(list.getType()).andTaskTypeEqualTo(list.getTaskType()).andWebhookEqualTo(list.getWebhook());
|
||||
if (StringUtils.isBlank(list.getTestId())) {
|
||||
example.createCriteria().andUserIdEqualTo(userId).andEventEqualTo(list.getEvent()).andTypeEqualTo(list.getType()).andTaskTypeEqualTo(list.getTaskType()).andWebhookEqualTo(list.getWebhook()).andOrganizationIdEqualTo(orgId);
|
||||
} else {
|
||||
example.createCriteria().andUserIdEqualTo(userId).andEventEqualTo(list.getEvent()).andTypeEqualTo(list.getType()).andTaskTypeEqualTo(list.getTaskType()).andWebhookEqualTo(list.getWebhook()).andTestIdEqualTo(list.getTestId()).andOrganizationIdEqualTo(orgId);
|
||||
}
|
||||
if (messageTaskMapper.countByExample(example) > 0) {
|
||||
MSException.throwException(Translator.get("message_task_already_exists"));
|
||||
}
|
||||
|
@ -151,4 +156,4 @@ public class NoticeService {
|
|||
example.createCriteria().andIdentificationEqualTo(identification);
|
||||
return messageTaskMapper.deleteByExample(example);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ public class WxChatTaskService {
|
|||
SendResult result = WxChatbotClient.send(Webhook, message);
|
||||
System.out.println(result);
|
||||
} catch (IOException e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -139,10 +139,10 @@ public class EngineFactory {
|
|||
String content = engineSourceParser.parse(engineContext, source);
|
||||
engineContext.setContent(content);
|
||||
} catch (MSException e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
MSException.throwException(e);
|
||||
}
|
||||
|
||||
|
|
|
@ -64,10 +64,10 @@ public class DockerTestEngine extends AbstractEngine {
|
|||
try {
|
||||
context = EngineFactory.createContext(loadTest, resource.getId(), ratio, this.getStartTime(), this.getReportId(), resourceIndex);
|
||||
} catch (MSException e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
MSException.throwException(e);
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ public class PerformanceNoticeTask {
|
|||
//查询定时任务是否关闭
|
||||
Thread.sleep(1000 * 30);// 每分钟检查 loadtest 的状态
|
||||
} catch (InterruptedException e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -258,7 +258,7 @@ public class PerformanceTestService {
|
|||
soc.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
MSException.throwException(Translator.get("load_test_kafka_invalid"));
|
||||
}
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ public class PerformanceTestService {
|
|||
} catch (MSException e) {
|
||||
// 启动失败之后清理任务
|
||||
engine.stop();
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
loadTest.setStatus(PerformanceTestStatus.Error.name());
|
||||
loadTest.setDescription(e.getMessage());
|
||||
loadTestMapper.updateByPrimaryKeySelective(loadTest);
|
||||
|
|
|
@ -119,7 +119,7 @@ public class JarConfigService {
|
|||
file.createNewFile();
|
||||
FileUtil.copyStream(in, out);
|
||||
} catch (IOException e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
MSException.throwException(Translator.get("upload_fail"));
|
||||
}
|
||||
return filePath;
|
||||
|
|
|
@ -87,7 +87,14 @@ public class SystemParameterService {
|
|||
javaMailSender.setUsername(hashMap.get(ParamConstants.MAIL.ACCOUNT.getKey()));
|
||||
javaMailSender.setPassword(hashMap.get(ParamConstants.MAIL.PASSWORD.getKey()));
|
||||
Properties props = new Properties();
|
||||
props.put("mail.smtp.auth", "true");
|
||||
boolean isAnon = Boolean.parseBoolean(hashMap.get(ParamConstants.MAIL.ANON.getKey()));
|
||||
if (isAnon) {
|
||||
props.put("mail.smtp.auth", "false");
|
||||
javaMailSender.setUsername(null);
|
||||
javaMailSender.setPassword(null);
|
||||
} else {
|
||||
props.put("mail.smtp.auth", "true");
|
||||
}
|
||||
if (BooleanUtils.toBoolean(hashMap.get(ParamConstants.MAIL.SSL.getKey()))) {
|
||||
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
|
||||
}
|
||||
|
@ -100,7 +107,7 @@ public class SystemParameterService {
|
|||
try {
|
||||
javaMailSender.testConnection();
|
||||
} catch (MessagingException e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
MSException.throwException(Translator.get("connection_failed"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@ public class TestResourcePoolService {
|
|||
MSException.throwException("Resource Pool is invalid.");
|
||||
}
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -145,6 +145,9 @@ public class TestResourcePoolService {
|
|||
if (StringUtils.isNotBlank(request.getName())) {
|
||||
criteria.andNameLike(StringUtils.wrapIfMissing(request.getName(), "%"));
|
||||
}
|
||||
if (StringUtils.isNotBlank(request.getStatus())) {
|
||||
criteria.andStatusEqualTo(request.getStatus());
|
||||
}
|
||||
example.setOrderByClause("update_time desc");
|
||||
List<TestResourcePool> testResourcePools = testResourcePoolMapper.selectByExample(example);
|
||||
List<TestResourcePoolDTO> testResourcePoolDTOS = new ArrayList<>();
|
||||
|
@ -158,7 +161,7 @@ public class TestResourcePoolService {
|
|||
testResourcePoolDTO.setResources(testResources);
|
||||
testResourcePoolDTOS.add(testResourcePoolDTO);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
return testResourcePoolDTOS;
|
||||
|
@ -207,7 +210,7 @@ public class TestResourcePoolService {
|
|||
ResponseEntity<String> entity = restTemplateWithTimeOut.getForEntity(String.format(nodeControllerUrl, node.getIp(), node.getPort()), String.class);
|
||||
return HttpStatus.OK.equals(entity.getStatusCode());
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -232,7 +235,7 @@ public class TestResourcePoolService {
|
|||
return testResourcePoolMapper.selectByPrimaryKey(resourcePoolId);
|
||||
}
|
||||
|
||||
public List<TestResourcePool> listValidResourcePools() {
|
||||
public List<TestResourcePoolDTO> listValidResourcePools() {
|
||||
QueryResourcePoolRequest request = new QueryResourcePoolRequest();
|
||||
List<TestResourcePoolDTO> testResourcePools = listResourcePools(request);
|
||||
// 重新校验 pool
|
||||
|
@ -249,16 +252,15 @@ public class TestResourcePoolService {
|
|||
testResourcePoolMapper.updateByPrimaryKeySelective(pool);
|
||||
}
|
||||
}
|
||||
TestResourcePoolExample example = new TestResourcePoolExample();
|
||||
example.createCriteria().andStatusEqualTo(ResourceStatusEnum.VALID.name());
|
||||
return testResourcePoolMapper.selectByExample(example);
|
||||
request.setStatus(VALID.name());
|
||||
return listResourcePools(request);
|
||||
}
|
||||
|
||||
public List<TestResourcePool> listValidQuotaResourcePools() {
|
||||
public List<TestResourcePoolDTO> listValidQuotaResourcePools() {
|
||||
return filterQuota(listValidResourcePools());
|
||||
}
|
||||
|
||||
private List<TestResourcePool> filterQuota(List<TestResourcePool> list) {
|
||||
private List<TestResourcePoolDTO> filterQuota(List<TestResourcePoolDTO> list) {
|
||||
QuotaService quotaService = CommonBeanFactory.getBean(QuotaService.class);
|
||||
if (quotaService != null) {
|
||||
Set<String> pools = quotaService.getQuotaResourcePools();
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
package io.metersphere.track.issue;
|
||||
|
||||
import io.metersphere.commons.utils.EncryptUtils;
|
||||
|
||||
public class ZentaoUtils {
|
||||
|
||||
/**
|
||||
* @param code Zentao 应用代号
|
||||
* @param key Zentao 密钥
|
||||
* @return token
|
||||
*/
|
||||
public static String getToken(String code, String key, String time) {
|
||||
return (String) EncryptUtils.md5Encrypt(code + key + time);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param url Zentao url
|
||||
* @param code Zentao 应用代号
|
||||
* @param key Zentao 密钥
|
||||
* @return url
|
||||
*/
|
||||
public static String getUrl(String url, String code, String key) {
|
||||
String time = String.valueOf(System.currentTimeMillis());;
|
||||
return url + "api.php?" + "code=" + code + "&time=" + time + "&token=" + getToken(code, key, time);
|
||||
}
|
||||
}
|
|
@ -116,7 +116,7 @@ public class IssuesService {
|
|||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ public class TestCaseCommentService {
|
|||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ public class TestCaseReviewService {
|
|||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -187,27 +187,25 @@ public class TestCaseReviewService {
|
|||
testCaseReviewMapper.updateByPrimaryKeySelective(testCaseReview);
|
||||
List<String> userIds = new ArrayList<>();
|
||||
userIds.addAll(testCaseReview.getUserIds());
|
||||
if (StringUtils.equals(TestPlanStatus.Completed.name(), testCaseReview.getStatus())) {
|
||||
try {
|
||||
String context = getReviewContext(testCaseReview, NoticeConstants.UPDATE);
|
||||
MessageSettingDetail messageSettingDetail = noticeService.searchMessage();
|
||||
List<MessageDetail> taskList = messageSettingDetail.getReviewTask();
|
||||
taskList.forEach(r -> {
|
||||
switch (r.getType()) {
|
||||
case NoticeConstants.NAIL_ROBOT:
|
||||
dingTaskService.sendNailRobot(r, userIds, context, NoticeConstants.UPDATE);
|
||||
break;
|
||||
case NoticeConstants.WECHAT_ROBOT:
|
||||
wxChatTaskService.sendWechatRobot(r, userIds, context, NoticeConstants.UPDATE);
|
||||
break;
|
||||
case NoticeConstants.EMAIL:
|
||||
mailService.sendReviewerNotice(r, userIds, testCaseReview, NoticeConstants.UPDATE);
|
||||
break;
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
}
|
||||
try {
|
||||
String context = getReviewContext(testCaseReview, NoticeConstants.UPDATE);
|
||||
MessageSettingDetail messageSettingDetail = noticeService.searchMessage();
|
||||
List<MessageDetail> taskList = messageSettingDetail.getReviewTask();
|
||||
taskList.forEach(r -> {
|
||||
switch (r.getType()) {
|
||||
case NoticeConstants.NAIL_ROBOT:
|
||||
dingTaskService.sendNailRobot(r, userIds, context, NoticeConstants.UPDATE);
|
||||
break;
|
||||
case NoticeConstants.WECHAT_ROBOT:
|
||||
wxChatTaskService.sendWechatRobot(r, userIds, context, NoticeConstants.UPDATE);
|
||||
break;
|
||||
case NoticeConstants.EMAIL:
|
||||
mailService.sendEndNotice(r, userIds, testCaseReview, NoticeConstants.UPDATE);
|
||||
break;
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -318,7 +316,7 @@ public class TestCaseReviewService {
|
|||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -468,7 +466,7 @@ public class TestCaseReviewService {
|
|||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -585,7 +583,15 @@ public class TestCaseReviewService {
|
|||
if (StringUtils.equals(NoticeConstants.CREATE, type)) {
|
||||
context = "测试评审任务通知:" + user.getName() + "发起的" + "'" + reviewRequest.getName() + "'" + "待开始,计划开始时间是" + start + "计划结束时间为" + end + "请跟进";
|
||||
} else if (StringUtils.equals(NoticeConstants.UPDATE, type)) {
|
||||
context = "测试评审任务通知:" + user.getName() + "发起的" + "'" + reviewRequest.getName() + "'" + "已完成,计划开始时间是" + start + "计划结束时间为" + end + "已完成";
|
||||
String status = "";
|
||||
if (StringUtils.equals(TestPlanStatus.Underway.name(), reviewRequest.getStatus())) {
|
||||
status = "进行中";
|
||||
} else if (StringUtils.equals(TestPlanStatus.Prepare.name(), reviewRequest.getStatus())) {
|
||||
status = "未开始";
|
||||
} else if (StringUtils.equals(TestPlanStatus.Completed.name(), reviewRequest.getStatus())) {
|
||||
status = "已完成";
|
||||
}
|
||||
context = "测试评审任务通知:" + user.getName() + "发起的" + "'" + reviewRequest.getName() + "'" + "计划开始时间是" + start + "计划结束时间为" + end + status;
|
||||
} else if (StringUtils.equals(NoticeConstants.DELETE, type)) {
|
||||
context = "测试评审任务通知:" + user.getName() + "发起的" + "'" + reviewRequest.getName() + "'" + "计划开始时间是" + start + "计划结束时间为" + end + "已删除";
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ public class TestPlanService {
|
|||
@Resource
|
||||
UserMapper userMapper;
|
||||
|
||||
public void addTestPlan(AddTestPlanRequest testPlan) {
|
||||
public synchronized void addTestPlan(AddTestPlanRequest testPlan) {
|
||||
if (getTestPlanByName(testPlan.getName()).size() > 0) {
|
||||
MSException.throwException(Translator.get("plan_name_already_exists"));
|
||||
}
|
||||
|
@ -137,11 +137,11 @@ public class TestPlanService {
|
|||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized List<TestPlan> getTestPlanByName(String name) {
|
||||
public List<TestPlan> getTestPlanByName(String name) {
|
||||
TestPlanExample example = new TestPlanExample();
|
||||
example.createCriteria().andWorkspaceIdEqualTo(SessionUtils.getCurrentWorkspaceId())
|
||||
.andNameEqualTo(name);
|
||||
|
@ -159,13 +159,16 @@ public class TestPlanService {
|
|||
//进行中状态,写入实际开始时间
|
||||
if (TestPlanStatus.Underway.name().equals(testPlan.getStatus())) {
|
||||
testPlan.setActualStartTime(System.currentTimeMillis());
|
||||
|
||||
} else if (TestPlanStatus.Completed.name().equals(testPlan.getStatus())) {
|
||||
List<String> userIds = new ArrayList<>();
|
||||
userIds.add(testPlan.getPrincipal());
|
||||
AddTestPlanRequest testPlans = new AddTestPlanRequest();
|
||||
//已完成,写入实际完成时间
|
||||
testPlan.setActualEndTime(System.currentTimeMillis());
|
||||
|
||||
}
|
||||
List<String> userIds = new ArrayList<>();
|
||||
userIds.add(testPlan.getPrincipal());
|
||||
AddTestPlanRequest testPlans = new AddTestPlanRequest();
|
||||
int i = testPlanMapper.updateByPrimaryKeySelective(testPlan);
|
||||
if (!StringUtils.isBlank(testPlan.getStatus())) {
|
||||
try {
|
||||
BeanUtils.copyBean(testPlans, getTestPlan(testPlan.getId()));
|
||||
String context = getTestPlanContext(testPlans, NoticeConstants.UPDATE);
|
||||
|
@ -180,16 +183,15 @@ public class TestPlanService {
|
|||
wxChatTaskService.sendWechatRobot(r, userIds, context, NoticeConstants.UPDATE);
|
||||
break;
|
||||
case NoticeConstants.EMAIL:
|
||||
mailService.sendTestPlanStartNotice(r, userIds, testPlans, NoticeConstants.UPDATE);
|
||||
mailService.sendTestPlanEndNotice(r, userIds, testPlans, NoticeConstants.UPDATE);
|
||||
break;
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return testPlanMapper.updateByPrimaryKeySelective(testPlan);
|
||||
return i;
|
||||
}
|
||||
|
||||
private void editTestPlanProject(TestPlanDTO testPlan) {
|
||||
|
@ -270,7 +272,7 @@ public class TestPlanService {
|
|||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
@ -511,7 +513,7 @@ public class TestPlanService {
|
|||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -557,11 +559,19 @@ public class TestPlanService {
|
|||
}
|
||||
String context = "";
|
||||
if (StringUtils.equals(NoticeConstants.CREATE, type)) {
|
||||
context = "测试计划任务通知:" + user.getName() + "创建的" + "'" + testPlan.getName() + "'" + "待开始,计划开始时间是" + start + "计划结束时间为" + end + "请跟进";
|
||||
context = "测试计划任务通知:" + user.getName() + "创建的" + "'" + testPlan.getName() + "'" + "待开始,计划开始时间是:" + "'" + start + "'" + ";" + "计划结束时间是:" + "'" + end + "'" + " " + "请跟进";
|
||||
} else if (StringUtils.equals(NoticeConstants.UPDATE, type)) {
|
||||
context = "测试计划任务通知:" + user.getName() + "创建的" + "'" + testPlan.getName() + "'" + "已完成,计划开始时间是" + start + "计划结束时间为" + end + "已完成";
|
||||
String status = "";
|
||||
if (StringUtils.equals(TestPlanStatus.Underway.name(), testPlan.getStatus())) {
|
||||
status = "进行中";
|
||||
} else if (StringUtils.equals(TestPlanStatus.Prepare.name(), testPlan.getStatus())) {
|
||||
status = "未开始";
|
||||
} else if (StringUtils.equals(TestPlanStatus.Completed.name(), testPlan.getStatus())) {
|
||||
status = "已完成";
|
||||
}
|
||||
context = "测试计划任务通知:" + user.getName() + "创建的" + "'" + testPlan.getName() + "'" + "计划开始时间是:" + "'" + start + "'" + ";" + "计划结束时间是:" + "'" + end + "'" + " " + status;
|
||||
} else if (StringUtils.equals(NoticeConstants.DELETE, type)) {
|
||||
context = "测试计划任务通知:" + user.getName() + "创建的" + "'" + testPlan.getName() + "'" + "计划开始时间是" + start + "计划结束时间为" + end + "已删除";
|
||||
context = "测试计划任务通知:" + user.getName() + "创建的" + "'" + testPlan.getName() + "'" + "计划开始时间是:" + "'" + start + "'" + ";" + "计划结束时间是:" + "'" + end + "'" + " " + "已删除";
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ public class ReportWebSocket {
|
|||
}
|
||||
Thread.sleep(20 * 1000L);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -231,7 +231,7 @@ public class XmindCaseParser {
|
|||
JSONObject step = new JSONObject(true);
|
||||
step.put("num", i + 1);
|
||||
step.put("desc", attacheds.get(i).getTitle());
|
||||
if (attacheds.get(i) != null && attacheds.get(i).getChildren() != null && attacheds.get(i).getChildren().getAttached()!=null) {
|
||||
if (attacheds.get(i) != null && attacheds.get(i).getChildren() != null && attacheds.get(i).getChildren().getAttached() != null) {
|
||||
step.put("result", attacheds.get(i).getChildren().getAttached().get(0).getTitle());
|
||||
}
|
||||
jsonArray.add(step);
|
||||
|
@ -283,17 +283,20 @@ public class XmindCaseParser {
|
|||
|
||||
// 测试步骤处理
|
||||
List<Attached> steps = new LinkedList<>();
|
||||
StringBuilder rc = new StringBuilder();
|
||||
if (attacheds != null && !attacheds.isEmpty()) {
|
||||
attacheds.forEach(item -> {
|
||||
if (isAvailable(item.getTitle(), PC_REGEX)) {
|
||||
testCase.setPrerequisite(replace(item.getTitle(), PC_REGEX));
|
||||
} else if (isAvailable(item.getTitle(), RC_REGEX)) {
|
||||
testCase.setRemark(replace(item.getTitle(), RC_REGEX));
|
||||
rc.append(replace(item.getTitle(), RC_REGEX));
|
||||
rc.append("\n");
|
||||
} else {
|
||||
steps.add(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
testCase.setRemark(rc.toString());
|
||||
testCase.setSteps(this.getSteps(steps));
|
||||
testCases.add(testCase);
|
||||
// 校验合规性
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<p style="text-align: left"> ${maintainer} 维护的<br/>
|
||||
<p style="text-align: left"> ${maintainer}为 <br/>
|
||||
${testCaseName}<br/>
|
||||
添加评论:${description}<br/>
|
||||
点击下面链接进入用例评审页面</p>
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
<body>
|
||||
<div>
|
||||
<p style="text-align: left">${creator} 发起的:<br>
|
||||
${reviewName}已完成<br>
|
||||
${reviewName}<br>
|
||||
计划开始时间是:${start}<br>
|
||||
计划结束时间为:${end}<br>
|
||||
已完成<br>
|
||||
${status}<br>
|
||||
点击下面链接进入用例评审页面</p>
|
||||
<a href="${url}/#/track/review/view">${url}/#/track/review/view</a>
|
||||
</div>
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
<body>
|
||||
<div>
|
||||
<p style="text-align: left">${creator} 创建的:<br>
|
||||
${testPlanName}已完成<br>
|
||||
${testPlanName}<br>
|
||||
计划开始时间是:${start}<br>
|
||||
计划结束时间为:${end}<br>
|
||||
已完成!<br>
|
||||
${status}!<br>
|
||||
点击下面链接进入测试计划页面</p>
|
||||
<a href="${url}/#/track/plan/view/${id}">${url}/#/track/plan/view</a>
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<artifactId>metersphere-server</artifactId>
|
||||
<groupId>io.metersphere</groupId>
|
||||
<version>1.4</version>
|
||||
<version>1.5</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
</el-row>
|
||||
<el-row id="header-top" type="flex" justify="space-between" align="middle">
|
||||
<el-col :span="12">
|
||||
<img v-if="logoId" :src="'/display/file/' + logoId" style="width: 156px;height: 37px;" alt="">
|
||||
<a v-else class="logo"/>
|
||||
<img :src="'/display/file/logo'" style="width: 156px;height: 37px;" alt="">
|
||||
<ms-top-menus/>
|
||||
</el-col>
|
||||
|
||||
|
|
|
@ -46,10 +46,9 @@ import MsScenarioResults from "./components/ScenarioResults";
|
|||
import MsContainer from "@/business/components/common/components/MsContainer";
|
||||
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
|
||||
import MsApiReportExport from "./ApiReportExport";
|
||||
import {exportPdf} from "@/common/js/utils";
|
||||
import html2canvas from "html2canvas";
|
||||
import MsApiReportViewHeader from "./ApiReportViewHeader";
|
||||
import {RequestFactory} from "../test/model/ScenarioModel";
|
||||
import {windowPrint} from "../../../../common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "MsApiReportViewDetail",
|
||||
|
@ -154,23 +153,16 @@ export default {
|
|||
this.scenarioName = requestResult.scenarioName;
|
||||
});
|
||||
},
|
||||
handleExport(name) {
|
||||
this.loading = true;
|
||||
handleExport() {
|
||||
this.reportExportVisible = true;
|
||||
let reset = this.exportReportReset;
|
||||
|
||||
this.$nextTick(function () {
|
||||
html2canvas(document.getElementById('apiTestReport'), {
|
||||
// scale: 2,
|
||||
}).then(function (canvas) {
|
||||
exportPdf(name, [canvas]);
|
||||
reset();
|
||||
});
|
||||
this.$nextTick(() => {
|
||||
windowPrint('apiTestReport', 0.57);
|
||||
reset();
|
||||
});
|
||||
},
|
||||
exportReportReset() {
|
||||
this.reportExportVisible = false;
|
||||
this.loading = false;
|
||||
this.$router.go(0);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ export default {
|
|||
methods: {
|
||||
search() {
|
||||
this.condition.excludeId = this.excludeId;
|
||||
this.condition.projectId = this.projectId;
|
||||
let url = "/api/list/" + this.currentPage + "/" + this.pageSize;
|
||||
this.result = this.$post(url, this.condition, response => {
|
||||
let data = response.data;
|
||||
|
|
|
@ -17,10 +17,9 @@
|
|||
:scenario="scenario"
|
||||
:extract="extract"
|
||||
type="body"
|
||||
:description="$t('api_test.request.parameters_desc')"
|
||||
v-if="body.isKV()"/>
|
||||
<div class="body-raw" v-if="body.type == 'Raw'">
|
||||
<ms-code-edit :mode="body.format" :read-only="isReadOnly" :data.sync="body.raw" :modes="modes" ref="codeEdit"/>
|
||||
<ms-code-edit :mode="body.format" :enable-format="false" :read-only="isReadOnly" :data.sync="body.raw" :modes="modes" ref="codeEdit"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('api_test.request.sql.pool_max')" prop="poolMax">
|
||||
<el-input-number size="small" :disabled="isReadOnly" v-model="currentConfig.poolMax" :placeholder="$t('commons.please_select')" :max="1000*10000000" :min="0"/>
|
||||
<el-input-number size="small" :disabled="isReadOnly" v-model="currentConfig.poolMax" :placeholder="$t('commons.please_select')" :max="100" :min="0"/>
|
||||
</el-form-item>
|
||||
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ export class Test extends BaseConfig {
|
|||
constructor(options) {
|
||||
super();
|
||||
this.type = "MS API CONFIG";
|
||||
this.version = '1.4.0';
|
||||
this.version = '1.5.0';
|
||||
this.id = uuid();
|
||||
this.name = undefined;
|
||||
this.projectId = undefined;
|
||||
|
@ -609,8 +609,8 @@ export class DatabaseConfig extends BaseConfig {
|
|||
super();
|
||||
this.id = undefined;
|
||||
this.name = undefined;
|
||||
this.poolMax = undefined;
|
||||
this.timeout = undefined;
|
||||
this.poolMax = 1;
|
||||
this.timeout = 100000;
|
||||
this.driver = undefined;
|
||||
this.dbUrl = undefined;
|
||||
this.username = undefined;
|
||||
|
|
|
@ -28,6 +28,12 @@
|
|||
init: {
|
||||
type: Function
|
||||
},
|
||||
enableFormat: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
|
@ -74,20 +80,24 @@
|
|||
}
|
||||
},
|
||||
format() {
|
||||
switch (this.mode) {
|
||||
case 'json':
|
||||
this.formatData = formatJson(this.data);
|
||||
break;
|
||||
case 'html':
|
||||
this.formatData = toDiffableHtml(this.data);
|
||||
break;
|
||||
case 'xml':
|
||||
this.formatData = formatXml(this.data);
|
||||
break;
|
||||
default:
|
||||
if (this.data) {
|
||||
this.formatData = this.data;
|
||||
}
|
||||
if (this.enableFormat) {
|
||||
switch (this.mode) {
|
||||
case 'json':
|
||||
this.formatData = formatJson(this.data);
|
||||
break;
|
||||
case 'html':
|
||||
this.formatData = toDiffableHtml(this.data);
|
||||
break;
|
||||
case 'xml':
|
||||
this.formatData = formatXml(this.data);
|
||||
break;
|
||||
default:
|
||||
if (this.data) {
|
||||
this.formatData = this.data;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.formatData = this.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
<br/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row class="tip" v-if="withTip">
|
||||
<span>
|
||||
<slot class="tip"></slot>
|
||||
</span>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="15">
|
||||
<el-input v-model="value" :placeholder="$t('commons.input_content')"/>
|
||||
|
@ -41,6 +46,12 @@
|
|||
default() {
|
||||
return this.$t('commons.title')
|
||||
}
|
||||
},
|
||||
withTip: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -80,5 +91,9 @@
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tip {
|
||||
margin-bottom: 20px;
|
||||
color: red;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -73,7 +73,9 @@
|
|||
this.$emit('scheduleChange');
|
||||
},
|
||||
flashResultList() {
|
||||
this.$refs.crontabResult.expressionChange();
|
||||
if (this.$refs.crontabResult) {
|
||||
this.$refs.crontabResult.expressionChange();
|
||||
}
|
||||
},
|
||||
cancelRefresh() {
|
||||
if (this.refreshScheduler) {
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
</el-dialog>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('schedule.task_notification')" name="second">
|
||||
<schedule-task-notification :test-id="testId" :schedule-receiver-options="scheduleReceiverOptions"></schedule-task-notification>
|
||||
<schedule-task-notification :is-tester-permission="isTesterPermission" :test-id="testId" :schedule-receiver-options="scheduleReceiverOptions"></schedule-task-notification>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
|
@ -46,6 +46,7 @@ import CrontabResult from "../cron/CrontabResult";
|
|||
import {cronValidate} from "@/common/js/cron";
|
||||
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
|
||||
import ScheduleTaskNotification from "../../settings/organization/components/ScheduleTaskNotification";
|
||||
import {checkoutTestManagerOrTestUser} from "../../../../common/js/utils";
|
||||
function defaultCustomValidate() {
|
||||
return {pass: true};
|
||||
}
|
||||
|
@ -113,10 +114,13 @@ export default {
|
|||
name: '',
|
||||
organizationId: this.currentUser().lastOrganizationId
|
||||
};
|
||||
this.result = this.$post('user/org/member/list/all', param, response => {
|
||||
this.scheduleReceiverOptions = response.data
|
||||
|
||||
});
|
||||
if (this.isTesterPermission) {
|
||||
this.result = this.$post('user/org/member/list/all', param, response => {
|
||||
this.scheduleReceiverOptions = response.data
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
/* handleClick() {
|
||||
if (this.activeName === "second") {
|
||||
|
@ -188,6 +192,11 @@ export default {
|
|||
let time1 = new Date(resultList[0]);
|
||||
let time2 = new Date(resultList[1]);
|
||||
return time2 - time1;
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isTesterPermission() {
|
||||
return checkoutTestManagerOrTestUser();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="report-right">
|
||||
<div class="test">
|
||||
<img class="logo" src="@/assets/logo-MeterSphere.png">
|
||||
</div>
|
||||
<img class="logo" src="@/assets/logo-MeterSphere.png">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -271,12 +271,14 @@ export default {
|
|||
let reset = this.exportReportReset;
|
||||
|
||||
this.$nextTick(function () {
|
||||
html2canvas(document.getElementById('performanceReportExport'), {
|
||||
// scale: 2
|
||||
}).then(function (canvas) {
|
||||
exportPdf(name, [canvas]);
|
||||
reset();
|
||||
});
|
||||
setTimeout(() => {
|
||||
html2canvas(document.getElementById('performanceReportExport'), {
|
||||
scale: 2
|
||||
}).then(function (canvas) {
|
||||
exportPdf(name, [canvas]);
|
||||
reset();
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
},
|
||||
exportReportReset() {
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
:placeholder="$t('load_test.input_thread_num')"
|
||||
v-model="threadGroup.threadNumber"
|
||||
@change="calculateChart(threadGroup)"
|
||||
:min="1"
|
||||
:min="resourcePoolResourceLength"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<br>
|
||||
|
@ -141,6 +141,7 @@ export default {
|
|||
activeNames: ["0"],
|
||||
threadGroups: [],
|
||||
serializeThreadgroups: false,
|
||||
resourcePoolResourceLength: 1
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
@ -368,6 +369,11 @@ export default {
|
|||
if (handler.rampUpTime < handler.step) {
|
||||
handler.step = handler.rampUpTime;
|
||||
}
|
||||
// 线程数不能小于资源池节点的数量
|
||||
let resourcePool = this.resourcePools.filter(v => v.id === this.resourcePool)[0];
|
||||
if (resourcePool) {
|
||||
this.resourcePoolResourceLength = resourcePool.resources.length;
|
||||
}
|
||||
handler.options = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
|
|
|
@ -204,6 +204,7 @@ export default {
|
|||
});
|
||||
}
|
||||
},
|
||||
|
||||
submit(formName) {
|
||||
this.$refs[formName].validate((valid) => {
|
||||
if (valid) {
|
||||
|
@ -282,7 +283,18 @@ export default {
|
|||
},
|
||||
openEnvironmentConfig(project) {
|
||||
this.$refs.environmentConfig.open(project.id);
|
||||
}
|
||||
},
|
||||
handleEvent(event) {
|
||||
if (event.keyCode === 13) {
|
||||
this.submit('form')
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
document.addEventListener('keydown', this.handleEvent)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener('keydown', this.handleEvent);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div>
|
||||
<el-row>
|
||||
<el-col :span="10">
|
||||
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel('scheduleTask')">
|
||||
<el-button :disabled="!isTesterPermission" icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel('scheduleTask')">
|
||||
{{ $t('organization.message.create_new_notification') }}
|
||||
</el-button>
|
||||
</el-col>
|
||||
|
@ -69,12 +69,14 @@
|
|||
type="primary"
|
||||
size="mini"
|
||||
v-show="scope.row.isSet"
|
||||
:disabled="!isTesterPermission"
|
||||
@click="handleAddTask(scope.$index,scope.row)"
|
||||
>{{ $t('commons.add') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
v-show="scope.row.isSet"
|
||||
:disabled="!isTesterPermission"
|
||||
@click.native.prevent="removeRowTask(scope.$index,form.scheduleTask)"
|
||||
>{{ $t('commons.cancel') }}
|
||||
</el-button>
|
||||
|
@ -82,6 +84,7 @@
|
|||
type="primary"
|
||||
size="mini"
|
||||
v-show="!scope.row.isSet"
|
||||
:disabled="!isTesterPermission"
|
||||
@click="handleEditTask(scope.$index,scope.row)"
|
||||
>{{ $t('commons.edit') }}</el-button>
|
||||
<el-button
|
||||
|
@ -89,6 +92,7 @@
|
|||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
v-show="!scope.row.isSet"
|
||||
:disabled="!isTesterPermission"
|
||||
@click.native.prevent="deleteRowTask(scope.$index,scope.row)"
|
||||
></el-button>
|
||||
</template>
|
||||
|
@ -106,6 +110,10 @@ export default {
|
|||
props: {
|
||||
testId:String,
|
||||
scheduleReceiverOptions:Array,
|
||||
isTesterPermission: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -120,7 +128,6 @@ export default {
|
|||
identification: "",
|
||||
isReadOnly: false,
|
||||
testId:this.testId,
|
||||
|
||||
}],
|
||||
},
|
||||
scheduleEventOptions: [
|
||||
|
@ -193,7 +200,6 @@ export default {
|
|||
},
|
||||
addTask(data) {
|
||||
let list = [];
|
||||
data.isSet = false;
|
||||
list.push(data);
|
||||
let param = {};
|
||||
param.messageDetail = list;
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
import MsDialogFooter from "../../common/components/MsDialogFooter";
|
||||
import {getCurrentUser, listenGoBack, removeGoBackListener} from "../../../../common/js/utils";
|
||||
import MsTableOperatorButton from "../../common/components/MsTableOperatorButton";
|
||||
import {PHONE_REGEX} from "@/common/js/regex";
|
||||
|
||||
export default {
|
||||
name: "MsPersonSetting",
|
||||
|
@ -115,7 +116,7 @@
|
|||
phone: [
|
||||
{
|
||||
required: false,
|
||||
pattern: '^1(3|4|5|7|8)\\d{9}$',
|
||||
pattern: PHONE_REGEX,
|
||||
message: this.$t('member.mobile_number_format_is_incorrect'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
<el-checkbox v-model="formInline.TLS" :label="$t('system_parameter_setting.TLS')"></el-checkbox>
|
||||
</div>
|
||||
<div style="border: 0px;margin-bottom: 20px">
|
||||
<el-checkbox v-model="formInline.SMTP" :label="$t('system_parameter_setting.SMTP')"></el-checkbox>
|
||||
<el-checkbox v-model="formInline.ANON" :label="$t('system_parameter_setting.SMTP')"></el-checkbox>
|
||||
</div>
|
||||
<template v-slot:footer>
|
||||
</template>
|
||||
|
@ -120,7 +120,7 @@ export default {
|
|||
this.$set(this.formInline, "password", response.data[3].paramValue);
|
||||
this.$set(this.formInline, "SSL", JSON.parse(response.data[4].paramValue));
|
||||
this.$set(this.formInline, "TLS", JSON.parse(response.data[5].paramValue));
|
||||
this.$set(this.formInline, "SMTP", JSON.parse(response.data[6].paramValue));
|
||||
this.$set(this.formInline, "ANON", JSON.parse(response.data[6].paramValue));
|
||||
this.$nextTick(() => {
|
||||
this.$refs.formInline.clearValidate();
|
||||
})
|
||||
|
@ -143,7 +143,7 @@ export default {
|
|||
"smtp.password": this.formInline.password,
|
||||
"smtp.ssl": this.formInline.SSL,
|
||||
"smtp.tls": this.formInline.TLS,
|
||||
"smtp.smtp": this.formInline.SMTP,
|
||||
"smtp.anon": this.formInline.ANON,
|
||||
};
|
||||
this.$refs[formInline].validate((valid) => {
|
||||
if (valid) {
|
||||
|
@ -173,7 +173,7 @@ export default {
|
|||
{paramKey: "smtp.password", paramValue: this.formInline.password, type: "password", sort: 4},
|
||||
{paramKey: "smtp.ssl", paramValue: this.formInline.SSL, type: "text", sort: 5},
|
||||
{paramKey: "smtp.tls", paramValue: this.formInline.TLS, type: "text", sort: 6},
|
||||
{paramKey: "smtp.smtp", paramValue: this.formInline.SMTP, type: "text", sort: 7}
|
||||
{paramKey: "smtp.anon", paramValue: this.formInline.ANON, type: "text", sort: 7}
|
||||
]
|
||||
|
||||
this.$refs[formInline].validate(valid => {
|
||||
|
|
|
@ -338,6 +338,7 @@ import {hasRole, listenGoBack, removeGoBackListener} from "@/common/js/utils";
|
|||
import MsRolesTag from "../../common/components/MsRolesTag";
|
||||
import {ROLE_ADMIN} from "@/common/js/constants";
|
||||
import {getCurrentUser} from "../../../../common/js/utils";
|
||||
import {PHONE_REGEX} from "@/common/js/regex";
|
||||
|
||||
export default {
|
||||
name: "MsUser",
|
||||
|
@ -380,7 +381,7 @@ export default {
|
|||
rule: {
|
||||
id: [
|
||||
{required: true, message: this.$t('user.input_id'), trigger: 'blur'},
|
||||
{min: 2, max: 50, message: this.$t('commons.input_limit', [2, 50]), trigger: 'blur'},
|
||||
{min: 1, max: 50, message: this.$t('commons.input_limit', [1, 50]), trigger: 'blur'},
|
||||
{
|
||||
required: true,
|
||||
pattern: '^[^\u4e00-\u9fa5]+$',
|
||||
|
@ -401,7 +402,7 @@ export default {
|
|||
{required: true, message: this.$t('user.input_phone'), trigger: 'blur'},
|
||||
{
|
||||
required: true,
|
||||
pattern: '^1(3|4|5|7|8)\\d{9}$',
|
||||
pattern: PHONE_REGEX,
|
||||
message: this.$t('user.mobile_number_format_is_incorrect'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
|
|
|
@ -55,204 +55,205 @@
|
|||
|
||||
<script>
|
||||
|
||||
import NodeTree from '../common/NodeTree';
|
||||
import TestCaseEdit from './components/TestCaseEdit';
|
||||
import {CURRENT_PROJECT, ROLE_TEST_MANAGER, ROLE_TEST_USER} from '../../../../common/js/constants';
|
||||
import TestCaseList from "./components/TestCaseList";
|
||||
import SelectMenu from "../common/SelectMenu";
|
||||
import TestCaseMove from "./components/TestCaseMove";
|
||||
import MsContainer from "../../common/components/MsContainer";
|
||||
import MsAsideContainer from "../../common/components/MsAsideContainer";
|
||||
import MsMainContainer from "../../common/components/MsMainContainer";
|
||||
import {checkoutTestManagerOrTestUser, hasRoles} from "../../../../common/js/utils";
|
||||
import BatchMove from "./components/BatchMove";
|
||||
import NodeTree from '../common/NodeTree';
|
||||
import TestCaseEdit from './components/TestCaseEdit';
|
||||
import {CURRENT_PROJECT, ROLE_TEST_MANAGER, ROLE_TEST_USER} from '../../../../common/js/constants';
|
||||
import TestCaseList from "./components/TestCaseList";
|
||||
import SelectMenu from "../common/SelectMenu";
|
||||
import TestCaseMove from "./components/TestCaseMove";
|
||||
import MsContainer from "../../common/components/MsContainer";
|
||||
import MsAsideContainer from "../../common/components/MsAsideContainer";
|
||||
import MsMainContainer from "../../common/components/MsMainContainer";
|
||||
import {checkoutTestManagerOrTestUser, hasRoles} from "../../../../common/js/utils";
|
||||
import BatchMove from "./components/BatchMove";
|
||||
|
||||
export default {
|
||||
name: "TestCase",
|
||||
components: {
|
||||
MsMainContainer,
|
||||
MsAsideContainer, MsContainer, TestCaseMove, TestCaseList, NodeTree, TestCaseEdit, SelectMenu, BatchMove},
|
||||
comments: {},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
total: 0,
|
||||
projects: [],
|
||||
currentProject: null,
|
||||
treeNodes: [],
|
||||
selectNodeIds: [],
|
||||
selectParentNodes: [],
|
||||
testCaseReadOnly: true,
|
||||
selectNode: {},
|
||||
nodeTreeDraggable: true,
|
||||
export default {
|
||||
name: "TestCase",
|
||||
components: {
|
||||
MsMainContainer,
|
||||
MsAsideContainer, MsContainer, TestCaseMove, TestCaseList, NodeTree, TestCaseEdit, SelectMenu, BatchMove
|
||||
},
|
||||
comments: {},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
total: 0,
|
||||
projects: [],
|
||||
currentProject: null,
|
||||
treeNodes: [],
|
||||
selectNodeIds: [],
|
||||
selectParentNodes: [],
|
||||
testCaseReadOnly: true,
|
||||
selectNode: {},
|
||||
nodeTreeDraggable: true,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init(this.$route);
|
||||
},
|
||||
watch: {
|
||||
'$route'(to, from) {
|
||||
this.init(to);
|
||||
},
|
||||
currentProject() {
|
||||
this.refresh();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init(route) {
|
||||
let path = route.path;
|
||||
if (path.indexOf("/track/case/edit") >= 0 || path.indexOf("/track/case/create") >= 0) {
|
||||
this.getProjects();
|
||||
this.testCaseReadOnly = false;
|
||||
if (!checkoutTestManagerOrTestUser()) {
|
||||
this.testCaseReadOnly = true;
|
||||
}
|
||||
let caseId = this.$route.params.caseId;
|
||||
this.openRecentTestCaseEditDialog(caseId);
|
||||
this.$router.push('/track/case/all');
|
||||
} else if (route.params.projectId) {
|
||||
this.getProjects();
|
||||
this.getProjectById(route.params.projectId);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init(this.$route);
|
||||
},
|
||||
watch: {
|
||||
'$route'(to, from) {
|
||||
this.init(to);
|
||||
},
|
||||
currentProject() {
|
||||
this.refresh();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init(route) {
|
||||
let path = route.path;
|
||||
if (path.indexOf("/track/case/edit") >= 0 || path.indexOf("/track/case/create") >= 0){
|
||||
this.getProjects();
|
||||
this.testCaseReadOnly = false;
|
||||
if (!checkoutTestManagerOrTestUser()) {
|
||||
this.testCaseReadOnly = true;
|
||||
getProjects() {
|
||||
this.$get("/project/listAll", (response) => {
|
||||
this.projects = response.data;
|
||||
let lastProject = JSON.parse(localStorage.getItem(CURRENT_PROJECT));
|
||||
if (lastProject) {
|
||||
let hasCurrentProject = false;
|
||||
for (let i = 0; i < this.projects.length; i++) {
|
||||
if (this.projects[i].id == lastProject.id) {
|
||||
this.currentProject = lastProject;
|
||||
hasCurrentProject = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasCurrentProject) {
|
||||
this.setCurrentProject(this.projects[0]);
|
||||
}
|
||||
let caseId = this.$route.params.caseId;
|
||||
this.openRecentTestCaseEditDialog(caseId);
|
||||
this.$router.push('/track/case/all');
|
||||
} else if (route.params.projectId){
|
||||
this.getProjects();
|
||||
this.getProjectById(route.params.projectId);
|
||||
}
|
||||
},
|
||||
getProjects() {
|
||||
this.$get("/project/listAll", (response) => {
|
||||
this.projects = response.data;
|
||||
let lastProject = JSON.parse(localStorage.getItem(CURRENT_PROJECT));
|
||||
if (lastProject) {
|
||||
let hasCurrentProject = false;
|
||||
for (let i = 0; i < this.projects.length; i++) {
|
||||
if (this.projects[i].id == lastProject.id) {
|
||||
this.currentProject = lastProject;
|
||||
hasCurrentProject = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasCurrentProject) {
|
||||
this.setCurrentProject(this.projects[0]);
|
||||
}
|
||||
} else {
|
||||
if(this.projects.length > 0){
|
||||
this.setCurrentProject(this.projects[0]);
|
||||
}
|
||||
}
|
||||
// this.checkProject();
|
||||
});
|
||||
},
|
||||
checkProject() {
|
||||
if(this.currentProject === null) {
|
||||
this.$alert(this.$t('test_track.case.no_project'), {
|
||||
confirmButtonText: this.$t('project.create'),
|
||||
callback: action => {
|
||||
this.$router.push("/track/project/create");
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
changeProject(project) {
|
||||
this.setCurrentProject(project);
|
||||
},
|
||||
nodeChange(nodeIds, pNodes) {
|
||||
this.selectNodeIds = nodeIds;
|
||||
this.selectParentNodes = pNodes;
|
||||
},
|
||||
refreshTable() {
|
||||
this.$refs.testCaseList.initTableData();
|
||||
},
|
||||
editTestCase(testCase) {
|
||||
this.testCaseReadOnly = false;
|
||||
if (this.treeNodes.length < 1) {
|
||||
this.$warning(this.$t('test_track.case.create_module_first'));
|
||||
return;
|
||||
}
|
||||
this.$refs.testCaseEditDialog.open(testCase);
|
||||
},
|
||||
copyTestCase(testCase) {
|
||||
this.testCaseReadOnly = false;
|
||||
let item = {};
|
||||
Object.assign(item, testCase);
|
||||
item.name = '';
|
||||
item.isCopy = true;
|
||||
this.$refs.testCaseEditDialog.open(item);
|
||||
},
|
||||
showTestCaseDetail(testCase) {
|
||||
this.testCaseReadOnly = true;
|
||||
this.$refs.testCaseEditDialog.open(testCase);
|
||||
},
|
||||
getProjectByCaseId(caseId) {
|
||||
return this.$get('/test/case/project/' + caseId, async response => {
|
||||
this.setCurrentProject(response.data);
|
||||
});
|
||||
},
|
||||
refresh() {
|
||||
this.selectNodeIds = [];
|
||||
this.selectParentNodes = [];
|
||||
this.selectNode = {};
|
||||
this.$refs.testCaseList.initTableData();
|
||||
this.getNodeTree();
|
||||
},
|
||||
openRecentTestCaseEditDialog(caseId) {
|
||||
if (caseId) {
|
||||
this.getProjectByCaseId(caseId);
|
||||
this.$get('/test/case/get/' + caseId, response => {
|
||||
if (response.data) {
|
||||
this.$refs.testCaseEditDialog.open(response.data);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.$refs.testCaseEditDialog.open();
|
||||
if (this.projects.length > 0) {
|
||||
this.setCurrentProject(this.projects[0]);
|
||||
}
|
||||
}
|
||||
},
|
||||
getProjectById(id) {
|
||||
if (id && id != 'all') {
|
||||
this.$get('/project/get/' + id, response => {
|
||||
let project = response.data;
|
||||
this.setCurrentProject(project);
|
||||
// this.$router.push('/track/case/all');
|
||||
});
|
||||
}
|
||||
if (id === 'all') {
|
||||
this.refresh();
|
||||
}
|
||||
},
|
||||
setCurrentProject(project) {
|
||||
if (project) {
|
||||
this.currentProject = project;
|
||||
localStorage.setItem(CURRENT_PROJECT, JSON.stringify(project));
|
||||
}
|
||||
this.refresh();
|
||||
},
|
||||
getNodeTree() {
|
||||
if (!hasRoles(ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
this.nodeTreeDraggable = false;
|
||||
}
|
||||
if (this.currentProject) {
|
||||
this.result = this.$get("/case/node/list/" + this.currentProject.id, response => {
|
||||
this.treeNodes = response.data;
|
||||
});
|
||||
}
|
||||
},
|
||||
moveToNode(selectIds) {
|
||||
if (selectIds.size < 1) {
|
||||
this.$warning(this.$t('test_track.plan_view.select_manipulate'));
|
||||
return;
|
||||
}
|
||||
this.$refs.testCaseEditDialog.getModuleOptions();
|
||||
this.$refs.testCaseMove.open(this.$refs.testCaseEditDialog.moduleOptions, selectIds);
|
||||
},
|
||||
batchMove(selectIds) {
|
||||
this.$refs.testBatchMove.open(this.treeNodes, selectIds,this.$refs.testCaseEditDialog.moduleOptions);
|
||||
// this.checkProject();
|
||||
});
|
||||
},
|
||||
checkProject() {
|
||||
if (this.currentProject === null) {
|
||||
this.$alert(this.$t('test_track.case.no_project'), {
|
||||
confirmButtonText: this.$t('project.create'),
|
||||
callback: action => {
|
||||
this.$router.push("/track/project/create");
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
changeProject(project) {
|
||||
this.setCurrentProject(project);
|
||||
},
|
||||
nodeChange(nodeIds, pNodes) {
|
||||
this.selectNodeIds = nodeIds;
|
||||
this.selectParentNodes = pNodes;
|
||||
},
|
||||
refreshTable() {
|
||||
this.$refs.testCaseList.initTableData();
|
||||
},
|
||||
editTestCase(testCase) {
|
||||
this.testCaseReadOnly = false;
|
||||
if (this.treeNodes.length < 1) {
|
||||
this.$warning(this.$t('test_track.case.create_module_first'));
|
||||
return;
|
||||
}
|
||||
this.$refs.testCaseEditDialog.open(testCase);
|
||||
},
|
||||
copyTestCase(testCase) {
|
||||
this.testCaseReadOnly = false;
|
||||
let item = {};
|
||||
Object.assign(item, testCase);
|
||||
item.name = '';
|
||||
item.isCopy = true;
|
||||
this.$refs.testCaseEditDialog.open(item);
|
||||
},
|
||||
showTestCaseDetail(testCase) {
|
||||
this.testCaseReadOnly = true;
|
||||
this.$refs.testCaseEditDialog.open(testCase);
|
||||
},
|
||||
getProjectByCaseId(caseId) {
|
||||
return this.$get('/test/case/project/' + caseId, async response => {
|
||||
this.setCurrentProject(response.data);
|
||||
});
|
||||
},
|
||||
refresh() {
|
||||
this.selectNodeIds = [];
|
||||
this.selectParentNodes = [];
|
||||
this.selectNode = {};
|
||||
this.$refs.testCaseList.initTableData();
|
||||
this.getNodeTree();
|
||||
},
|
||||
openRecentTestCaseEditDialog(caseId) {
|
||||
if (caseId) {
|
||||
this.getProjectByCaseId(caseId);
|
||||
this.$get('/test/case/get/' + caseId, response => {
|
||||
if (response.data) {
|
||||
this.$refs.testCaseEditDialog.open(response.data);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.$refs.testCaseEditDialog.open();
|
||||
}
|
||||
},
|
||||
getProjectById(id) {
|
||||
if (id && id != 'all') {
|
||||
this.$get('/project/get/' + id, response => {
|
||||
let project = response.data;
|
||||
this.setCurrentProject(project);
|
||||
// this.$router.push('/track/case/all');
|
||||
});
|
||||
}
|
||||
if (id === 'all') {
|
||||
this.refresh();
|
||||
}
|
||||
},
|
||||
setCurrentProject(project) {
|
||||
if (project) {
|
||||
this.currentProject = project;
|
||||
localStorage.setItem(CURRENT_PROJECT, JSON.stringify(project));
|
||||
}
|
||||
this.refresh();
|
||||
},
|
||||
getNodeTree() {
|
||||
if (!hasRoles(ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
this.nodeTreeDraggable = false;
|
||||
}
|
||||
if (this.currentProject) {
|
||||
this.result = this.$get("/case/node/list/" + this.currentProject.id, response => {
|
||||
this.treeNodes = response.data;
|
||||
});
|
||||
}
|
||||
},
|
||||
moveToNode(selectIds) {
|
||||
if (selectIds.size < 1) {
|
||||
this.$warning(this.$t('test_track.plan_view.select_manipulate'));
|
||||
return;
|
||||
}
|
||||
this.$refs.testCaseEditDialog.getModuleOptions();
|
||||
this.$refs.testCaseMove.open(this.$refs.testCaseEditDialog.moduleOptions, selectIds);
|
||||
},
|
||||
batchMove(selectIds) {
|
||||
this.$refs.testBatchMove.open(this.treeNodes, selectIds, this.$refs.testCaseEditDialog.moduleOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.el-main {
|
||||
padding: 15px;
|
||||
}
|
||||
.el-main {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -161,6 +161,7 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
result: {},
|
||||
testCase: {},
|
||||
dialogFormVisible: false,
|
||||
readOnly: true,
|
||||
form: {
|
||||
|
@ -190,9 +191,15 @@ export default {
|
|||
]
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$get('test/case/get/' + this.testCaseId, response => {
|
||||
this.testCase = response.data;
|
||||
});
|
||||
},
|
||||
methods: {},
|
||||
props: {
|
||||
testCase: {
|
||||
type: Object
|
||||
testCaseId: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -256,9 +256,9 @@
|
|||
|
||||
<script>
|
||||
|
||||
import {TokenKey, WORKSPACE_ID} from '../../../../../common/js/constants';
|
||||
import {TokenKey, WORKSPACE_ID} from '@/common/js/constants';
|
||||
import MsDialogFooter from '../../../common/components/MsDialogFooter'
|
||||
import {listenGoBack, removeGoBackListener} from "../../../../../common/js/utils";
|
||||
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
|
||||
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
|
||||
import {Message} from "element-ui";
|
||||
import TestCaseAttachment from "@/business/components/track/case/components/TestCaseAttachment";
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
:tip="$t('commons.search_by_name_or_id')"
|
||||
:create-tip="$t('test_track.case.create')" @create="testCaseCreate">
|
||||
<template v-slot:title>
|
||||
<node-breadcrumb class="table-title" :nodes="selectParentNodes" @refresh="showAll"/>
|
||||
<node-breadcrumb class="table-title" :nodes="selectParentNodes" @refresh="refresh"/>
|
||||
</template>
|
||||
<template v-slot:button>
|
||||
<ms-table-button :is-tester-permission="true" icon="el-icon-download"
|
||||
|
@ -35,6 +35,7 @@
|
|||
@filter-change="filter"
|
||||
@select-all="handleSelectAll"
|
||||
@select="handleSelectionChange"
|
||||
@cell-mouse-enter="showPopover"
|
||||
row-key="id"
|
||||
class="test-content adjust-table">
|
||||
<el-table-column
|
||||
|
@ -65,7 +66,7 @@
|
|||
width="60%"
|
||||
trigger="hover"
|
||||
>
|
||||
<test-case-detail :test-case="scope.row"/>
|
||||
<test-case-detail v-if="currentCaseId === scope.row.id" :test-case-id="currentCaseId"/>
|
||||
<span slot="reference">{{ scope.row.name }}</span>
|
||||
</el-popover>
|
||||
</template>
|
||||
|
@ -166,11 +167,11 @@ import MethodTableItem from "../../common/tableItems/planview/MethodTableItem";
|
|||
import MsTableOperator from "../../../common/components/MsTableOperator";
|
||||
import MsTableOperatorButton from "../../../common/components/MsTableOperatorButton";
|
||||
import MsTableButton from "../../../common/components/MsTableButton";
|
||||
import {_filter, _sort} from "../../../../../common/js/utils";
|
||||
import {_filter, _sort} from "@/common/js/utils";
|
||||
import {TEST_CASE_CONFIGS} from "../../../common/components/search/search-components";
|
||||
import ShowMoreBtn from "./ShowMoreBtn";
|
||||
import BatchEdit from "./BatchEdit";
|
||||
import {WORKSPACE_ID} from "../../../../../common/js/constants";
|
||||
import {WORKSPACE_ID} from "@/common/js/constants";
|
||||
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
|
||||
import StatusTableItem from "@/business/components/track/common/tableItems/planview/StatusTableItem";
|
||||
import TestCaseDetail from "./TestCaseDetail";
|
||||
|
@ -187,336 +188,346 @@ export default {
|
|||
PriorityTableItem,
|
||||
MsCreateBox,
|
||||
TestCaseImport,
|
||||
TestCaseExport,
|
||||
MsTablePagination,
|
||||
NodeBreadcrumb,
|
||||
MsTableHeader,
|
||||
ShowMoreBtn,
|
||||
BatchEdit,
|
||||
StatusTableItem,
|
||||
TestCaseDetail,
|
||||
ReviewStatus
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
deletePath: "/test/case/delete",
|
||||
condition: {
|
||||
components: TEST_CASE_CONFIGS
|
||||
},
|
||||
tableData: [],
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
selectRows: new Set(),
|
||||
priorityFilters: [
|
||||
{text: 'P0', value: 'P0'},
|
||||
{text: 'P1', value: 'P1'},
|
||||
{text: 'P2', value: 'P2'},
|
||||
{text: 'P3', value: 'P3'}
|
||||
],
|
||||
methodFilters: [
|
||||
{text: this.$t('test_track.case.manual'), value: 'manual'},
|
||||
{text: this.$t('test_track.case.auto'), value: 'auto'}
|
||||
],
|
||||
typeFilters: [
|
||||
{text: this.$t('commons.functional'), value: 'functional'},
|
||||
{text: this.$t('commons.performance'), value: 'performance'},
|
||||
{text: this.$t('commons.api'), value: 'api'}
|
||||
],
|
||||
statusFilters: [
|
||||
{text: this.$t('test_track.case.status_prepare'), value: 'Prepare'},
|
||||
{text: this.$t('test_track.case.status_pass'), value: 'Pass'},
|
||||
{text: this.$t('test_track.case.status_un_pass'), value: 'UnPass'},
|
||||
],
|
||||
showMore: false,
|
||||
buttons: [
|
||||
{
|
||||
name: this.$t('test_track.case.batch_edit_case'), handleClick: this.handleBatchEdit
|
||||
}, {
|
||||
name: this.$t('test_track.case.batch_move_case'), handleClick: this.handleBatchMove
|
||||
}, {
|
||||
name: this.$t('test_track.case.batch_delete_case'), handleClick: this.handleDeleteBatch
|
||||
}
|
||||
],
|
||||
typeArr: [
|
||||
{id: 'priority', name: this.$t('test_track.case.priority')},
|
||||
{id: 'type', name: this.$t('test_track.case.type')},
|
||||
{id: 'method', name: this.$t('test_track.case.method')},
|
||||
{id: 'maintainer', name: this.$t('test_track.case.maintainer')},
|
||||
],
|
||||
valueArr: {
|
||||
priority: [
|
||||
{name: 'P0', id: 'P0'},
|
||||
{name: 'P1', id: 'P1'},
|
||||
{name: 'P2', id: 'P2'},
|
||||
{name: 'P3', id: 'P3'}
|
||||
],
|
||||
type: [
|
||||
{name: this.$t('commons.functional'), id: 'functional'},
|
||||
{name: this.$t('commons.performance'), id: 'performance'},
|
||||
{name: this.$t('commons.api'), id: 'api'}
|
||||
],
|
||||
method: [
|
||||
{name: this.$t('test_track.case.manual'), id: 'manual'},
|
||||
{name: this.$t('test_track.case.auto'), id: 'auto'}
|
||||
],
|
||||
maintainer: [],
|
||||
TestCaseExport,
|
||||
MsTablePagination,
|
||||
NodeBreadcrumb,
|
||||
MsTableHeader,
|
||||
ShowMoreBtn,
|
||||
BatchEdit,
|
||||
StatusTableItem,
|
||||
TestCaseDetail,
|
||||
ReviewStatus
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
deletePath: "/test/case/delete",
|
||||
condition: {
|
||||
components: TEST_CASE_CONFIGS
|
||||
},
|
||||
tableData: [],
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
selectRows: new Set(),
|
||||
priorityFilters: [
|
||||
{text: 'P0', value: 'P0'},
|
||||
{text: 'P1', value: 'P1'},
|
||||
{text: 'P2', value: 'P2'},
|
||||
{text: 'P3', value: 'P3'}
|
||||
],
|
||||
methodFilters: [
|
||||
{text: this.$t('test_track.case.manual'), value: 'manual'},
|
||||
{text: this.$t('test_track.case.auto'), value: 'auto'}
|
||||
],
|
||||
typeFilters: [
|
||||
{text: this.$t('commons.functional'), value: 'functional'},
|
||||
{text: this.$t('commons.performance'), value: 'performance'},
|
||||
{text: this.$t('commons.api'), value: 'api'}
|
||||
],
|
||||
statusFilters: [
|
||||
{text: this.$t('test_track.case.status_prepare'), value: 'Prepare'},
|
||||
{text: this.$t('test_track.case.status_pass'), value: 'Pass'},
|
||||
{text: this.$t('test_track.case.status_un_pass'), value: 'UnPass'},
|
||||
],
|
||||
showMore: false,
|
||||
buttons: [
|
||||
{
|
||||
name: this.$t('test_track.case.batch_edit_case'), handleClick: this.handleBatchEdit
|
||||
}, {
|
||||
name: this.$t('test_track.case.batch_move_case'), handleClick: this.handleBatchMove
|
||||
}, {
|
||||
name: this.$t('test_track.case.batch_delete_case'), handleClick: this.handleDeleteBatch
|
||||
}
|
||||
}
|
||||
},
|
||||
props: {
|
||||
currentProject: {
|
||||
type: Object
|
||||
],
|
||||
typeArr: [
|
||||
{id: 'priority', name: this.$t('test_track.case.priority')},
|
||||
{id: 'type', name: this.$t('test_track.case.type')},
|
||||
{id: 'method', name: this.$t('test_track.case.method')},
|
||||
{id: 'maintainer', name: this.$t('test_track.case.maintainer')},
|
||||
],
|
||||
valueArr: {
|
||||
priority: [
|
||||
{name: 'P0', id: 'P0'},
|
||||
{name: 'P1', id: 'P1'},
|
||||
{name: 'P2', id: 'P2'},
|
||||
{name: 'P3', id: 'P3'}
|
||||
],
|
||||
type: [
|
||||
{name: this.$t('commons.functional'), id: 'functional'},
|
||||
{name: this.$t('commons.performance'), id: 'performance'},
|
||||
{name: this.$t('commons.api'), id: 'api'}
|
||||
],
|
||||
method: [
|
||||
{name: this.$t('test_track.case.manual'), id: 'manual'},
|
||||
{name: this.$t('test_track.case.auto'), id: 'auto'}
|
||||
],
|
||||
maintainer: [],
|
||||
},
|
||||
selectNodeIds: {
|
||||
type: Array
|
||||
},
|
||||
selectParentNodes: {
|
||||
type: Array
|
||||
}
|
||||
currentCaseId: null
|
||||
}
|
||||
},
|
||||
props: {
|
||||
currentProject: {
|
||||
type: Object
|
||||
},
|
||||
created: function () {
|
||||
selectNodeIds: {
|
||||
type: Array
|
||||
},
|
||||
selectParentNodes: {
|
||||
type: Array
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
this.initTableData();
|
||||
},
|
||||
watch: {
|
||||
currentProject() {
|
||||
this.initTableData();
|
||||
},
|
||||
watch: {
|
||||
currentProject() {
|
||||
this.initTableData();
|
||||
},
|
||||
selectNodeIds() {
|
||||
this.currentPage = 1;
|
||||
this.initTableData();
|
||||
selectNodeIds() {
|
||||
this.currentPage = 1;
|
||||
this.initTableData();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initTableData() {
|
||||
this.condition.planId = "";
|
||||
this.condition.nodeIds = [];
|
||||
if (this.planId) {
|
||||
// param.planId = this.planId;
|
||||
this.condition.planId = this.planId;
|
||||
}
|
||||
if (this.selectNodeIds && this.selectNodeIds.length > 0) {
|
||||
// param.nodeIds = this.selectNodeIds;
|
||||
this.condition.nodeIds = this.selectNodeIds;
|
||||
}
|
||||
this.getData();
|
||||
},
|
||||
getData() {
|
||||
if (this.currentProject) {
|
||||
this.condition.projectId = this.currentProject.id;
|
||||
this.result = this.$post(this.buildPagePath('/test/case/list'), this.condition, response => {
|
||||
let data = response.data;
|
||||
this.total = data.itemCount;
|
||||
this.tableData = data.listObject;
|
||||
// this.selectIds.clear();
|
||||
this.selectRows.clear();
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initTableData() {
|
||||
if (this.planId) {
|
||||
// param.planId = this.planId;
|
||||
this.condition.planId = this.planId;
|
||||
}
|
||||
if (this.selectNodeIds && this.selectNodeIds.length > 0) {
|
||||
// param.nodeIds = this.selectNodeIds;
|
||||
this.condition.nodeIds = this.selectNodeIds;
|
||||
}
|
||||
this.getData();
|
||||
},
|
||||
getData() {
|
||||
if (this.currentProject) {
|
||||
this.condition.projectId = this.currentProject.id;
|
||||
this.result = this.$post(this.buildPagePath('/test/case/list'), this.condition, response => {
|
||||
let data = response.data;
|
||||
this.total = data.itemCount;
|
||||
this.tableData = data.listObject;
|
||||
// this.selectIds.clear();
|
||||
this.selectRows.clear();
|
||||
});
|
||||
}
|
||||
},
|
||||
search() {
|
||||
this.initTableData();
|
||||
},
|
||||
buildPagePath(path) {
|
||||
return path + "/" + this.currentPage + "/" + this.pageSize;
|
||||
},
|
||||
testCaseCreate() {
|
||||
this.$emit('testCaseEdit');
|
||||
},
|
||||
handleEdit(testCase) {
|
||||
search() {
|
||||
this.initTableData();
|
||||
},
|
||||
buildPagePath(path) {
|
||||
return path + "/" + this.currentPage + "/" + this.pageSize;
|
||||
},
|
||||
testCaseCreate() {
|
||||
this.$emit('testCaseEdit');
|
||||
},
|
||||
handleEdit(testCase) {
|
||||
this.$get('test/case/get/' + testCase.id, response => {
|
||||
let testCase = response.data;
|
||||
this.$emit('testCaseEdit', testCase);
|
||||
},
|
||||
handleCopy(testCase) {
|
||||
});
|
||||
},
|
||||
handleCopy(testCase) {
|
||||
this.$get('test/case/get/' + testCase.id, response => {
|
||||
let testCase = response.data;
|
||||
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);
|
||||
}
|
||||
});
|
||||
},
|
||||
handleDelete(testCase) {
|
||||
this.$alert(this.$t('test_track.case.delete_confirm') + '\'' + testCase.name + '\'' + "?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
this._handleDelete(testCase);
|
||||
}
|
||||
});
|
||||
},
|
||||
handleDeleteBatch() {
|
||||
this.$alert(this.$t('test_track.case.delete_confirm') + "?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
let ids = Array.from(this.selectRows).map(row => row.id);
|
||||
this.$post('/test/case/batch/delete', {ids: ids}, () => {
|
||||
this.selectRows.clear();
|
||||
this.$emit("refresh");
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
TrackEvent.$emit(LIST_CHANGE);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
handleDeleteBatch() {
|
||||
this.$alert(this.$t('test_track.case.delete_confirm') + "?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
let ids = Array.from(this.selectRows).map(row => row.id);
|
||||
this.$post('/test/case/batch/delete', {ids: ids}, () => {
|
||||
this.selectRows.clear();
|
||||
this.$emit("refresh");
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
TrackEvent.$emit(LIST_CHANGE);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
_handleDelete(testCase) {
|
||||
let testCaseId = testCase.id;
|
||||
this.$post('/test/case/delete/' + testCaseId, {}, () => {
|
||||
this.initTableData();
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
TrackEvent.$emit(LIST_CHANGE);
|
||||
});
|
||||
},
|
||||
refresh() {
|
||||
this.condition = {components: TEST_CASE_CONFIGS};
|
||||
// this.selectIds.clear();
|
||||
this.selectRows.clear();
|
||||
this.$emit('refresh');
|
||||
},
|
||||
showDetail(row, event, column) {
|
||||
this.$emit('testCaseDetail', row);
|
||||
},
|
||||
handleSelectAll(selection) {
|
||||
if (selection.length > 0) {
|
||||
this.tableData.forEach(item => {
|
||||
this.$set(item, "showMore", true);
|
||||
this.selectRows.add(item);
|
||||
});
|
||||
},
|
||||
_handleDelete(testCase) {
|
||||
let testCaseId = testCase.id;
|
||||
this.$post('/test/case/delete/' + testCaseId, {}, () => {
|
||||
this.initTableData();
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
TrackEvent.$emit(LIST_CHANGE);
|
||||
});
|
||||
},
|
||||
refresh() {
|
||||
this.condition = {components: TEST_CASE_CONFIGS};
|
||||
// this.selectIds.clear();
|
||||
} else {
|
||||
this.selectRows.clear();
|
||||
this.$emit('refresh');
|
||||
},
|
||||
showAll() {
|
||||
this.condition = {components: TEST_CASE_CONFIGS};
|
||||
this.getData();
|
||||
},
|
||||
showDetail(row, event, column) {
|
||||
this.$emit('testCaseDetail', row);
|
||||
},
|
||||
handleSelectAll(selection) {
|
||||
if (selection.length > 0) {
|
||||
this.tableData.forEach(item => {
|
||||
this.$set(item, "showMore", true);
|
||||
this.selectRows.add(item);
|
||||
});
|
||||
} else {
|
||||
this.selectRows.clear();
|
||||
this.tableData.forEach(row => {
|
||||
this.$set(row, "showMore", false);
|
||||
})
|
||||
}
|
||||
},
|
||||
handleSelectionChange(selection, row) {
|
||||
if (this.selectRows.has(row)) {
|
||||
this.tableData.forEach(row => {
|
||||
this.$set(row, "showMore", false);
|
||||
this.selectRows.delete(row);
|
||||
})
|
||||
}
|
||||
},
|
||||
handleSelectionChange(selection, row) {
|
||||
if (this.selectRows.has(row)) {
|
||||
this.$set(row, "showMore", false);
|
||||
this.selectRows.delete(row);
|
||||
} else {
|
||||
this.$set(row, "showMore", true);
|
||||
this.selectRows.add(row);
|
||||
}
|
||||
},
|
||||
importTestCase() {
|
||||
this.$refs.testCaseImport.open();
|
||||
},
|
||||
exportTestCase() {
|
||||
let ids = Array.from(this.selectRows).map(row => row.id);
|
||||
let config = {
|
||||
url: '/test/case/export/testcase',
|
||||
method: 'post',
|
||||
responseType: 'blob',
|
||||
// data: {ids: [...this.selectIds]}
|
||||
data: {ids: ids, projectId: this.currentProject.id}
|
||||
};
|
||||
this.result = this.$request(config).then(response => {
|
||||
const filename = this.$t('test_track.case.test_case') + ".xlsx";
|
||||
const blob = new Blob([response.data]);
|
||||
if ("download" in document.createElement("a")) {
|
||||
let aTag = document.createElement('a');
|
||||
aTag.download = filename;
|
||||
aTag.href = URL.createObjectURL(blob);
|
||||
aTag.click();
|
||||
URL.revokeObjectURL(aTag.href)
|
||||
} else {
|
||||
this.$set(row, "showMore", true);
|
||||
this.selectRows.add(row);
|
||||
navigator.msSaveBlob(blob, filename);
|
||||
}
|
||||
},
|
||||
importTestCase() {
|
||||
this.$refs.testCaseImport.open();
|
||||
},
|
||||
exportTestCase() {
|
||||
let ids = Array.from(this.selectRows).map(row => row.id);
|
||||
let config = {
|
||||
url: '/test/case/export/testcase',
|
||||
method: 'post',
|
||||
responseType: 'blob',
|
||||
// data: {ids: [...this.selectIds]}
|
||||
data: {ids: ids, projectId: this.currentProject.id}
|
||||
};
|
||||
this.result = this.$request(config).then(response => {
|
||||
const filename = this.$t('test_track.case.test_case') + ".xlsx";
|
||||
const blob = new Blob([response.data]);
|
||||
if ("download" in document.createElement("a")) {
|
||||
let aTag = document.createElement('a');
|
||||
aTag.download = filename;
|
||||
aTag.href = URL.createObjectURL(blob);
|
||||
aTag.click();
|
||||
URL.revokeObjectURL(aTag.href)
|
||||
} else {
|
||||
navigator.msSaveBlob(blob, filename);
|
||||
}
|
||||
});
|
||||
},
|
||||
handleBatch(type) {
|
||||
});
|
||||
},
|
||||
handleBatch(type) {
|
||||
|
||||
if (this.selectRows.size < 1) {
|
||||
if (type === 'export') {
|
||||
this.$alert(this.$t('test_track.case.export_all_cases'), '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
this.exportTestCase();
|
||||
}
|
||||
if (this.selectRows.size < 1) {
|
||||
if (type === 'export') {
|
||||
this.$alert(this.$t('test_track.case.export_all_cases'), '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
this.exportTestCase();
|
||||
}
|
||||
})
|
||||
return;
|
||||
} else {
|
||||
this.$warning(this.$t('test_track.plan_view.select_manipulate'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (type === 'move') {
|
||||
let ids = Array.from(this.selectRows).map(row => row.id);
|
||||
this.$emit('moveToNode', ids);
|
||||
} else if (type === 'delete') {
|
||||
this.handleDeleteBatch();
|
||||
}
|
||||
})
|
||||
return;
|
||||
} else {
|
||||
this.exportTestCase();
|
||||
this.$warning(this.$t('test_track.plan_view.select_manipulate'));
|
||||
return;
|
||||
}
|
||||
},
|
||||
batchEdit(form) {
|
||||
let arr = Array.from(this.selectRows);
|
||||
let ids = arr.map(row => row.id);
|
||||
let param = {};
|
||||
param[form.type] = form.value;
|
||||
param.ids = ids;
|
||||
this.$post('/test/case/batch/edit', param, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.refresh();
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
TrackEvent.$emit(LIST_CHANGE);
|
||||
});
|
||||
},
|
||||
filter(filters) {
|
||||
_filter(filters, this.condition);
|
||||
this.initTableData();
|
||||
},
|
||||
sort(column) {
|
||||
// 每次只对一个字段排序
|
||||
if (this.condition.orders) {
|
||||
this.condition.orders = [];
|
||||
}
|
||||
_sort(column, this.condition);
|
||||
this.initTableData();
|
||||
},
|
||||
handleBatchEdit() {
|
||||
this.getMaintainerOptions();
|
||||
this.$refs.batchEdit.open();
|
||||
},
|
||||
handleBatchMove() {
|
||||
this.$emit("batchMove", Array.from(this.selectRows).map(row => row.id));
|
||||
},
|
||||
getMaintainerOptions() {
|
||||
let workspaceId = localStorage.getItem(WORKSPACE_ID);
|
||||
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
|
||||
this.valueArr.maintainer = response.data;
|
||||
});
|
||||
}
|
||||
if (type === 'move') {
|
||||
let ids = Array.from(this.selectRows).map(row => row.id);
|
||||
this.$emit('moveToNode', ids);
|
||||
} else if (type === 'delete') {
|
||||
this.handleDeleteBatch();
|
||||
} else {
|
||||
this.exportTestCase();
|
||||
}
|
||||
},
|
||||
batchEdit(form) {
|
||||
let arr = Array.from(this.selectRows);
|
||||
let ids = arr.map(row => row.id);
|
||||
let param = {};
|
||||
param[form.type] = form.value;
|
||||
param.ids = ids;
|
||||
this.$post('/test/case/batch/edit', param, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.refresh();
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
TrackEvent.$emit(LIST_CHANGE);
|
||||
});
|
||||
},
|
||||
filter(filters) {
|
||||
_filter(filters, this.condition);
|
||||
this.initTableData();
|
||||
},
|
||||
sort(column) {
|
||||
// 每次只对一个字段排序
|
||||
if (this.condition.orders) {
|
||||
this.condition.orders = [];
|
||||
}
|
||||
_sort(column, this.condition);
|
||||
this.initTableData();
|
||||
},
|
||||
handleBatchEdit() {
|
||||
this.getMaintainerOptions();
|
||||
this.$refs.batchEdit.open();
|
||||
},
|
||||
handleBatchMove() {
|
||||
this.$emit("batchMove", Array.from(this.selectRows).map(row => row.id));
|
||||
},
|
||||
getMaintainerOptions() {
|
||||
let workspaceId = localStorage.getItem(WORKSPACE_ID);
|
||||
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
|
||||
this.valueArr.maintainer = response.data;
|
||||
});
|
||||
},
|
||||
showPopover(row, column, cell) {
|
||||
if (column.property === 'name') {
|
||||
this.currentCaseId = row.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.table-page {
|
||||
padding-top: 20px;
|
||||
margin-right: -9px;
|
||||
float: right;
|
||||
}
|
||||
.table-page {
|
||||
padding-top: 20px;
|
||||
margin-right: -9px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.operate-button {
|
||||
float: right;
|
||||
}
|
||||
.operate-button {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.operate-button > div {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.operate-button > div {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.search {
|
||||
margin-left: 10px;
|
||||
width: 240px;
|
||||
}
|
||||
.search {
|
||||
margin-left: 10px;
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
.el-table {
|
||||
cursor: pointer;
|
||||
}
|
||||
.el-table {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -193,8 +193,7 @@ export default {
|
|||
let param = {};
|
||||
Object.assign(param, this.form);
|
||||
param.name = param.name.trim();
|
||||
if (param.name === '') {
|
||||
this.$warning(this.$t('test_track.plan.input_plan_name'));
|
||||
if (!this.validate(param)) {
|
||||
return;
|
||||
}
|
||||
param.workspaceId = localStorage.getItem(WORKSPACE_ID);
|
||||
|
@ -227,6 +226,17 @@ export default {
|
|||
}
|
||||
});
|
||||
},
|
||||
validate(param) {
|
||||
if (param.name === '') {
|
||||
this.$warning(this.$t('test_track.plan.input_plan_name'));
|
||||
return false;
|
||||
}
|
||||
if (param.plannedStartTime > param.plannedEndTime) {
|
||||
this.$warning(this.$t('commons.date.data_time_error'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
editTestPlan(param) {
|
||||
this.$post('/test/plan/' + this.operationType, param, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
|
|
|
@ -137,7 +137,9 @@
|
|||
|
||||
<test-report-template-list @openReport="openReport" ref="testReportTemplateList"/>
|
||||
<test-case-report-view @refresh="initTableData" ref="testCaseReportView"/>
|
||||
<ms-delete-confirm :title="$t('test_track.plan.plan_delete')" @delete="_handleDelete" ref="deleteConfirm"/>
|
||||
<ms-delete-confirm :title="$t('test_track.plan.plan_delete')" @delete="_handleDelete" ref="deleteConfirm" :with-tip="enableDeleteTip">
|
||||
{{$t('test_track.plan.plan_delete_tip')}}
|
||||
</ms-delete-confirm>
|
||||
|
||||
</el-card>
|
||||
</template>
|
||||
|
@ -171,6 +173,7 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
result: {},
|
||||
enableDeleteTip: false,
|
||||
queryPath: "/test/plan/list",
|
||||
deletePath: "/test/plan/delete",
|
||||
condition: {
|
||||
|
@ -249,6 +252,7 @@ export default {
|
|||
});
|
||||
},
|
||||
handleDelete(testPlan) {
|
||||
this.enableDeleteTip = testPlan.status === 'Underway' ? true : false;
|
||||
this.$refs.deleteConfirm.open(testPlan);
|
||||
},
|
||||
_handleDelete(testPlan) {
|
||||
|
|
|
@ -215,6 +215,16 @@
|
|||
item.checked = false;
|
||||
});
|
||||
flag ? this.testCases = tableData : this.testCases = this.testCases.concat(tableData);
|
||||
// 去重处理
|
||||
let hash = {}
|
||||
this.testCases = this.testCases.reduce((item, next) => {
|
||||
if (!hash[next.id]) {
|
||||
hash[next.id] = true
|
||||
item.push(next)
|
||||
}
|
||||
return item
|
||||
}, [])
|
||||
|
||||
this.lineStatus = tableData.length === 50 && this.testCases.length < this.total;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@
|
|||
this.listenGoBack();
|
||||
},
|
||||
initComponents() {
|
||||
this.componentMap.forEach((value, key) =>{
|
||||
this.componentMap.forEach((value, key) => {
|
||||
if (this.template.content.components.indexOf(key) < 0 && this.components.indexOf(key) < 0) {
|
||||
this.components.push(key);
|
||||
}
|
||||
|
@ -205,7 +205,7 @@
|
|||
if (this.isReport) {
|
||||
url = '/case/report/get/';
|
||||
}
|
||||
this.$get(url + id, (response) =>{
|
||||
this.$get(url + id, (response) => {
|
||||
this.template = response.data;
|
||||
this.template.content = JSON.parse(response.data.content);
|
||||
if (this.template.content.customComponent) {
|
||||
|
@ -238,7 +238,7 @@
|
|||
if (this.isReport) {
|
||||
url = '/case/report/';
|
||||
}
|
||||
this.$post(url + this.type, param, () =>{
|
||||
this.$post(url + this.type, param, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.handleClose();
|
||||
this.$emit('refresh');
|
||||
|
|
|
@ -210,14 +210,15 @@
|
|||
let reset = this.exportReportReset;
|
||||
|
||||
this.$nextTick(function () {
|
||||
html2canvas(document.getElementById('testCaseReportExport'), {
|
||||
// scale: 2
|
||||
}).then(function(canvas) {
|
||||
exportPdf(name, [canvas]);
|
||||
reset();
|
||||
});
|
||||
setTimeout(() => {
|
||||
html2canvas(document.getElementById('testCaseReportExport'), {
|
||||
scale: 2
|
||||
}).then(function(canvas) {
|
||||
exportPdf(name, [canvas]);
|
||||
reset();
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
},
|
||||
exportReportReset() {
|
||||
this.reportExportVisible = false;
|
||||
|
@ -225,7 +226,7 @@
|
|||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</script>cd
|
||||
|
||||
<style scoped>
|
||||
|
||||
|
|
|
@ -23,9 +23,10 @@
|
|||
resize="none"
|
||||
:autosize="{ minRows: 4, maxRows: 4}"
|
||||
@keyup.ctrl.enter.native="sendComment"
|
||||
:disabled="isReadOnly"
|
||||
>
|
||||
</el-input>
|
||||
<el-button type="primary" size="mini" class="send-btn" @click="sendComment">
|
||||
<el-button type="primary" size="mini" class="send-btn" @click="sendComment" :disabled="isReadOnly">
|
||||
{{ $t('test_track.comment.send') }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
@ -34,6 +35,7 @@
|
|||
|
||||
<script>
|
||||
import ReviewCommentItem from "./ReviewCommentItem";
|
||||
import {checkoutTestManagerOrTestUser} from "@/common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "ReviewComment",
|
||||
|
@ -47,8 +49,12 @@ export default {
|
|||
return {
|
||||
result: {},
|
||||
textarea: '',
|
||||
isReadOnly: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.isReadOnly = !checkoutTestManagerOrTestUser();
|
||||
},
|
||||
methods: {
|
||||
sendComment() {
|
||||
let comment = {};
|
||||
|
|
|
@ -219,6 +219,15 @@
|
|||
item.checked = false;
|
||||
});
|
||||
flag ? this.testReviews = tableData : this.testReviews = this.testReviews.concat(tableData);
|
||||
// 去重处理
|
||||
let hash = {}
|
||||
this.testReviews = this.testReviews.reduce((item, next) => {
|
||||
if (!hash[next.id]) {
|
||||
hash[next.id] = true
|
||||
item.push(next)
|
||||
}
|
||||
return item
|
||||
}, [])
|
||||
this.lineStatus = tableData.length === 50 && this.testReviews.length < this.total;
|
||||
|
||||
});
|
||||
|
|
|
@ -108,3 +108,9 @@ body {
|
|||
margin: 5px 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* 修复带长度限制的文本框,内容太长造成的无法查看内容的问题 */
|
||||
|
||||
.el-input__inner[maxlength] {
|
||||
padding-right: 60px;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,9 @@ export default {
|
|||
success(response.data);
|
||||
} else {
|
||||
window.console.warn(response.data);
|
||||
Message.warning(response.data.message);
|
||||
if (response.data.message) {
|
||||
Message.warning(response.data.message);
|
||||
}
|
||||
}
|
||||
result.loading = false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export const PHONE_REGEX = '^1(3|4|5|7|8|9)\\d{9}$';
|
|
@ -275,3 +275,17 @@ export function exportPdf(name, canvasList) {
|
|||
|
||||
}
|
||||
|
||||
export function windowPrint(id, zoom) {
|
||||
//根据div标签ID拿到div中的局部内容
|
||||
let bdhtml=window.document.body.innerHTML;
|
||||
let el = document.getElementById(id);
|
||||
var jubuData = el.innerHTML;
|
||||
document.getElementsByTagName('body')[0].style.zoom=zoom;
|
||||
//把获取的 局部div内容赋给body标签, 相当于重置了 body里的内容
|
||||
window.document.body.innerHTML= jubuData;
|
||||
//调用打印功能
|
||||
window.print();
|
||||
window.document.body.innerHTML=bdhtml;//重新给页面内容赋值;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -893,6 +893,7 @@ export default {
|
|||
actual_start_time: "Actual Start Time",
|
||||
actual_end_time: "Actual End Time",
|
||||
plan_delete_confirm: "All use cases under this plan will be deleted,confirm delete test plan: ",
|
||||
plan_delete_tip: "The test plan is under way, please confirm and delete it!",
|
||||
plan_delete: "Delete test plan",
|
||||
},
|
||||
review: {
|
||||
|
|
|
@ -470,7 +470,7 @@ export default {
|
|||
title: "jar包管理",
|
||||
jar_file: "jar包",
|
||||
delete_tip: "删除需重启服务后生效",
|
||||
file_exist: "该项目下已存在改jar包",
|
||||
file_exist: "该项目下已存在该jar包",
|
||||
upload_limit_size: "上传文件大小不能超过 30MB!",
|
||||
},
|
||||
definition: {
|
||||
|
@ -896,6 +896,7 @@ export default {
|
|||
actual_start_time: "实际开始",
|
||||
actual_end_time: "实际结束",
|
||||
plan_delete_confirm: "将删除该测试计划下所有用例,确认删除测试计划: ",
|
||||
plan_delete_tip: "该测试计划正在进行中,请确认再删除!",
|
||||
plan_delete: "删除计划",
|
||||
},
|
||||
review: {
|
||||
|
@ -1063,7 +1064,7 @@ export default {
|
|||
SMTP_password: 'SMTP密码',
|
||||
SSL: '开启SSL(如果SMTP端口是465,通常需要启用SSL)',
|
||||
TLS: '开启TLS(如果SMTP端口是587,通常需要启用TLS)',
|
||||
SMTP: '是否匿名 SMTP',
|
||||
SMTP: '是否免密 SMTP',
|
||||
host: '主机号不能为空',
|
||||
port: '端口号不能为空',
|
||||
account: '账户不能为空',
|
||||
|
|
|
@ -470,7 +470,7 @@ export default {
|
|||
title: "jar包管理",
|
||||
jar_file: "jar包",
|
||||
delete_tip: "刪除需重啟服務後生效",
|
||||
file_exist: "該項目下已存在改jar包",
|
||||
file_exist: "該項目下已存在該jar包",
|
||||
upload_limit_size: "上傳文件大小不能超過 30MB!",
|
||||
},
|
||||
definition: {
|
||||
|
@ -894,6 +894,7 @@ export default {
|
|||
actual_start_time: "實際開始",
|
||||
actual_end_time: "實際結束",
|
||||
plan_delete_confirm: "將刪除該測試計劃下所有用例,確認刪除測試計劃: ",
|
||||
plan_delete_tip: "該測試計劃正在進行中,請確認再刪除!",
|
||||
plan_delete: "刪除計劃",
|
||||
},
|
||||
review: {
|
||||
|
@ -1061,7 +1062,7 @@ export default {
|
|||
SMTP_password: 'SMTP密碼',
|
||||
SSL: '開啟SSL(如果SMTP端口是465,通常需要啟用SSL)',
|
||||
TLS: '開啟TLS(如果SMTP端口是587,通常需要啟用TLS)',
|
||||
SMTP: '是否匿名 SMTP',
|
||||
SMTP: '是否免密 SMTP',
|
||||
host: '主機號不能為空',
|
||||
port: '端口號不能為空',
|
||||
account: '賬戶不能為空',
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
<el-col :span="12">
|
||||
<el-form :model="form" :rules="rules" ref="form">
|
||||
<div class="logo">
|
||||
<img v-if="loginLogoId" :src="'/display/file/' + loginLogoId" style="width: 224px;height: 45px;" alt="">
|
||||
<img v-else src="../assets/logo-dark-MeterSphere.svg" style="width: 224px; " alt="">
|
||||
<img :src="'/display/file/loginLogo'" style="width: 224px;height: 45px;" alt="">
|
||||
</div>
|
||||
<div class="title">
|
||||
<span id="s1">{{ loginTitle }}</span>
|
||||
|
@ -41,8 +40,7 @@
|
|||
</el-form>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<img v-if="loginImageId" :src="'/display/file/' + loginImageId" style="height: 560px; width: 100%">
|
||||
<img v-else src="../assets/info.png" style="height: 560px; width: 100%">
|
||||
<img :src="'/display/file/loginImage'" style="height: 560px; width: 100%">
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
@ -86,8 +84,6 @@ export default {
|
|||
msg: '',
|
||||
ready: false,
|
||||
openLdap: false,
|
||||
loginLogoId: '_blank',
|
||||
loginImageId: '_blank',
|
||||
loginTitle: this.$t("commons.login") + " MeterSphere"
|
||||
}
|
||||
},
|
||||
|
@ -264,6 +260,10 @@ export default {
|
|||
background: url(../assets/info.png);
|
||||
height: 560px;
|
||||
}
|
||||
|
||||
.login-logo {
|
||||
background: url(../assets/logo-dark-MeterSphere.svg);
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
|
|
Loading…
Reference in New Issue