Merge branches 'master', 'master' and 'master' of github.com:metersphere/metersphere into master

This commit is contained in:
Captain.B 2020-12-10 18:15:48 +08:00
commit 8c26c9b9f3
73 changed files with 1294 additions and 1032 deletions

View File

@ -44,6 +44,9 @@ public class MsScenario extends MsTestElement {
private List<KeyValue> variables;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
if (environmentId != null) {
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentId);

View File

@ -12,6 +12,7 @@ import io.metersphere.api.dto.definition.request.auth.MsAuthManager;
import io.metersphere.api.dto.definition.request.configurations.MsHeaderManager;
import io.metersphere.api.dto.definition.request.controller.MsIfController;
import io.metersphere.api.dto.definition.request.extract.MsExtract;
import io.metersphere.api.dto.definition.request.processors.MsJSR223Processor;
import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor;
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
import io.metersphere.api.dto.definition.request.sampler.MsDubboSampler;
@ -37,6 +38,7 @@ import java.util.List;
@JsonSubTypes({
@JsonSubTypes.Type(value = MsHTTPSamplerProxy.class, name = "HTTPSamplerProxy"),
@JsonSubTypes.Type(value = MsHeaderManager.class, name = "HeaderManager"),
@JsonSubTypes.Type(value = MsJSR223Processor.class, name = "JSR223Processor"),
@JsonSubTypes.Type(value = MsJSR223PostProcessor.class, name = "JSR223PostProcessor"),
@JsonSubTypes.Type(value = MsJSR223PreProcessor.class, name = "JSR223PreProcessor"),
@JsonSubTypes.Type(value = MsTestPlan.class, name = "TestPlan"),
@ -52,7 +54,7 @@ import java.util.List;
@JsonSubTypes.Type(value = MsScenario.class, name = "scenario"),
})
@JSONType(seeAlso = {MsHTTPSamplerProxy.class, MsHeaderManager.class, MsJSR223PostProcessor.class,
@JSONType(seeAlso = {MsHTTPSamplerProxy.class, MsHeaderManager.class, MsJSR223Processor.class, MsJSR223PostProcessor.class,
MsJSR223PreProcessor.class, MsTestPlan.class, MsThreadGroup.class, AuthManager.class, MsAssertions.class,
MsExtract.class, MsTCPSampler.class, MsDubboSampler.class, MsJDBCSampler.class, MsConstantTimer.class, MsIfController.class, MsScenario.class}, typeKey = "type")
@Data
@ -73,6 +75,9 @@ public abstract class MsTestElement {
@JSONField(ordinal = 7)
private String index;
@JSONField(ordinal = 8)
private boolean enable = true;
@JSONField(ordinal = 9)
private LinkedList<MsTestElement> hashTree;
// 公共环境逐层传递如果自身有环境 以自身引用环境为准否则以公共环境作为请求环境
@ -118,7 +123,8 @@ public abstract class MsTestElement {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
ApiDefinitionWithBLOBs apiDefinition = apiDefinitionService.getBLOBs(this.getId());
element = mapper.readValue(apiDefinition.getRequest(), new TypeReference<MsTestElement>() {});
element = mapper.readValue(apiDefinition.getRequest(), new TypeReference<MsTestElement>() {
});
hashTree.add(element);
} catch (Exception ex) {
ex.printStackTrace();

View File

@ -25,7 +25,9 @@ public class MsAssertions extends MsTestElement {
private String type = "Assertions";
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
addAssertions(tree);
if (this.isEnable()) {
addAssertions(tree);
}
}
private void addAssertions(HashTree hashTree) {

View File

@ -52,6 +52,9 @@ public class MsAuthManager extends MsTestElement {
private String environment;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
AuthManager authManager = new AuthManager();
authManager.setEnabled(true);
authManager.setName(this.getUsername() + "AuthManager");

View File

@ -26,6 +26,9 @@ public class MsHeaderManager extends MsTestElement {
private List<KeyValue> headers;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
HeaderManager headerManager = new HeaderManager();
headerManager.setEnabled(true);
headerManager.setName(this.getName() + "Headers");

View File

@ -20,12 +20,14 @@ import java.util.List;
public class MsIfController extends MsTestElement {
private String type = "IfController";
private String id;
private boolean enable = true;
private String variable;
private String operator;
private String value;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
final HashTree groupTree = tree.add(ifController());
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {

View File

@ -25,6 +25,9 @@ import java.util.List;
public class MsDNSCacheManager extends MsTestElement {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
for (MsTestElement el : hashTree) {
el.toHashTree(tree, el.getHashTree(), config);
}

View File

@ -25,6 +25,9 @@ public class MsExtract extends MsTestElement {
private String type = "Extract";
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
addRequestExtractors(tree);
}

View File

@ -27,6 +27,9 @@ public class MsJSR223Processor extends MsTestElement {
private String scriptLanguage;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
JSR223Sampler processor = new JSR223Sampler();
processor.setEnabled(true);
processor.setName(this.getName() + "JSR223Processor");

View File

@ -28,6 +28,9 @@ public class MsJSR223PostProcessor extends MsTestElement {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
JSR223PostProcessor processor = new JSR223PostProcessor();
processor.setEnabled(true);
processor.setName(this.getName() + "JSR223PostProcessor");

View File

@ -27,6 +27,9 @@ public class MsJSR223PreProcessor extends MsTestElement {
private String scriptLanguage;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
JSR223PreProcessor processor = new JSR223PreProcessor();
processor.setEnabled(true);
processor.setName(this.getName() + "JSR223PreProcessor");

View File

@ -52,6 +52,9 @@ public class MsDubboSampler extends MsTestElement {
private List<KeyValue> attachmentArgs;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
if (this.getReferenced() != null && this.getReferenced().equals("Deleted")) {
return;
}

View File

@ -86,6 +86,9 @@ public class MsHTTPSamplerProxy extends MsTestElement {
private List<KeyValue> arguments;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
if (this.getReferenced() != null && this.getReferenced().equals("REF")) {
this.getRefElement(this);
}

View File

@ -40,6 +40,9 @@ public class MsJDBCSampler extends MsTestElement {
private String environmentId;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
if (this.getReferenced() != null && this.getReferenced().equals("REF")) {
this.getRefElement(this);
}

View File

@ -50,6 +50,9 @@ public class MsTCPSampler extends MsTestElement {
private String request;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
if (this.getReferenced() != null && this.getReferenced().equals("REF")) {
this.getRefElement(this);
}

View File

@ -22,11 +22,12 @@ public class MsConstantTimer extends MsTestElement {
@JSONField(ordinal = 10)
private String id;
@JSONField(ordinal = 11)
private boolean enable = true;
@JSONField(ordinal = 12)
private String delay;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
final HashTree groupTree = tree.add(constantTimer());
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {

View File

@ -12,7 +12,7 @@ public interface ExtTestCaseReviewMapper {
List<TestCaseReviewDTO> list(@Param("request") QueryCaseReviewRequest params);
List<TestCaseReviewDTO> listByWorkspaceId(@Param("workspaceId") String workspaceId, @Param("userId") String userId);
List<TestCaseReviewDTO> listByWorkspaceId(@Param("workspaceId") String workspaceId, @Param("userId") String userId, @Param("projectId") String projectId);
List<TestReviewDTOWithMetric> listRelate(@Param("request") QueryTestReviewRequest request);

View File

@ -15,6 +15,9 @@
and test_case_review.name like CONCAT('%', #{request.name},'%')
</if>
and project.workspace_id = #{request.workspaceId}
<if test="request.projectId != null">
and test_case_review_project.project_id = #{request.projectId}
</if>
</where>
<if test="request.orders != null and request.orders.size() > 0">
order by
@ -32,6 +35,9 @@
test_case_review.id = test_case_review_project.review_id
and test_case_review_project.project_id = project.id
and project.workspace_id = #{workspaceId}
<if test="projectId != null">
and test_case_review_project.project_id = #{projectId}
</if>
and (
(test_case_review_users.review_id = test_case_review.id
and test_case_review_users.user_id = #{userId} )
@ -51,6 +57,9 @@
<if test="request.reviewerId != null">
and test_case_review_users.user_id = #{request.reviewerId}
</if>
<if test="request.projectId != null">
and test_case_review_project.project_id = #{request.projectId}
</if>
<if test="request.creator != null">
and (test_case_review.creator = #{request.creator}
<if test="request.reviewIds != null and request.reviewIds.size() > 0">

View File

@ -114,6 +114,9 @@
<if test="request.workspaceId != null">
AND test_plan.workspace_id = #{request.workspaceId}
</if>
<if test="request.projectId != null">
AND test_plan_project.project_id = #{request.projectId}
</if>
<if test="request.id != null">
AND test_plan.id = #{request.id}
</if>
@ -160,16 +163,22 @@
</select>
<select id="listRelate" resultType="io.metersphere.track.dto.TestPlanDTOWithMetric">
select test_plan.* from test_plan
where test_plan.workspace_id = #{request.workspaceId}
and (test_plan.principal = #{request.principal}
<if test="request.planIds != null and request.planIds.size() > 0">
or test_plan.id in
<foreach collection="request.planIds" item="planId" open="(" close=")" separator=",">
#{planId}
</foreach>
</if>
)
select distinct test_plan.* from test_plan
inner join test_plan_project on test_plan.id = test_plan_project.test_plan_id
<where>
test_plan.workspace_id = #{request.workspaceId}
<if test="request.projectId != null">
and test_plan_project.project_id = #{request.projectId}
</if>
and (test_plan.principal = #{request.principal}
<if test="request.planIds != null and request.planIds.size() > 0">
or test_plan.id in
<foreach collection="request.planIds" item="planId" open="(" close=")" separator=",">
#{planId}
</foreach>
</if>
)
</where>
order by test_plan.update_time desc
</select>

View File

@ -19,7 +19,7 @@ public interface ExtTestPlanTestCaseMapper {
List<TestPlanCaseDTO> listByNodes(@Param("request") QueryTestPlanCaseRequest request);
List<String> findRelateTestPlanId(@Param("userId") String userId, @Param("workspaceId") String workspaceId);
List<String> findRelateTestPlanId(@Param("userId") String userId, @Param("workspaceId") String workspaceId, @Param("projectId") String projectId);
List<TestPlanCaseDTO> getRecentTestedTestCase(@Param("request") QueryTestPlanCaseRequest request);

View File

@ -270,8 +270,15 @@
select distinct plan_id from test_plan_test_case
inner join test_plan
on test_plan_test_case.plan_id = test_plan.id
where test_plan_test_case.executor = #{userId}
and test_plan.workspace_id = #{workspaceId}
inner join test_plan_project
on test_plan.id = test_plan_project.test_plan_id
<where>
test_plan_test_case.executor = #{userId}
and test_plan.workspace_id = #{workspaceId}
<if test="projectId != null">
and test_plan_project.project_id = #{projectId}
</if>
</where>
</select>
<select id="getRecentTestedTestCase" resultType="io.metersphere.track.dto.TestPlanCaseDTO">
select test_plan_test_case.*, test_case.*

View File

@ -11,7 +11,7 @@ public interface ExtTestReviewCaseMapper {
List<TestReviewCaseDTO> list(@Param("request") QueryCaseReviewRequest request);
List<String> getStatusByReviewId(String reviewId);
List<String> findRelateTestReviewId(@Param("userId") String userId, @Param("workspaceId") String workspaceId);
List<String> findRelateTestReviewId(@Param("userId") String userId, @Param("workspaceId") String workspaceId, @Param("projectId") String projectId);
/**
* 根据项目 ids 查询 TestReviewCaseDTO 列表

View File

@ -206,6 +206,7 @@
inner join project on project.id = test_case_review_project.project_id
where test_case_review_test_case.review_id = #{userId}
and project.workspace_id = #{workspaceId}
and test_case_review_project.project_id = #{projectId}
</select>
<select id="listTestCaseByProjectIds" resultType="io.metersphere.track.dto.TestReviewCaseDTO">
select distinct * from test_case_review_test_case, test_case

View File

@ -68,4 +68,8 @@ public class SessionUtils {
public static String getCurrentOrganizationId() {
return Optional.ofNullable(getUser()).orElse(new SessionUser()).getLastOrganizationId();
}
public static String getCurrentProjectId() {
return Optional.ofNullable(getUser()).orElse(new SessionUser()).getLastProjectId();
}
}

View File

@ -60,7 +60,6 @@ public class TestCaseController {
@GetMapping("/list/method/{projectId}")
public List<TestCaseDTO> listByMethod(@PathVariable String projectId) {
checkOwnerService.checkProjectOwner(projectId);
QueryTestCaseRequest request = new QueryTestCaseRequest();
request.setProjectId(projectId);
return testCaseService.listTestCaseMthod(request);

View File

@ -81,8 +81,7 @@ public class TestCaseReviewController {
@PostMapping("/list/all")
public List<TestCaseReview> listAll() {
String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId();
return testCaseReviewService.listCaseReviewAll(currentWorkspaceId);
return testCaseReviewService.listCaseReviewAll();
}
@PostMapping("/relevance")

View File

@ -35,4 +35,6 @@ public class QueryCaseReviewRequest extends TestCaseReviewTestCase {
private String method;
private Map<String, Object> combine;
private String projectId;
}

View File

@ -156,6 +156,7 @@ public class TestCaseReviewService {
public List<TestCaseReviewDTO> listCaseReview(QueryCaseReviewRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
request.setProjectId(SessionUtils.getCurrentProjectId());
return extTestCaseReviewMapper.list(request);
}
@ -198,7 +199,7 @@ public class TestCaseReviewService {
}
public List<TestCaseReviewDTO> recent(String currentWorkspaceId) {
return extTestCaseReviewMapper.listByWorkspaceId(currentWorkspaceId, SessionUtils.getUserId());
return extTestCaseReviewMapper.listByWorkspaceId(currentWorkspaceId, SessionUtils.getUserId(), SessionUtils.getCurrentProjectId());
}
public void editCaseReview(SaveTestCaseReviewRequest testCaseReview) {
@ -346,21 +347,16 @@ public class TestCaseReviewService {
testCaseReviewTestCaseMapper.deleteByExample(testCaseReviewTestCaseExample);
}
public List<TestCaseReview> listCaseReviewAll(String currentWorkspaceId) {
ProjectExample projectExample = new ProjectExample();
projectExample.createCriteria().andWorkspaceIdEqualTo(currentWorkspaceId);
List<Project> projects = projectMapper.selectByExample(projectExample);
List<String> projectIds = projects.stream().map(Project::getId).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(projectIds)) {
TestCaseReviewProjectExample testCaseReviewProjectExample = new TestCaseReviewProjectExample();
testCaseReviewProjectExample.createCriteria().andProjectIdIn(projectIds);
List<TestCaseReviewProject> testCaseReviewProjects = testCaseReviewProjectMapper.selectByExample(testCaseReviewProjectExample);
List<String> reviewIds = testCaseReviewProjects.stream().map(TestCaseReviewProject::getReviewId).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(reviewIds)) {
public List<TestCaseReview> listCaseReviewAll() {
TestCaseReviewProjectExample reviewProjectExample = new TestCaseReviewProjectExample();
TestCaseReviewProjectExample.Criteria criteria = reviewProjectExample.createCriteria();
if (StringUtils.isNotBlank(SessionUtils.getCurrentProjectId())) {
criteria.andProjectIdEqualTo(SessionUtils.getCurrentProjectId());
List<TestCaseReviewProject> testCaseReviewProjects = testCaseReviewProjectMapper.selectByExample(reviewProjectExample);
if (!CollectionUtils.isEmpty(testCaseReviewProjects)) {
List<String> caseReviewIds = testCaseReviewProjects.stream().map(TestCaseReviewProject::getReviewId).collect(Collectors.toList());
TestCaseReviewExample testCaseReviewExample = new TestCaseReviewExample();
testCaseReviewExample.createCriteria().andIdIn(reviewIds);
testCaseReviewExample.createCriteria().andIdIn(caseReviewIds);
return testCaseReviewMapper.selectByExample(testCaseReviewExample);
}
}
@ -481,7 +477,8 @@ public class TestCaseReviewService {
request.setReviewerId(user.getId());
}
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
request.setReviewIds(extTestReviewCaseMapper.findRelateTestReviewId(user.getId(), SessionUtils.getCurrentWorkspaceId()));
request.setProjectId(SessionUtils.getCurrentProjectId());
request.setReviewIds(extTestReviewCaseMapper.findRelateTestReviewId(user.getId(), SessionUtils.getCurrentWorkspaceId(), user.getLastProjectId()));
List<String> projectIds = extProjectMapper.getProjectIdByWorkspaceId(SessionUtils.getCurrentWorkspaceId());
@ -545,9 +542,11 @@ public class TestCaseReviewService {
if (userIds.size() > 0) {
for (String id : userIds) {
stringBuilder.append(userMap.get(id)).append("");
if (StringUtils.isNotBlank(userMap.get(id))) {
stringBuilder.append(userMap.get(id)).append("");
}
}
name = stringBuilder.toString().substring(0, stringBuilder.length() - 1);
name = stringBuilder.substring(0, stringBuilder.length() - 1);
}
return name;
}

View File

@ -220,27 +220,17 @@ public class TestCaseService {
public List<TestCase> recentTestPlans(QueryTestCaseRequest request, int count) {
if (StringUtils.isBlank(request.getWorkspaceId())) {
return null;
}
ProjectExample projectExample = new ProjectExample();
projectExample.createCriteria().andWorkspaceIdEqualTo(request.getWorkspaceId());
List<String> projectIds = projectMapper.selectByExample(projectExample).stream()
.map(Project::getId).collect(Collectors.toList());
if (projectIds.isEmpty()) {
return null;
}
PageHelper.startPage(1, count, true);
TestCaseExample testCaseExample = new TestCaseExample();
testCaseExample.createCriteria().andProjectIdIn(projectIds).andMaintainerEqualTo(request.getUserId());
testCaseExample.setOrderByClause("update_time desc, sort desc");
return testCaseMapper.selectByExample(testCaseExample);
TestCaseExample.Criteria criteria = testCaseExample.createCriteria();
criteria.andMaintainerEqualTo(request.getUserId());
String projectId = SessionUtils.getCurrentProjectId();
if (StringUtils.isNotBlank(projectId)) {
criteria.andProjectIdEqualTo(projectId);
testCaseExample.setOrderByClause("update_time desc, sort desc");
return testCaseMapper.selectByExample(testCaseExample);
}
return new ArrayList<>();
}
public Project getProjectByTestCaseId(String testCaseId) {

View File

@ -327,6 +327,10 @@ public class TestPlanService {
public List<TestPlanDTOWithMetric> listTestPlan(QueryTestPlanRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
String projectId = SessionUtils.getCurrentProjectId();
if (StringUtils.isNotBlank(projectId)) {
request.setProjectId(projectId);
}
List<TestPlanDTOWithMetric> testPlans = extTestPlanMapper.list(request);
calcTestPlanRate(testPlans);
return testPlans;
@ -392,17 +396,41 @@ public class TestPlanService {
if (StringUtils.isBlank(currentWorkspaceId)) {
return null;
}
TestPlanExample testPlanTestCaseExample = new TestPlanExample();
testPlanTestCaseExample.createCriteria().andWorkspaceIdEqualTo(currentWorkspaceId)
.andPrincipalEqualTo(SessionUtils.getUserId());
testPlanTestCaseExample.setOrderByClause("update_time desc");
return testPlanMapper.selectByExample(testPlanTestCaseExample);
TestPlanProjectExample testPlanProjectExample = new TestPlanProjectExample();
TestPlanProjectExample.Criteria criteria = testPlanProjectExample.createCriteria();
if (StringUtils.isNotBlank(SessionUtils.getCurrentProjectId())) {
criteria.andProjectIdEqualTo(SessionUtils.getCurrentProjectId());
List<TestPlanProject> testPlanProjects = testPlanProjectMapper.selectByExample(testPlanProjectExample);
if (!CollectionUtils.isEmpty(testPlanProjects)) {
List<String> testPlanIds = testPlanProjects.stream().map(TestPlanProject::getTestPlanId).collect(Collectors.toList());
TestPlanExample testPlanTestCaseExample = new TestPlanExample();
testPlanTestCaseExample.createCriteria().andWorkspaceIdEqualTo(currentWorkspaceId)
.andIdIn(testPlanIds)
.andPrincipalEqualTo(SessionUtils.getUserId());
testPlanTestCaseExample.setOrderByClause("update_time desc");
return testPlanMapper.selectByExample(testPlanTestCaseExample);
}
}
return new ArrayList<>();
}
public List<TestPlan> listTestAllPlan(String currentWorkspaceId) {
TestPlanExample testPlanExample = new TestPlanExample();
testPlanExample.createCriteria().andWorkspaceIdEqualTo(currentWorkspaceId);
return testPlanMapper.selectByExample(testPlanExample);
TestPlanProjectExample testPlanProjectExample = new TestPlanProjectExample();
TestPlanProjectExample.Criteria criteria = testPlanProjectExample.createCriteria();
if (StringUtils.isNotBlank(SessionUtils.getCurrentProjectId())) {
criteria.andProjectIdEqualTo(SessionUtils.getCurrentProjectId());
List<TestPlanProject> testPlanProjects = testPlanProjectMapper.selectByExample(testPlanProjectExample);
if (!CollectionUtils.isEmpty(testPlanProjects)) {
List<String> testPlanIds = testPlanProjects.stream().map(TestPlanProject::getTestPlanId).collect(Collectors.toList());
TestPlanExample testPlanExample = new TestPlanExample();
TestPlanExample.Criteria testPlanCriteria = testPlanExample.createCriteria();
testPlanCriteria.andWorkspaceIdEqualTo(currentWorkspaceId);
testPlanCriteria.andIdIn(testPlanIds);
return testPlanMapper.selectByExample(testPlanExample);
}
}
return new ArrayList<>();
}
public List<TestPlanDTOWithMetric> listRelateAllPlan() {
@ -410,7 +438,8 @@ public class TestPlanService {
QueryTestPlanRequest request = new QueryTestPlanRequest();
request.setPrincipal(user.getId());
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
request.setPlanIds(extTestPlanTestCaseMapper.findRelateTestPlanId(user.getId(), SessionUtils.getCurrentWorkspaceId()));
request.setProjectId(SessionUtils.getCurrentProjectId());
request.setPlanIds(extTestPlanTestCaseMapper.findRelateTestPlanId(user.getId(), SessionUtils.getCurrentWorkspaceId(), SessionUtils.getCurrentProjectId()));
List<TestPlanDTOWithMetric> testPlans = extTestPlanMapper.listRelate(request);
calcTestPlanRate(testPlans);
return testPlans;

View File

@ -123,7 +123,7 @@ public class TestPlanTestCaseService {
public void buildQueryRequest(QueryTestPlanCaseRequest request, int count) {
SessionUser user = SessionUtils.getUser();
List<String> relateTestPlanIds = extTestPlanTestCaseMapper.findRelateTestPlanId(user.getId(), SessionUtils.getCurrentWorkspaceId());
List<String> relateTestPlanIds = extTestPlanTestCaseMapper.findRelateTestPlanId(user.getId(), SessionUtils.getCurrentWorkspaceId(), SessionUtils.getCurrentProjectId());
PageHelper.startPage(1, count, true);
request.setPlanIds(relateTestPlanIds);
request.setExecutor(user.getId());

View File

@ -14,6 +14,7 @@ import io.metersphere.xmind.parser.XmindParser;
import io.metersphere.xmind.parser.pojo.Attached;
import io.metersphere.xmind.parser.pojo.JsonRootBean;
import io.metersphere.xmind.utils.DetailUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;
@ -185,7 +186,7 @@ public class XmindCaseParser {
String nodePath = parent.getPath() + "/" + item.getTitle();
item.setPath(nodePath);
item.setParent(parent);
if (item.getChildren() != null && !item.getChildren().getAttached().isEmpty()) {
if (item.getChildren() != null && CollectionUtils.isNotEmpty(item.getChildren().getAttached())) {
recursion(item, level + 1, item.getChildren().getAttached());
} else {
if (!nodePath.startsWith("/")) {

View File

@ -46,6 +46,14 @@ export default {
logoId: '_blank',
}
},
created() {
if (localStorage.getItem("store")) {
this.$store.replaceState(Object.assign({}, this.$store.state, JSON.parse(localStorage.getItem("store"))))
}
window.addEventListener("beforeunload", () => {
localStorage.setItem("store", JSON.stringify(this.$store.state))
})
},
beforeCreate() {
this.$get("/isLogin").then(response => {
if (response.data.success) {

View File

@ -2,21 +2,32 @@
<div v-loading="loading">
<el-card>
<el-row>
<div class="el-step__icon is-text ms-api-col" v-if="request.referenced">
<div class="el-step__icon is-text ms-api-col" v-if="request.referenced!=undefined && request.referenced==='Deleted' || request.referenced=='REF'">
<div class="el-step__icon-inner">{{request.index}}</div>
</div>
<div class="el-step__icon is-text ms-api-col-create" v-else>
<div class="el-step__icon-inner">{{request.index}}</div>
</div>
<i class="icon el-icon-arrow-right" :class="{'is-active': request.active}"
@click="active(request)" v-if="request.referenced!=undefined && request.referenced!='Deleted' && request.referenced!='REF'"/>
<span>{{request.type!= 'create' ? request.name:''}} </span>
<el-button v-if="request.referenced!=undefined && request.referenced==='Deleted' || request.referenced=='REF'" class="ms-left-buttion" size="small">
{{$t('api_test.automation.api_list_import')}}
</el-button>
<el-button v-if="request.referenced==undefined || request.referenced==='Created' || request.referenced==='Copy'" class="ms-create-buttion" size="small">
{{$t('api_test.automation.customize_req')}}
</el-button>
<span v-if="request.referenced!=undefined && request.referenced==='Deleted' || request.referenced=='REF'">{{request.name}} </span>
<el-input size="small" v-model="request.name" style="width: 40%;" :placeholder="$t('commons.input_name')" v-else/>
<el-tag size="mini" style="margin-left: 20px" v-if="request.referenced==='Deleted'" type="danger">{{$t('api_test.automation.reference_deleted')}}</el-tag>
<el-tag size="mini" style="margin-left: 20px" v-if="request.referenced ==='REF'">{{ $t('api_test.scenario.reference') }}</el-tag>
<el-button size="mini" type="danger" icon="el-icon-delete" circle @click="remove" style="margin-right: 20px; float: right"/>
<div style="margin-right: 20px; float: right">
<i class="icon el-icon-arrow-right" :class="{'is-active': request.active}"
@click="active(request)" v-if="request.referenced!=undefined && request.referenced!='Deleted' && request.referenced!='REF'"/>
<el-switch v-model="request.enable" style="margin-left: 10px"/>
<el-button size="mini" icon="el-icon-delete" circle @click="remove" style="margin-left: 10px"/>
</div>
</el-row>
<!-- 请求参数-->
<el-collapse-transition>
@ -112,6 +123,12 @@
color: #F56C6C;
}
.ms-left-buttion {
color: #F56C6C;
background-color: #FCF1F1;
margin-right: 20px;
}
.ms-api-col-create {
background-color: #EBF2F2;
border-color: #008080;
@ -127,6 +144,12 @@
transform: rotate(90deg);
}
.ms-create-buttion {
color: #008080;
background-color: #EBF2F2;
margin-right: 20px;
}
.tip {
padding: 3px 5px;
font-size: 16px;

View File

@ -61,7 +61,9 @@
this.request.method = row.method;
}
this.request.resourceId = getUUID();
this.$emit('addCustomizeApi', this.request);
let obj = {};
Object.assign(obj, this.request);
this.$emit('addCustomizeApi', obj);
},
reload() {
this.loading = true

View File

@ -2,13 +2,17 @@
<div v-loading="loading">
<el-card>
<el-row>
<div class="el-step__icon is-text ms-api-col" style="float: left">
<div class="el-step__icon is-text ms-api-col">
<div class="el-step__icon-inner">{{scenario.index}}</div>
</div>
<div style="margin-left: 20px;float: left"> {{scenario.name}}</div>
<el-button class="ms-title-buttion" size="small">{{$t('api_test.automation.scenario_import')}}</el-button>
{{scenario.name}}
<el-tag size="mini" style="margin-left: 20px" v-if="scenario.referenced==='Deleted'" type="danger">{{$t('api_test.automation.reference_deleted')}}</el-tag>
<el-tag size="mini" style="margin-left: 20px" v-if="scenario.referenced==='REF'">{{ $t('api_test.scenario.reference') }}</el-tag>
<el-button size="mini" type="danger" icon="el-icon-delete" circle @click="remove" style="margin-right: 20px; float: right"/>
<div style="margin-right: 20px; float: right">
<el-switch v-model="scenario.enable" style="margin-left: 10px"/>
<el-button size="mini" icon="el-icon-delete" circle @click="remove" style="margin-left: 10px"/>
</div>
</el-row>
</el-card>
</div>
@ -73,6 +77,12 @@
padding: 15px;
}
.ms-title-buttion {
background-color: #F4F4F5;
margin-right: 20px;
color: #606266;
}
.icon.is-active {
transform: rotate(90deg);
}

View File

@ -2,23 +2,15 @@
<div>
<el-card>
<el-row>
<div class="el-step__icon is-text ms-api-col" style="float: left">
<div class="el-step__icon is-text ms-api-col">
<div class="el-step__icon-inner">{{timer.index}}</div>
</div>
<div>
<el-row :gutter="10" type="flex" align="middle">
<el-col :span="2">{{ $t('api_test.request.wait') }}</el-col>
<el-col :span="10">
<el-input-number class="width-100" size="small" v-model="timer.delay" :min="0" :step="1000"/>
</el-col>
<el-col :span="2">ms</el-col>
<el-col :span="8">
<el-switch v-model="timer.enable" :inactive-text="$t('api_test.scenario.enable_disable')"/>
</el-col>
<el-col :span="2">
<el-button size="mini" type="danger" icon="el-icon-delete" circle @click="remove"/>
</el-col>
</el-row>
<el-button class="ms-title-buttion" size="small">{{$t('api_test.automation.wait_controller')}}</el-button>
<el-input-number class="width-100" size="small" v-model="timer.delay" :min="0" :step="1000"/>
ms
<div style="margin-right: 20px; float: right">
<el-switch v-model="timer.enable" style="margin-left: 10px"/>
<el-button size="mini" icon="el-icon-delete" circle @click="remove" style="margin-left: 10px;"/>
</div>
</el-row>
</el-card>
@ -37,7 +29,7 @@
},
methods: {
remove() {
this.$emit('remove', this.timer,this.node);
this.$emit('remove', this.timer, this.node);
}
}
}
@ -45,7 +37,7 @@
<style scoped>
.width-100 {
width: 100%
width: 40%
}
.ms-api-col {
@ -55,6 +47,12 @@
color: #67C23A;
}
.ms-title-buttion {
background-color: #F2F9EE;
color: #67C23A;
margin-right: 20px;
}
/deep/ .el-card__body {
padding: 15px;
}

View File

@ -1,10 +1,10 @@
<template>
<el-card class="card-content">
<div style="background-color: white;">
<div class="ms-main-div">
<el-row>
<el-col>
<!--操作按钮-->
<div style="float: right;margin-right: 20px">
<div class="ms-opt-btn">
<el-button type="primary" size="small" @click="editScenario">{{$t('commons.save')}}</el-button>
</div>
</el-col>
@ -119,7 +119,7 @@
<el-row>
<el-col :span="21">
<!-- 调试部分 -->
<div style="margin-left: 20px;border:1px #DCDFE6 solid;border-radius: 4px;margin-right: 10px">
<div class="ms-debug-div">
<el-row style="margin: 5px">
<el-col :span="6" class="ms-col-one">
{{currentScenario.name ===undefined || ''? $t('api_test.scenario.name') : currentScenario.name}}
@ -199,37 +199,37 @@
<el-button type="primary" icon="el-icon-refresh" size="small" @click="showAll">{{$t('commons.show_all')}}</el-button>
<br/>
<div v-if="operatingElements.indexOf('HTTPSamplerProxy')>0 || operatingElements.indexOf('DubboSampler')>0 || operatingElements.indexOf('JDBCSampler')>0 || operatingElements.indexOf('TCPSampler')>0 ">
<el-button class="ms-right-buttion" size="small" style="color: #F56C6C;background-color: #FCF1F1" @click="apiListImport">+{{$t('api_test.automation.api_list_import')}}</el-button>
<el-button class="ms-right-buttion ms-btn-1" size="small" @click="apiListImport">+{{$t('api_test.automation.api_list_import')}}</el-button>
</div>
<!--<div v-if="operatingElements.indexOf('OT_IMPORT')>0">
<el-button class="ms-right-buttion" size="small" style="color: #409EFF;background-color: #EEF5FE" @click="addComponent('OT_IMPORT')">+{{$t('api_test.automation.external_import')}}</el-button>
</div>-->
<div v-if="operatingElements.indexOf('ConstantTimer')>0">
<el-button class="ms-right-buttion" size="small" style="color: #67C23A;background-color: #F2F9EE" @click="addComponent('ConstantTimer')">+{{$t('api_test.automation.wait_controller')}}</el-button>
<el-button class="ms-right-buttion ms-btn-3" size="small" @click="addComponent('ConstantTimer')">+{{$t('api_test.automation.wait_controller')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('IfController')>0">
<el-button class="ms-right-buttion" size="small" style="color: #E6A23C;background-color: #FCF6EE" @click="addComponent('IfController')">+{{$t('api_test.automation.if_controller')}}</el-button>
<el-button class="ms-right-buttion ms-btn-4" size="small" @click="addComponent('IfController')">+{{$t('api_test.automation.if_controller')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('scenario')===0">
<el-button class="ms-right-buttion" size="small" style="color: #606266;background-color: #F4F4F5" @click="addComponent('scenario')">+{{$t('api_test.automation.scenario_import')}}</el-button>
<el-button class="ms-right-buttion ms-btn-5" size="small" @click="addComponent('scenario')">+{{$t('api_test.automation.scenario_import')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('JSR223Processor')>0">
<el-button class="ms-right-buttion" size="small" style="color: #7B4D12;background-color: #F1EEE9" @click="addComponent('JSR223Processor')">+{{$t('api_test.automation.customize_script')}}</el-button>
<el-button class="ms-right-buttion ms-btn-6" size="small" @click="addComponent('JSR223Processor')">+{{$t('api_test.automation.customize_script')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('CustomizeReq')>0">
<el-button class="ms-right-buttion" size="small" style="color: #008080;background-color: #EBF2F2" @click="addComponent('CustomizeReq')">+{{$t('api_test.automation.customize_req')}}</el-button>
<el-button class="ms-right-buttion ms-btn-7" size="small" @click="addComponent('CustomizeReq')">+{{$t('api_test.automation.customize_req')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('JSR223PreProcessor')>0">
<el-button class="ms-right-buttion" size="small" style="color: #B8741A;background-color: #F9F1EA" @click="addComponent('JSR223PreProcessor')">+{{$t('api_test.definition.request.pre_script')}}</el-button>
<el-button class="ms-right-buttion ms-btn-8" size="small" @click="addComponent('JSR223PreProcessor')">+{{$t('api_test.definition.request.pre_script')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('JSR223PostProcessor')>0">
<el-button class="ms-right-buttion" size="small" style="color: #783887;background-color: #F2ECF3" @click="addComponent('JSR223PostProcessor')">+{{$t('api_test.definition.request.post_script')}}</el-button>
<el-button class="ms-right-buttion ms-btn-9" size="small" @click="addComponent('JSR223PostProcessor')">+{{$t('api_test.definition.request.post_script')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('Assertions')>0">
<el-button class="ms-right-buttion" size="small" style="color: #A30014;background-color: #F7E6E9" @click="addComponent('Assertions')">+{{$t('api_test.definition.request.assertions_rule')}}</el-button>
<el-button class="ms-right-buttion ms-btn-10" size="small" @click="addComponent('Assertions')">+{{$t('api_test.definition.request.assertions_rule')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('Extract')>0">
<el-button class="ms-right-buttion" size="small" style="color: #015478;background-color: #E6EEF2" @click="addComponent('Extract')">+{{$t('api_test.definition.request.extract_param')}}</el-button>
<el-button class="ms-right-buttion ms-btn-11" size="small" @click="addComponent('Extract')">+{{$t('api_test.definition.request.extract_param')}}</el-button>
</div>
</el-col>
</div>
@ -245,7 +245,7 @@
<!--自定义接口-->
<el-drawer :visible.sync="customizeVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('api_test.automation.customize_req')" style="overflow: auto" :modal="false" size="90%">
<ms-api-customize :request="customizeRequest" @addCustomizeApi="addCustomizeApi" />
<ms-api-customize :request="customizeRequest" @addCustomizeApi="addCustomizeApi"/>
<!--<el-button style="float: right;margin: 20px" @click="addCustomizeApi">{{$t('commons.save')}}</el-button>-->
</el-drawer>
<!--场景导入 -->
@ -361,38 +361,6 @@
},
watch: {},
methods: {
nodeClick(e) {
if (e.referenced != 'REF' && e.referenced != 'Deleted') {
this.operatingElements = ELEMENTS.get(e.type);
} else {
this.operatingElements = [];
}
this.selectedTreeNode = e;
},
showAll() {
this.operatingElements = ELEMENTS.get("ALL");
this.selectedTreeNode = undefined;
this.reload();
},
apiListImport() {
this.apiListVisible = true;
},
recursiveSorting(arr) {
for (let i in arr) {
arr[i].index = Number(i) + 1;
if (arr[i].hashTree != undefined && arr[i].hashTree.length > 0) {
this.recursiveSorting(arr[i].hashTree);
}
}
},
sort() {
for (let i in this.scenarioDefinition) {
this.scenarioDefinition[i].index = Number(i) + 1;
if (this.scenarioDefinition[i].hashTree != undefined && this.scenarioDefinition[i].hashTree.length > 0) {
this.recursiveSorting(this.scenarioDefinition[i].hashTree);
}
}
},
addComponent(type) {
switch (type) {
case ELEMENT_TYPE.IfController:
@ -436,8 +404,41 @@
this.sort();
this.reload();
},
nodeClick(e) {
if (e.referenced != 'REF' && e.referenced != 'Deleted') {
this.operatingElements = ELEMENTS.get(e.type);
} else {
this.operatingElements = [];
}
this.selectedTreeNode = e;
},
showAll() {
this.operatingElements = ELEMENTS.get("ALL");
this.selectedTreeNode = undefined;
this.reload();
},
apiListImport() {
this.apiListVisible = true;
},
recursiveSorting(arr) {
for (let i in arr) {
arr[i].index = Number(i) + 1;
if (arr[i].hashTree != undefined && arr[i].hashTree.length > 0) {
this.recursiveSorting(arr[i].hashTree);
}
}
},
sort() {
for (let i in this.scenarioDefinition) {
this.scenarioDefinition[i].index = Number(i) + 1;
if (this.scenarioDefinition[i].hashTree != undefined && this.scenarioDefinition[i].hashTree.length > 0) {
this.recursiveSorting(this.scenarioDefinition[i].hashTree);
}
}
},
addCustomizeApi(request) {
this.customizeVisible = false;
request.enable === undefined ? request.enable = true : request.enable;
if (this.selectedTreeNode != undefined) {
this.selectedTreeNode.hashTree.push(request);
} else {
@ -450,6 +451,7 @@
addScenario(arr) {
if (arr.length > 0) {
arr.forEach(item => {
item.enable === undefined ? item.enable = true : item.enable;
this.scenarioDefinition.push(item);
})
}
@ -470,6 +472,7 @@
request = item.request;
}
request.referenced = referenced;
request.enable === undefined ? request.enable = true : request.enable;
request.active = false;
request.resourceId = getUUID();
if (referenced === 'REF') {
@ -489,6 +492,7 @@
request = item.request;
}
request.referenced = referenced;
request.enable === undefined ? request.enable = true : request.enable;
request.active = false;
request.resourceId = getUUID();
if (referenced === 'REF') {
@ -734,6 +738,22 @@
width: 100%;
}
.ms-main-div {
background-color: white;
}
.ms-opt-btn {
float: right;
margin-right: 20px;
}
.ms-debug-div {
margin-left: 20px;
border: 1px #DCDFE6 solid;
border-radius: 4px;
margin-right: 10px;
}
.ms-scenario-button {
margin-left: 30%;
padding: 7px;
@ -761,6 +781,61 @@
margin-top: 10px;
}
.ms-btn-1 {
color: #F56C6C;
background-color: #FCF1F1
}
.ms-btn-2 {
color: #F56C6C;
background-color: #FCF1F1
}
.ms-btn-3 {
color: #67C23A;
background-color: #F2F9EE
}
.ms-btn-4 {
color: #E6A23C;
background-color: #FCF6EE
}
.ms-btn-5 {
color: #606266;
background-color: #F4F4F5
}
.ms-btn-6 {
color: #7B4D12;
background-color: #F1EEE9
}
.ms-btn-7 {
color: #008080;
background-color: #EBF2F2
}
.ms-btn-8 {
color: #B8741A;
background-color: #F9F1EA
}
.ms-btn-9 {
color: #783887;
background-color: #F2ECF3
}
.ms-btn-10 {
color: #A30014;
background-color: #F7E6E9
}
.ms-btn-11 {
color: #015478;
background-color: #E6EEF2
}
/deep/ .el-tree-node__content {
height: 100%;
margin-top: 8px;
@ -775,4 +850,7 @@
overflow: auto;
}
/deep/ .el-step__icon.is-text {
border: 1px solid;
}
</style>

View File

@ -1,31 +1,22 @@
<template>
<el-card>
<el-row>
<div class="el-step__icon is-text ms-api-col" style="float: left">
<div class="el-step__icon is-text ms-api-col">
<div class="el-step__icon-inner">{{controller.index}}</div>
</div>
<div>
<el-row :gutter="10" type="flex" align="middle">
<el-col :span="1">If</el-col>
<el-col :span="6">
<el-input size="small" v-model="controller.variable" :placeholder="$t('api_test.request.condition_variable')"/>
</el-col>
<el-col :span="5">
<el-select v-model="controller.operator" :placeholder="$t('commons.please_select')" size="small"
@change="change">
<el-option v-for="o in operators" :key="o.value" :label="$t(o.label)" :value="o.value"/>
</el-select>
</el-col>
<el-col :span="6">
<el-input size="small" v-model="controller.value" :placeholder="$t('api_test.value')" v-if="!hasEmptyOperator"/>
</el-col>
<el-col :span="4">
<el-switch v-model="controller.enable" :inactive-text="$t('api_test.scenario.enable_disable')"/>
</el-col>
<el-col :span="2">
<el-button size="mini" type="danger" icon="el-icon-delete" circle @click="remove"/>
</el-col>
</el-row>
<el-button class="ms-title-buttion" size="small">{{$t('api_test.automation.if_controller')}}</el-button>
<el-input size="small" v-model="controller.variable" style="width: 20%" :placeholder="$t('api_test.request.condition_variable')"/>
<el-select v-model="controller.operator" :placeholder="$t('commons.please_select')" size="small"
@change="change" style="width: 10%;margin-left: 10px">
<el-option v-for="o in operators" :key="o.value" :label="$t(o.label)" :value="o.value"/>
</el-select>
<el-input size="small" v-model="controller.value" :placeholder="$t('api_test.value')" v-if="!hasEmptyOperator" style="width: 20%;margin-left: 20px"/>
<div style="margin-right: 20px; float: right">
<el-switch v-model="controller.enable" style="margin-left: 10px"/>
<el-button size="mini" icon="el-icon-delete" circle @click="remove" style="margin-left: 10px;"/>
</div>
</el-row>
</el-card>
@ -102,4 +93,10 @@
margin-right: 10px;
color: #E6A23C;
}
.ms-title-buttion {
background-color: #FCF6EE;
margin-right: 20px;
color: #E6A23C;
}
</style>

View File

@ -6,9 +6,12 @@
<div class="el-step__icon-inner">{{jsr223ProcessorData.index}}</div>
</div>
<el-button class="ms-left-buttion" size="small" :style="styleType" style="color: #B8741A;background-color: #F9F1EA">{{title}}</el-button>
<i class="icon el-icon-arrow-right" :class="{'is-active': this.jsr223ProcessorData.active}" @click="changeActive" style="margin-left: 20px"/>
<el-input size="small" v-model="jsr223ProcessorData.name" class="ms-api-header-select" style="width: 380px"/>
<el-button size="small" style="float: right" @click="remove">{{$t('commons.remove')}}</el-button>
<el-input size="small" v-model="jsr223ProcessorData.name" :placeholder="$t('commons.input_name')" class="ms-api-header-select" style="width: 40%"/>
<div style="margin-right: 20px; float: right">
<i class="icon el-icon-arrow-right" :class="{'is-active': this.jsr223ProcessorData.active}" @click="changeActive" style="margin-left: 20px"/>
<el-switch v-model="jsr223ProcessorData.enable" style="margin-left: 10px"/>
<el-button size="mini" icon="el-icon-delete" circle @click="remove" style="margin-left: 10px;"/>
</div>
</div>
</el-row>
<el-collapse-transition>

View File

@ -1,7 +1,7 @@
<template>
<ms-container>
<ms-aside-container>
<ms-node-tree @selectModule="selectModule" @getApiModuleTree="initTree" @changeProject="changeProject" @changeProtocol="changeProtocol"
<ms-node-tree @selectModule="selectModule" @getApiModuleTree="initTree" @changeProtocol="changeProtocol"
@refresh="refresh" @saveAsEdit="editApi" @debug="debug" @exportAPI="exportAPI"/>
</ms-aside-container>
@ -15,7 +15,8 @@
<el-dropdown-item command="closeAll">{{$t('api_test.definition.request.close_all_label')}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!-- 主框架列表 -->
<!-- 主框架列表 -->
<el-tabs v-model="apiDefaultTab" @edit="handleTabsEdit">
<el-tab-pane
:key="item.name"
@ -26,7 +27,6 @@
<!-- 列表集合 -->
<ms-api-list
v-if="item.type === 'list'"
:current-project="currentProject"
:current-protocol="currentProtocol"
:current-module="currentModule"
@editApi="editApi"
@ -38,7 +38,6 @@
<!-- 添加测试窗口-->
<div v-else-if="item.type=== 'add'" class="ms-api-div">
<ms-api-config @runTest="runTest" @saveApi="saveApi" :current-api="currentApi"
:currentProject="currentProject"
:currentProtocol="currentProtocol"
:moduleOptions="moduleOptions" ref="apiConfig"/>
</div>
@ -46,21 +45,21 @@
<!-- 快捷调试 -->
<div v-else-if="item.type=== 'debug'" class="ms-api-div">
<ms-debug-http-page :currentProtocol="currentProtocol" @saveAs="editApi" v-if="currentProtocol==='HTTP'"/>
<ms-debug-jdbc-page :currentProtocol="currentProtocol" :currentProject="currentProject" @saveAs="editApi" v-if="currentProtocol==='SQL'"/>
<ms-debug-tcp-page :currentProtocol="currentProtocol" :currentProject="currentProject" @saveAs="editApi" v-if="currentProtocol==='TCP'"/>
<ms-debug-dubbo-page :currentProtocol="currentProtocol" :currentProject="currentProject" @saveAs="editApi" v-if="currentProtocol==='DUBBO'"/>
<ms-debug-jdbc-page :currentProtocol="currentProtocol" @saveAs="editApi" v-if="currentProtocol==='SQL'"/>
<ms-debug-tcp-page :currentProtocol="currentProtocol" @saveAs="editApi" v-if="currentProtocol==='TCP'"/>
<ms-debug-dubbo-page :currentProtocol="currentProtocol" @saveAs="editApi" v-if="currentProtocol==='DUBBO'"/>
</div>
<!-- 测试-->
<div v-else-if="item.type=== 'test'" class="ms-api-div">
<ms-run-test-http-page :currentProtocol="currentProtocol" :api-data="runTestData" @saveAsApi="editApi" :currentProject="currentProject" v-if="currentProtocol==='HTTP'"/>
<ms-run-test-tcp-page :currentProtocol="currentProtocol" :api-data="runTestData" @saveAsApi="editApi" :currentProject="currentProject" v-if="currentProtocol==='TCP'"/>
<ms-run-test-sql-page :currentProtocol="currentProtocol" :api-data="runTestData" @saveAsApi="editApi" :currentProject="currentProject" v-if="currentProtocol==='SQL'"/>
<ms-run-test-dubbo-page :currentProtocol="currentProtocol" :api-data="runTestData" @saveAsApi="editApi" :currentProject="currentProject" v-if="currentProtocol==='DUBBO'"/>
<ms-run-test-http-page :currentProtocol="currentProtocol" :api-data="runTestData" @saveAsApi="editApi" v-if="currentProtocol==='HTTP'"/>
<ms-run-test-tcp-page :currentProtocol="currentProtocol" :api-data="runTestData" @saveAsApi="editApi" v-if="currentProtocol==='TCP'"/>
<ms-run-test-sql-page :currentProtocol="currentProtocol" :api-data="runTestData" @saveAsApi="editApi" v-if="currentProtocol==='SQL'"/>
<ms-run-test-dubbo-page :currentProtocol="currentProtocol" :api-data="runTestData" @saveAsApi="editApi" v-if="currentProtocol==='DUBBO'"/>
</div>
</el-tab-pane>
</el-tabs>
</ms-main-container>
@ -84,8 +83,7 @@
import MsRunTestTcpPage from "./components/runtest/RunTestTCPPage";
import MsRunTestSqlPage from "./components/runtest/RunTestSQLPage";
import MsRunTestDubboPage from "./components/runtest/RunTestDubboPage";
import {downloadFile, getCurrentUser, getUUID} from "@/common/js/utils";
import {downloadFile, getCurrentUser, getUUID, getCurrentProjectID} from "@/common/js/utils";
export default {
name: "ApiDefinition",
@ -118,7 +116,6 @@
return {
isHide: true,
apiDefaultTab: 'default',
currentProject: null,
currentProtocol: null,
currentModule: null,
currentApi: {},
@ -209,7 +206,7 @@
if (!this.$refs.apiList[0].tableData) {
return;
}
let obj = {projectName: this.currentProject.name, protocol: this.currentProtocol, data: this.$refs.apiList[0].tableData}
let obj = {projectName: getCurrentProjectID(), protocol: this.currentProtocol, data: this.$refs.apiList[0].tableData}
downloadFile("导出API.json", JSON.stringify(obj));
},
refresh(data) {
@ -236,9 +233,6 @@
initTree(data) {
this.moduleOptions = data;
},
changeProject(data) {
this.currentProject = data;
},
changeProtocol(data) {
this.currentProtocol = data;
}
@ -273,4 +267,11 @@
/deep/ .el-main {
overflow: hidden;
}
/deep/ .el-card {
/*border: 1px solid #EBEEF5;*/
/*border-style: none;*/
border-top: none;
}
</style>

View File

@ -1,161 +1,166 @@
<template>
<div>
<el-container style="padding-bottom: 200px">
<el-header style="width: 100% ;padding: 0px">
<el-card>
<el-row>
<el-col :span="api.protocol==='HTTP'? 3:5">
<div class="variable-combine"> {{api.name}}</div>
</el-col>
<el-col :span="api.protocol==='HTTP'? 1:3">
<ms-tag v-if="api.status == 'Prepare'" type="info" effect="plain" :content="$t('test_track.plan.plan_status_prepare')"/>
<ms-tag v-if="api.status == 'Underway'" type="warning" effect="plain" :content="$t('test_track.plan.plan_status_running')"/>
<ms-tag v-if="api.status == 'Completed'" type="success" effect="plain" :content="$t('test_track.plan.plan_status_completed')"/>
</el-col>
<el-col :span="api.protocol==='HTTP'? 4:0">
<div class="variable-combine" style="margin-left: 10px">{{api.path ===null ? " " : api.path}}</div>
</el-col>
<el-col :span="2">
<div>{{$t('test_track.plan_view.case_count')}}{{apiCaseList.length}}</div>
</el-col>
<el-col :span="3">
<div>
<el-select size="small" :placeholder="$t('api_test.definition.request.grade_info')" v-model="priorityValue"
class="ms-api-header-select" @change="getApiTest">
<el-option v-for="grd in priority" :key="grd.id" :label="grd.name" :value="grd.id"/>
</el-select>
</div>
</el-col>
<el-col :span="4">
<div>
<el-select :disabled="isReadOnly" v-model="environment" size="small" class="ms-api-header-select"
:placeholder="$t('api_test.definition.request.run_env')"
@change="environmentChange" clearable>
<el-option v-for="(environment, index) in environments" :key="index"
:label="environment.name + (environment.config.httpConfig.socket ? (': ' + environment.config.httpConfig.protocol + '://' + environment.config.httpConfig.socket) : '')"
:value="environment.id"/>
<el-button class="environment-button" size="mini" type="primary" @click="openEnvironmentConfig">
{{ $t('api_test.environment.environment_config') }}
</el-button>
<template v-slot:empty>
<div class="empty-environment">
<el-button class="environment-button" size="mini" type="primary" @click="openEnvironmentConfig">
{{ $t('api_test.environment.environment_config') }}
</el-button>
</div>
</template>
</el-select>
</div>
</el-col>
<el-col :span="3">
<div class="ms-api-header-select">
<el-input size="small" :placeholder="$t('api_test.definition.request.select_case')"
v-model="name" @blur="getApiTest"/>
</div>
</el-col>
<el-col :span="2">
<el-dropdown size="small" split-button type="primary" class="ms-api-header-select" @click="addCase"
@command="handleCommand">
+{{$t('api_test.definition.request.case')}}
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="run">{{$t('commons.test')}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<div v-if="visible" v-loading="result.loading">
<ms-drawer :size="40" direction="bottom">
</el-col>
<el-col :span="2">
<button type="button" aria-label="Close" class="el-card-btn" @click="apiCaseClose()"><i
class="el-dialog__close el-icon el-icon-close"></i></button>
</el-col>
</el-row>
</el-card>
<!-- 环境 -->
<api-environment-config ref="environmentConfig" @close="environmentConfigClose"/>
</el-header>
<!-- 用例部分 -->
<el-main v-loading="loading" style="overflow: auto">
<div v-for="(item,index) in apiCaseList" :key="index">
<el-card style="margin-top: 5px" @click.native="selectTestCase(item,$event)">
<template v-slot:header>
<el-header style="width: 100% ;padding: 0px">
<el-card>
<el-row>
<el-col :span="1">
<el-checkbox v-if="visible" @change="caseChecked(item)"/>
<el-col :span="api.protocol==='HTTP'? 3:5">
<div class="variable-combine"> {{api.name}}</div>
</el-col>
<el-col :span="5">
<div class="el-step__icon is-text ms-api-col">
<div class="el-step__icon-inner">{{index+1}}</div>
<el-col :span="api.protocol==='HTTP'? 1:3">
<ms-tag v-if="api.status == 'Prepare'" type="info" effect="plain" :content="$t('test_track.plan.plan_status_prepare')"/>
<ms-tag v-if="api.status == 'Underway'" type="warning" effect="plain" :content="$t('test_track.plan.plan_status_running')"/>
<ms-tag v-if="api.status == 'Completed'" type="success" effect="plain" :content="$t('test_track.plan.plan_status_completed')"/>
</el-col>
<el-col :span="api.protocol==='HTTP'? 4:0">
<div class="variable-combine" style="margin-left: 10px">{{api.path ===null ? " " : api.path}}</div>
</el-col>
<el-col :span="2">
<div>{{$t('test_track.plan_view.case_count')}}{{apiCaseList.length}}</div>
</el-col>
<el-col :span="3">
<div>
<el-select size="small" :placeholder="$t('api_test.definition.request.grade_info')" v-model="priorityValue"
class="ms-api-header-select" @change="getApiTest">
<el-option v-for="grd in priority" :key="grd.id" :label="grd.name" :value="grd.id"/>
</el-select>
</div>
<label class="ms-api-label">{{$t('test_track.case.priority')}}</label>
<el-select size="small" v-model="item.priority" class="ms-api-select">
<el-option v-for="grd in priority" :key="grd.id" :label="grd.name" :value="grd.id"/>
</el-select>
</el-col>
<el-col :span="10">
<i class="icon el-icon-arrow-right" :class="{'is-active': item.active}"
@click="active(item)"/>
<el-input v-if="item.type==='create'" size="small" v-model="item.name" :name="index" :key="index"
class="ms-api-header-select" style="width: 180px"
@blur="saveTestCase(item)"/>
<span v-else>
<el-col :span="4">
<div>
<el-select :disabled="isReadOnly" v-model="environment" size="small" class="ms-api-header-select"
:placeholder="$t('api_test.definition.request.run_env')"
@change="environmentChange" clearable>
<el-option v-for="(environment, index) in environments" :key="index"
:label="environment.name + (environment.config.httpConfig.socket ? (': ' + environment.config.httpConfig.protocol + '://' + environment.config.httpConfig.socket) : '')"
:value="environment.id"/>
<el-button class="environment-button" size="mini" type="primary" @click="openEnvironmentConfig">
{{ $t('api_test.environment.environment_config') }}
</el-button>
<template v-slot:empty>
<div class="empty-environment">
<el-button class="environment-button" size="mini" type="primary" @click="openEnvironmentConfig">
{{ $t('api_test.environment.environment_config') }}
</el-button>
</div>
</template>
</el-select>
</div>
</el-col>
<el-col :span="3">
<div class="ms-api-header-select">
<el-input size="small" :placeholder="$t('api_test.definition.request.select_case')"
v-model="name" @blur="getApiTest"/>
</div>
</el-col>
<el-col :span="2">
<el-dropdown size="small" split-button type="primary" class="ms-api-header-select" @click="addCase"
@command="handleCommand">
+{{$t('api_test.definition.request.case')}}
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="run">{{$t('commons.test')}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-col>
<el-col :span="2">
<button type="button" aria-label="Close" class="el-card-btn" @click="apiCaseClose()"><i
class="el-dialog__close el-icon el-icon-close"></i></button>
</el-col>
</el-row>
</el-card>
<!-- 环境 -->
<api-environment-config ref="environmentConfig" @close="environmentConfigClose"/>
</el-header>
</template>
<el-container style="padding-bottom: 200px">
<el-main v-loading="loading" style="overflow: auto">
<div v-for="(item,index) in apiCaseList" :key="index">
<el-card style="margin-top: 5px" @click.native="selectTestCase(item,$event)">
<el-row>
<el-col :span="1">
<el-checkbox v-if="visible" @change="caseChecked(item)"/>
</el-col>
<el-col :span="5">
<div class="el-step__icon is-text ms-api-col">
<div class="el-step__icon-inner">{{index+1}}</div>
</div>
<label class="ms-api-label">{{$t('test_track.case.priority')}}</label>
<el-select size="small" v-model="item.priority" class="ms-api-select">
<el-option v-for="grd in priority" :key="grd.id" :label="grd.name" :value="grd.id"/>
</el-select>
</el-col>
<el-col :span="10">
<i class="icon el-icon-arrow-right" :class="{'is-active': item.active}"
@click="active(item)"/>
<el-input v-if="item.type==='create'" size="small" v-model="item.name" :name="index" :key="index"
class="ms-api-header-select" style="width: 180px"
@blur="saveTestCase(item)"/>
<span v-else>
{{item.type!= 'create' ? item.name:''}}
<i class="el-icon-edit" style="cursor:pointer" @click="showInput(item)"/>
</span>
<div v-if="item.type!='create'" style="color: #999999;font-size: 12px">
<div v-if="item.type!='create'" style="color: #999999;font-size: 12px">
<span>
{{item.createTime | timestampFormatDate }}
{{item.createUser}} {{$t('api_test.definition.request.create_info')}}
</span>
<span>
<span>
{{item.updateTime | timestampFormatDate }}
{{item.updateUser}} {{$t('api_test.definition.request.update_info')}}
</span>
</div>
</el-col>
<el-col :span="4">
<ms-tip-button @click="singleRun(item)" :tip="$t('api_test.run')" icon="el-icon-video-play"
style="background-color: #409EFF;color: white" size="mini" circle/>
<ms-tip-button @click="copyCase(item)" :tip="$t('commons.copy')" icon="el-icon-document-copy"
size="mini" circle/>
<ms-tip-button @click="deleteCase(index,item)" :tip="$t('commons.delete')" icon="el-icon-delete"
size="mini" circle/>
<ms-api-extend-btns :row="item"/>
</el-col>
<el-col :span="3">
<div v-if="item.type!='create'">{{getResult(item.execResult)}}</div>
<div v-if="item.type!='create'" style="color: #999999;font-size: 12px">
<span> {{item.updateTime | timestampFormatDate }}</span>
{{item.updateUser}}
</div>
</el-col>
</el-row>
<!-- 请求参数-->
<el-collapse-transition>
<div v-if="item.active">
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-api-request-form :is-read-only="isReadOnly" :headers="item.request.headers " :request="item.request" v-if="api.protocol==='HTTP'"/>
<ms-tcp-basis-parameters :request="item.request" v-if="api.protocol==='TCP'"/>
<ms-sql-basis-parameters :request="item.request" v-if="api.protocol==='SQL'"/>
<ms-dubbo-basis-parameters :request="item.request" v-if="api.protocol==='DUBBO'"/>
<!-- 保存操作 -->
<el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(item)">
{{$t('commons.save')}}
</el-button>
</div>
</el-col>
</el-collapse-transition>
</el-card>
</div>
</el-main>
<el-col :span="4">
<ms-tip-button @click="singleRun(item)" :tip="$t('api_test.run')" icon="el-icon-video-play"
style="background-color: #409EFF;color: white" size="mini" circle/>
<ms-tip-button @click="copyCase(item)" :tip="$t('commons.copy')" icon="el-icon-document-copy"
size="mini" circle/>
<ms-tip-button @click="deleteCase(index,item)" :tip="$t('commons.delete')" icon="el-icon-delete"
size="mini" circle/>
<ms-api-extend-btns :row="item"/>
</el-col>
<el-col :span="3">
<div v-if="item.type!='create'">{{getResult(item.execResult)}}</div>
<div v-if="item.type!='create'" style="color: #999999;font-size: 12px">
<span> {{item.updateTime | timestampFormatDate }}</span>
{{item.updateUser}}
</div>
</el-col>
</el-row>
<!-- 请求参数-->
<el-collapse-transition>
<div v-if="item.active">
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-api-request-form :is-read-only="isReadOnly" :headers="item.request.headers " :request="item.request" v-if="api.protocol==='HTTP'"/>
<ms-tcp-basis-parameters :request="item.request" :currentProject="currentProject" v-if="api.protocol==='TCP'"/>
<ms-sql-basis-parameters :request="item.request" :currentProject="currentProject" v-if="api.protocol==='SQL'"/>
<ms-dubbo-basis-parameters :request="item.request" :currentProject="currentProject" v-if="api.protocol==='DUBBO'"/>
<!-- 保存操作 -->
<el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(item)">
{{$t('commons.save')}}
</el-button>
</div>
</el-collapse-transition>
</el-card>
</div>
</el-main>
</el-container>
</el-container>
</ms-drawer>
<!-- 执行组件 -->
<ms-run :debug="false" :environment="environment" :reportId="reportId" :run-data="runData"
@ -168,7 +173,7 @@
import MsTag from "../../../common/components/MsTag";
import MsTipButton from "../../../common/components/MsTipButton";
import MsApiRequestForm from "./request/http/ApiRequestForm";
import {downloadFile, getUUID} from "@/common/js/utils";
import {downloadFile, getUUID, getCurrentProjectID} from "@/common/js/utils";
import {parseEnvironment} from "../model/EnvironmentModel";
import ApiEnvironmentConfig from "./environment/ApiEnvironmentConfig";
import {PRIORITY, RESULT_MAP} from "../model/JsonData";
@ -177,11 +182,13 @@
import MsSqlBasisParameters from "./request/database/BasisParameters";
import MsTcpBasisParameters from "./request/tcp/BasisParameters";
import MsDubboBasisParameters from "./request/dubbo/BasisParameters";
import MsDrawer from "../../../common/components/MsDrawer";
import MsApiExtendBtns from "./reference/ApiExtendBtns";
export default {
name: 'ApiCaseList',
components: {
MsDrawer,
MsTag,
MsTipButton,
MsApiRequestForm,
@ -198,10 +205,6 @@
type: Object
},
createCase: String,
visible: {
type: Boolean,
default: false,
},
loaded: Boolean,
currentProject: {},
refreshSign: String,
@ -209,6 +212,7 @@
},
data() {
return {
result: {},
grades: [],
environments: [],
environment: {},
@ -221,7 +225,9 @@
loading: false,
runData: [],
reportId: "",
projectId: "",
checkedCases: new Set(),
visible: false
}
},
@ -250,6 +256,7 @@
}
},
created() {
this.projectId = getCurrentProjectID();
this.getEnvironments();
if (this.createCase) {
this.sysAddition();
@ -258,6 +265,10 @@
}
},
methods: {
open() {
// this.apiCaseList = [];
this.visible = true;
},
sysAddition() {
let condition = {};
condition.projectId = this.api.projectId;
@ -292,7 +303,7 @@
},
apiCaseClose() {
this.apiCaseList = [];
this.$emit('apiCaseClose');
this.visible = false;
},
batchRun() {
if (!this.environment) {
@ -403,7 +414,7 @@
condition.apiDefinitionId = this.api.id;
condition.priority = this.priorityValue;
condition.name = this.name;
this.$post("/api/testcase/list", condition, response => {
this.result = this.$post("/api/testcase/list", condition, response => {
for (let index in response.data) {
let test = response.data[index];
test.request = JSON.parse(test.request);
@ -438,8 +449,8 @@
});
},
getEnvironments() {
if (this.currentProject) {
this.$get('/api/environment/list/' + this.currentProject.id, response => {
if (this.projectId) {
this.$get('/api/environment/list/' + this.projectId, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
@ -460,11 +471,11 @@
}
},
openEnvironmentConfig() {
if (!this.currentProject) {
if (!this.projectId) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.environmentConfig.open(this.currentProject.id);
this.$refs.environmentConfig.open(this.projectId);
},
environmentChange(value) {
for (let i in this.environments) {
@ -504,6 +515,9 @@
}
let arr = Array.from(this.checkedCases);
this.currentRow.cases = arr;
},
handleClose() {
this.visible = false;
}
}
}

View File

@ -3,17 +3,16 @@
<div class="card-container">
<!-- HTTP 请求参数 -->
<ms-edit-complete-http-api @runTest="runTest" @saveApi="saveApi" :request="request" :response="response"
:basisData="currentApi" :moduleOptions="moduleOptions" :currentProject="currentProject" v-if="currentProtocol === 'HTTP'"/>
:basisData="currentApi" :moduleOptions="moduleOptions" v-if="currentProtocol === 'HTTP'"/>
<!-- TCP -->
<ms-edit-complete-tcp-api :request="request" @runTest="runTest" @saveApi="saveApi" :currentProject="currentProject" :basisData="currentApi"
<ms-edit-complete-tcp-api :request="request" @runTest="runTest" @saveApi="saveApi" :basisData="currentApi"
:moduleOptions="moduleOptions" v-if="currentProtocol === 'TCP'"/>
<!--DUBBO-->
<ms-edit-complete-dubbo-api :request="request" @runTest="runTest" @saveApi="saveApi" :currentProject="currentProject" :basisData="currentApi"
<ms-edit-complete-dubbo-api :request="request" @runTest="runTest" @saveApi="saveApi" :basisData="currentApi"
:moduleOptions="moduleOptions" v-if="currentProtocol === 'DUBBO'"/>
<!--SQL-->
<ms-edit-complete-sql-api :request="request" @runTest="runTest" @saveApi="saveApi" :currentProject="currentProject" :basisData="currentApi"
<ms-edit-complete-sql-api :request="request" @runTest="runTest" @saveApi="saveApi" :basisData="currentApi"
:moduleOptions="moduleOptions" v-if="currentProtocol === 'SQL'"/>
</div>
</template>
@ -24,7 +23,7 @@
import MsEditCompleteSqlApi from "./complete/EditCompleteSQLApi";
import {ResponseFactory, Body} from "../model/ApiTestModel";
import {getUUID} from "@/common/js/utils";
import {getUUID, getCurrentProjectID} from "@/common/js/utils";
import {createComponent, Request} from "./jmeter/components";
import Sampler from "./jmeter/components/sampler/sampler";
import {WORKSPACE_ID} from '@/common/js/constants';
@ -38,16 +37,17 @@
request: Sampler,
config: {},
response: {},
projectId: "",
maintainerOptions: [],
}
},
props: {
currentApi: {},
moduleOptions: {},
currentProject: {},
currentProtocol: String,
},
created() {
this.projectId = getCurrentProjectID();
this.getMaintainerOptions();
switch (this.currentProtocol) {
case Request.TYPES.SQL:
@ -136,7 +136,7 @@
});
},
setParameters(data) {
data.projectId = this.currentProject.id;
data.projectId = this.projectId;
this.request.name = this.currentApi.name;
data.protocol = this.currentProtocol;
data.request = this.request;

View File

@ -1,8 +1,7 @@
<template>
<div id="svgBox" style="overflow: auto">
<div id="svgTop" style="background-color: white">
<el-card class="card-content">
<el-input placeholder="搜索" @blur="search" style="float: right ;width: 300px;margin-bottom: 20px;margin-right: 20px" size="small" v-model="condition.name"/>
<div>
<el-card class="card-content">
<el-input placeholder="搜索" @blur="search" class="search-input" size="small" v-model="condition.name"/>
<el-table border :data="tableData" row-key="id" class="test-content adjust-table"
@select-all="handleSelectAll"
@ -88,13 +87,8 @@
<ms-table-pagination :change="initApiTable" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/>
</el-card>
</div>
<div id="svgResize"/>
<div id="svgDown">
<ms-bottom-container v-bind:enableAsideHidden="isHide">
<ms-api-case-list @apiCaseClose="apiCaseClose" @refresh="initApiTable" :visible="visible" :currentRow="currentRow" :api="selectApi" :current-project="currentProject"/>
</ms-bottom-container>
</div>
<ms-api-case-list @refresh="initApiTable" :currentRow="currentRow"
:api="selectApi" ref="caseList"/>
</div>
</template>
@ -112,7 +106,8 @@
import MsContainer from "../../../common/components/MsContainer";
import MsBottomContainer from "./BottomContainer";
import ShowMoreBtn from "../../../../components/track/case/components/ShowMoreBtn";
import {API_METHOD_COLOUR, FILTER_MAP_1, FILTER_MAP_2} from "../model/JsonData";
import {API_METHOD_COLOUR} from "../model/JsonData";
import {getCurrentProjectID} from "@/common/js/utils";
export default {
name: "ApiList",
@ -131,7 +126,6 @@
data() {
return {
condition: {},
isHide: true,
selectApi: {},
moduleId: "",
deletePath: "/test/case/delete",
@ -142,11 +136,11 @@
currentPage: 1,
pageSize: 10,
total: 0,
projectId: "",
screenHeight: document.documentElement.clientHeight - 330,//
}
},
props: {
currentProject: Object,
currentProtocol: String,
currentModule: Object,
visible: {
@ -158,23 +152,15 @@
}
},
created: function () {
this.projectId = getCurrentProjectID();
this.initApiTable();
},
mounted() {
this.dragControllerDiv();
},
watch: {
currentProject() {
this.initApiTable();
this.apiCaseClose();
},
currentModule() {
this.initApiTable();
this.apiCaseClose();
},
currentProtocol() {
this.initApiTable();
this.apiCaseClose();
},
},
methods: {
@ -191,8 +177,8 @@
this.condition.moduleIds = this.currentModule.ids;
}
}
if (this.currentProject != null) {
this.condition.projectId = this.currentProject.id;
if (this.projectId != null) {
this.condition.projectId = this.projectId;
}
if (this.currentProtocol != null) {
this.condition.protocol = this.currentProtocol;
@ -298,17 +284,10 @@
}
},
handleTestCase(testCase) {
let h = window.screen.height;
let svgTop = document.getElementById("svgTop");
svgTop.style.height = h / 2 - 200 + "px";
let svgDown = document.getElementById("svgDown");
svgDown.style.height = h / 2 + "px";
this.selectApi = testCase;
let request = JSON.parse(testCase.request);
this.selectApi.url = request.path;
this.isHide = false;
this.$refs.caseList.open();
},
handleDelete(api) {
if (this.currentModule != undefined && this.currentModule.id == "gc") {
@ -331,48 +310,11 @@
}
});
},
apiCaseClose() {
let h = window.screen.height;
let svgTop = document.getElementById("svgTop");
svgTop.style.height = h - 200 + "px";
let svgDown = document.getElementById("svgDown");
svgDown.style.height = 0 + "px";
this.isHide = true;
},
getColor(enable, method) {
if (enable) {
return this.methodColorMap.get(method);
}
},
dragControllerDiv: function () {
let svgResize = document.getElementById("svgResize");
let svgTop = document.getElementById("svgTop");
let svgDown = document.getElementById("svgDown");
let svgBox = document.getElementById("svgBox");
svgResize.onmousedown = function (e) {
let startY = e.clientY;
svgResize.top = svgResize.offsetTop;
document.onmousemove = function (e) {
let endY = e.clientY;
let moveLen = svgResize.top + (endY - startY);
let maxT = svgBox.clientHeight - svgResize.offsetHeight;
if (moveLen < 30) moveLen = 30;
if (moveLen > maxT - 30) moveLen = maxT - 30;
svgResize.style.top = moveLen;
svgTop.style.height = moveLen + "px";
svgDown.style.height = (svgBox.clientHeight - moveLen - 5) + "px";
}
document.onmouseup = function (evt) {
document.onmousemove = null;
document.onmouseup = null;
svgResize.releaseCapture && svgResize.releaseCapture();
}
svgResize.setCapture && svgResize.setCapture();
return false;
}
},
}
}
</script>
@ -392,32 +334,11 @@
color: white;
}
#svgBox {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
.search-input {
float: right;
width: 300px;
/*margin-bottom: 20px;*/
margin-right: 20px;
}
#svgTop {
height: calc(30% - 5px);
width: 100%;
float: left;
overflow: auto;
}
#svgResize {
position: relative;
height: 5px;
width: 100%;
cursor: s-resize;
float: left;
}
#svgDown {
height: 70%;
width: 100%;
float: left;
overflow: hidden;
}
</style>

View File

@ -1,11 +1,5 @@
<template>
<div v-loading="result.loading">
<select-menu
:data="projects"
:current-data="currentProject"
:title="$t('test_track.project')"
@dataChange="changeProject" style="margin-bottom: 20px"/>
<el-select style="width: 100px ;height: 30px" size="small" v-model="protocol" @change="changeProtocol">
<el-option
v-for="item in options"
@ -95,7 +89,7 @@
</el-tree>
<ms-add-basis-api :current-protocol="protocol" ref="basisApi"></ms-add-basis-api>
<api-import ref="apiImport" :project-id="currentProject.id" @refresh="refresh"/>
<api-import ref="apiImport" :project-id="projectId" @refresh="refresh"/>
</div>
@ -106,6 +100,7 @@
import SelectMenu from "../../../track/common/SelectMenu";
import {OPTIONS, DEFAULT_DATA} from "../model/JsonData";
import ApiImport from "./import/ApiImport";
import {getCurrentProjectID} from "@/common/js/utils";
export default {
name: 'MsApiModule',
@ -123,43 +118,36 @@
expandedNode: [],
filterText: "",
nextFlag: true,
currentProject: {},
projects: [],
projectId: "",
data: DEFAULT_DATA,
currentModule: {},
newLabel: ""
}
},
mounted() {
this.getProjects();
this.projectId = getCurrentProjectID();
this.changeProtocol();
},
watch: {
currentProject() {
this.getApiModuleTree();
this.$emit('changeProject', this.currentProject);
},
filterText(val) {
this.$refs.tree.filter(val);
}
},
methods: {
getApiModuleTree() {
if (this.currentProject) {
if (this.expandedNode.length === 0) {
this.expandedNode.push("root");
}
this.result = this.$get("/api/module/list/" + this.currentProject.id + "/" + this.protocol, response => {
if (response.data != undefined && response.data != null) {
this.data[1].children = response.data;
let moduleOptions = [];
this.data[1].children.forEach(node => {
this.buildNodePath(node, {path: ''}, moduleOptions);
});
this.$emit('getApiModuleTree', moduleOptions);
}
});
if (this.expandedNode.length === 0) {
this.expandedNode.push("root");
}
this.result = this.$get("/api/module/list/" + this.projectId + "/" + this.protocol, response => {
if (response.data != undefined && response.data != null) {
this.data[1].children = response.data;
let moduleOptions = [];
this.data[1].children.forEach(node => {
this.buildNodePath(node, {path: ''}, moduleOptions);
});
this.$emit('getApiModuleTree', moduleOptions);
}
});
},
handleCommand(e) {
switch (e) {
@ -364,7 +352,7 @@
},
//
editApiModule(node, data) {
if (!this.currentProject) {
if (!this.projectId) {
this.$error("$t('api_test.select_project')");
return;
}
@ -383,7 +371,7 @@
data.nodeIds = ids;
}
data.protocol = this.protocol;
data.projectId = this.currentProject.id;
data.projectId = this.projectId;
this.$post(url, data, () => {
this.$success(this.$t('commons.save_success'));
this.getApiModuleTree();
@ -420,20 +408,7 @@
return data.name.indexOf(value) !== -1;
},
addApi() {
this.$refs.basisApi.open(this.currentModule, this.currentProject.id);
},
//
changeProject(project) {
this.currentProject = project;
},
getProjects() {
let projectId;
this.$get("/project/listAll", (response) => {
this.projects = response.data;
if (this.projects.length > 0) {
this.currentProject = this.projects[0];
}
});
this.$refs.basisApi.open(this.currentModule, this.projectId);
},
nodeExpand(data) {
if (data.id) {

View File

@ -6,40 +6,51 @@
<div class="el-step__icon-inner">{{assertions.index}}</div>
</div>
<el-button class="ms-left-buttion" size="small" style="color: #A30014;background-color: #F7E6E9">{{$t('api_test.definition.request.assertions_rule')}}</el-button>
<el-button size="small" style="float: right;margin-top: 0px" @click="remove">{{$t('commons.remove')}}</el-button>
</div>
<div class="assertion-add">
<el-row :gutter="10">
<el-col :span="4">
<el-select :disabled="isReadOnly" class="assertion-item" v-model="type"
:placeholder="$t('api_test.request.assertions.select_type')"
size="small">
<el-option :label="$t('api_test.request.assertions.regex')" :value="options.REGEX"/>
<el-option :label="'JSONPath'" :value="options.JSON_PATH"/>
<el-option :label="'XPath'" :value="options.XPATH2"/>
<el-option :label="$t('api_test.request.assertions.response_time')" :value="options.DURATION"/>
<el-option :label="$t('api_test.request.assertions.jsr223')" :value="options.JSR223"/>
</el-select>
</el-col>
<el-col :span="20">
<ms-api-assertion-regex :is-read-only="isReadOnly" :list="assertions.regex" v-if="type === options.REGEX"
:callback="after"/>
<ms-api-assertion-json-path :is-read-only="isReadOnly" :list="assertions.jsonPath"
v-if="type === options.JSON_PATH" :callback="after"/>
<ms-api-assertion-x-path2 :is-read-only="isReadOnly" :list="assertions.xpath2" v-if="type === options.XPATH2"
:callback="after"/>
<ms-api-assertion-duration :is-read-only="isReadOnly" v-model="time" :duration="assertions.duration"
v-if="type === options.DURATION" :callback="after"/>
<ms-api-assertion-jsr223 :is-read-only="isReadOnly" :list="assertions.jsr223" v-if="type === options.JSR223"
:callback="after"/>
<el-button v-if="!type" :disabled="true" type="primary" size="small">
{{ $t('api_test.request.assertions.add') }}
</el-button>
</el-col>
</el-row>
</div>
<ms-api-assertions-edit :is-read-only="isReadOnly" :assertions="assertions" :reloadData="reloadData" style="margin-bottom: 20px"/>
<el-input size="small" v-model="assertions.name" style="width: 40%;margin-left: 20px" :placeholder="$t('commons.input_name')"/>
<div style="margin-right: 20px; float: right">
<i class="icon el-icon-arrow-right" :class="{'is-active': assertions.active}" @click="active(assertions)" style="margin-left: 20px"/>
<el-switch v-model="assertions.enable" style="margin-left: 10px"/>
<el-button size="mini" icon="el-icon-delete" circle @click="remove" style="margin-left: 10px;"/>
</div>
</div>
<!-- 请求参数-->
<el-collapse-transition>
<div v-if="assertions.active">
<div class="assertion-add">
<el-row :gutter="10">
<el-col :span="4">
<el-select :disabled="isReadOnly" class="assertion-item" v-model="type"
:placeholder="$t('api_test.request.assertions.select_type')"
size="small">
<el-option :label="$t('api_test.request.assertions.regex')" :value="options.REGEX"/>
<el-option :label="'JSONPath'" :value="options.JSON_PATH"/>
<el-option :label="'XPath'" :value="options.XPATH2"/>
<el-option :label="$t('api_test.request.assertions.response_time')" :value="options.DURATION"/>
<el-option :label="$t('api_test.request.assertions.jsr223')" :value="options.JSR223"/>
</el-select>
</el-col>
<el-col :span="20">
<ms-api-assertion-regex :is-read-only="isReadOnly" :list="assertions.regex" v-if="type === options.REGEX"
:callback="after"/>
<ms-api-assertion-json-path :is-read-only="isReadOnly" :list="assertions.jsonPath"
v-if="type === options.JSON_PATH" :callback="after"/>
<ms-api-assertion-x-path2 :is-read-only="isReadOnly" :list="assertions.xpath2" v-if="type === options.XPATH2"
:callback="after"/>
<ms-api-assertion-duration :is-read-only="isReadOnly" v-model="time" :duration="assertions.duration"
v-if="type === options.DURATION" :callback="after"/>
<ms-api-assertion-jsr223 :is-read-only="isReadOnly" :list="assertions.jsr223" v-if="type === options.JSR223"
:callback="after"/>
<el-button v-if="!type" :disabled="true" type="primary" size="small">
{{ $t('api_test.request.assertions.add') }}
</el-button>
</el-col>
</el-row>
</div>
<ms-api-assertions-edit :is-read-only="isReadOnly" :assertions="assertions" :reloadData="reloadData" style="margin-bottom: 20px"/>
</div>
</el-collapse-transition>
</el-card>
</div>
</template>
@ -72,7 +83,7 @@
node: {},
request: {},
customizeStyle: {
type:String,
type: String,
default: "margin-top: 10px"
},
scenario: Scenario,
@ -111,8 +122,12 @@
this.loading = false
})
},
active(item) {
item.active = !item.active;
this.reload();
},
remove() {
this.$emit('remove', this.assertions,this.node);
this.$emit('remove', this.assertions, this.node);
},
addJsonpathSuggest(jsonPathList) {
jsonPathList.forEach(jsonPath => {
@ -142,31 +157,11 @@
border-radius: 5px;
}
.bg-purple-dark {
background: #99a9bf;
.icon.is-active {
transform: rotate(90deg);
}
.bg-purple {
background: #d3dce6;
/deep/ .el-card__body {
padding: 15px;
}
.bg-purple-light {
background: #e5e9f2;
}
.grid-content {
border-radius: 4px;
min-height: 36px;
}
.row-bg {
padding: 10px 0;
background-color: #f9fafc;
}
.json-path-suggest-button {
margin-top: 20px;
margin-left: 20px;
}
</style>

View File

@ -80,7 +80,6 @@
basicForm: {},
httpVisible: false,
currentModule: {},
projectId: "",
maintainerOptions: [],
rule: {
name: [

View File

@ -22,10 +22,9 @@
<!-- 请求参数 -->
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-basis-parameters :request="request" :currentProject="currentProject"/>
<ms-basis-parameters :request="request"/>
</div>
</template>
<script>
@ -40,7 +39,6 @@
props: {
request: {},
basisData: {},
currentProject: {},
moduleOptions: Array,
isReadOnly: {
type: Boolean,
@ -57,10 +55,6 @@
validateApi() {
this.validated = false;
this.basisData.method = this.request.protocol;
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['basicForm'].validate();
},
saveApi() {

View File

@ -103,13 +103,9 @@
options: API_STATUS,
}
},
props: {moduleOptions: {}, currentProject: {}, request: {}, response: {}, basisData: {}},
props: {moduleOptions: {}, request: {}, response: {}, basisData: {}},
methods: {
runTest() {
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs['httpForm'].validate((valid) => {
if (valid) {
this.setParameter();
@ -132,10 +128,6 @@
this.httpForm.request.useEnvironment = undefined;
},
saveApi() {
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['httpForm'].validate((valid) => {
if (valid) {
this.setParameter();

View File

@ -21,7 +21,7 @@
<!-- 请求参数 -->
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-basis-parameters :request="request" :currentProject="currentProject"/>
<ms-basis-parameters :request="request"/>
</div>
</template>
@ -38,7 +38,6 @@
props: {
request: {},
basisData: {},
currentProject: {},
moduleOptions: Array,
isReadOnly: {
type: Boolean,
@ -55,10 +54,6 @@
},
validateApi() {
this.validated = false;
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['basicForm'].validate();
},
saveApi() {

View File

@ -21,7 +21,7 @@
<!-- 请求参数 -->
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-basis-parameters :request="request" :currentProject="currentProject"/>
<ms-basis-parameters :request="request"/>
</div>
@ -37,7 +37,6 @@
props: {
request: {},
basisData: {},
currentProject: {},
moduleOptions: Array,
isReadOnly: {
type: Boolean,
@ -57,10 +56,6 @@
validateApi() {
this.validated = false;
this.basisData.method = "TCP";
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['basicForm'].validate();
},
saveApi() {

View File

@ -1,35 +1,44 @@
<template>
<div :style="customizeStyle">
<div :style="customizeStyle" v-loading="loading">
<el-card>
<div class="el-step__icon is-text" style="color: #015478;background-color: #E6EEF2;margin-right: 10px" v-if="extract.index">
<div class="el-step__icon-inner">{{extract.index}}</div>
</div>
<el-button class="ms-left-buttion" size="small" style="color: #015478;background-color: #E6EEF2">{{$t('api_test.definition.request.extract_param')}}</el-button>
<el-button size="small" style="float: right;margin-top: 0px" @click="remove">移除</el-button>
<div style="margin: 20px">
<div class="extract-description">
{{$t('api_test.request.extract.description')}}
</div>
<div class="extract-add">
<el-row :gutter="10">
<el-col :span="2">
<el-select :disabled="isReadOnly" class="extract-item" v-model="type" :placeholder="$t('api_test.request.extract.select_type')"
size="small">
<el-option :label="$t('api_test.request.extract.regex')" :value="options.REGEX"/>
<el-option label="JSONPath" :value="options.JSON_PATH"/>
<el-option label="XPath" :value="options.XPATH"/>
</el-select>
</el-col>
<el-col :span="22">
<ms-api-extract-common :is-read-only="isReadOnly" :extract-type="type" :list="list" v-if="type" :callback="after"/>
</el-col>
<el-button v-if="!type" :disabled="true" type="primary" size="small">Add</el-button>
</el-row>
</div>
<ms-api-extract-edit :is-read-only="isReadOnly" :reloadData="reloadData" :extract="extract"/>
<el-input size="small" v-model="extract.name" style="width: 40%;margin-left: 20px" :placeholder="$t('commons.input_name')"/>
<div style="margin-right: 20px; float: right">
<i class="icon el-icon-arrow-right" :class="{'is-active': extract.active}" @click="active(extract)" style="margin-left: 20px"/>
<el-switch v-model="extract.enable" style="margin-left: 10px"/>
<el-button size="mini" icon="el-icon-delete" circle @click="remove" style="margin-left: 10px;"/>
</div>
<!-- 请求参数-->
<el-collapse-transition>
<div v-if="extract.active">
<div style="margin: 20px">
<div class="extract-description">
{{$t('api_test.request.extract.description')}}
</div>
<div class="extract-add">
<el-row :gutter="10">
<el-col :span="2">
<el-select :disabled="isReadOnly" class="extract-item" v-model="type" :placeholder="$t('api_test.request.extract.select_type')"
size="small">
<el-option :label="$t('api_test.request.extract.regex')" :value="options.REGEX"/>
<el-option label="JSONPath" :value="options.JSON_PATH"/>
<el-option label="XPath" :value="options.XPATH"/>
</el-select>
</el-col>
<el-col :span="22">
<ms-api-extract-common :is-read-only="isReadOnly" :extract-type="type" :list="list" v-if="type" :callback="after"/>
</el-col>
<el-button v-if="!type" :disabled="true" type="primary" size="small">Add</el-button>
</el-row>
</div>
<ms-api-extract-edit :is-read-only="isReadOnly" :reloadData="reloadData" :extract="extract"/>
</div>
</div>
</el-collapse-transition>
</el-card>
</div>
</template>
@ -66,6 +75,7 @@
options: EXTRACT_TYPE,
type: "",
reloadData: "",
loading: false,
}
},
@ -77,9 +87,17 @@
remove() {
this.$emit('remove', this.extract, this.node);
},
reload() {
this.loading = true
this.$nextTick(() => {
this.loading = false
})
},
active(item) {
item.active = !item.active;
this.reload();
},
},
computed: {
list() {
switch (this.type) {
@ -113,4 +131,12 @@
margin: 5px 0;
border-radius: 5px;
}
.icon.is-active {
transform: rotate(90deg);
}
/deep/ .el-card__body {
padding: 15px;
}
</style>

View File

@ -1,42 +1,48 @@
<template>
<div style="border:1px #DCDFE6 solid; height: 100%;border-radius: 4px ;width: 100% ;margin-top: 20px">
<el-row>
<div>
<el-button class="ms-left-buttion" size="small" :style="styleType" style="color: #B8741A;background-color: #F9F1EA">{{title}}</el-button>
<i class="icon el-icon-arrow-right" :class="{'is-active': active}" @click="changeActive" style="margin-left: 20px"/>
<el-input size="small" v-model="jsr223ProcessorData.name" class="ms-api-header-select" style="width: 380px"/>
<el-button size="small" style="float: right" @click="remove">移除</el-button>
</div>
</el-row>
<el-collapse-transition>
<div v-if="active">
<el-row style="margin:0px 10px 10px">
<el-col>
<div class="document-url">
<el-link href="https://jmeter.apache.org/usermanual/component_reference.html#BeanShell_PostProcessor"
type="primary">{{$t('commons.reference_documentation')}}
</el-link>
<ms-instructions-icon :content="$t('api_test.request.processor.bean_shell_processor_tip')"/>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="20" class="script-content">
<ms-code-edit v-if="isCodeEditAlive" :mode="jsr223ProcessorData.scriptLanguage"
:read-only="isReadOnly"
:data.sync="jsr223ProcessorData.script" theme="eclipse" :modes="['java','python']"
ref="codeEdit"/>
</el-col>
<el-col :span="4" class="script-index">
<ms-dropdown :default-command="jsr223ProcessorData.language" :commands="languages" @command="languageChange"/>
<div class="template-title">{{$t('api_test.request.processor.code_template')}}</div>
<div v-for="(template, index) in codeTemplates" :key="index" class="code-template">
<el-link :disabled="template.disabled" @click="addTemplate(template)">{{template.title}}</el-link>
</div>
</el-col>
</el-row>
</div>
</el-collapse-transition>
<div style="margin-top: 10px">
<el-card>
<el-row>
<div>
<el-button class="ms-left-buttion" size="small" :style="styleType" style="color: #B8741A;background-color: #F9F1EA">{{title}}</el-button>
<el-input size="small" v-model="jsr223ProcessorData.name" class="ms-api-header-select" style="width: 380px"/>
<div style="margin-right: 20px; float: right">
<i class="icon el-icon-arrow-right" :class="{'is-active': active}" @click="changeActive"/>
<el-switch v-model="jsr223ProcessorData.enable" style="margin-left: 10px"/>
<el-button size="mini" icon="el-icon-delete" circle @click="remove" style="margin-left: 10px;"/>
</div>
</div>
</el-row>
<el-collapse-transition>
<div v-if="active">
<el-row style="margin:0px 10px 10px">
<el-col>
<div class="document-url">
<el-link href="https://jmeter.apache.org/usermanual/component_reference.html#BeanShell_PostProcessor"
type="primary">{{$t('commons.reference_documentation')}}
</el-link>
<ms-instructions-icon :content="$t('api_test.request.processor.bean_shell_processor_tip')"/>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="20" class="script-content">
<ms-code-edit v-if="isCodeEditAlive" :mode="jsr223ProcessorData.scriptLanguage"
:read-only="isReadOnly"
:data.sync="jsr223ProcessorData.script" theme="eclipse" :modes="['java','python']"
ref="codeEdit"/>
</el-col>
<el-col :span="4" class="script-index">
<ms-dropdown :default-command="jsr223ProcessorData.language" :commands="languages" @command="languageChange"/>
<div class="template-title">{{$t('api_test.request.processor.code_template')}}</div>
<div v-for="(template, index) in codeTemplates" :key="index" class="code-template">
<el-link :disabled="template.disabled" @click="addTemplate(template)">{{template.title}}</el-link>
</div>
</el-col>
</el-row>
</div>
</el-collapse-transition>
</el-card>
</div>
</template>
@ -138,7 +144,7 @@
}
this.reload();
},
remove(){
remove() {
this.$emit('remove', this.jsr223ProcessorData);
},
reload() {
@ -195,4 +201,8 @@
.icon.is-active {
transform: rotate(90deg);
}
/deep/ .el-card__body {
padding: 15px;
}
</style>

View File

@ -106,6 +106,7 @@
import {Assertions, Extract} from "../../../model/ApiTestModel";
import {parseEnvironment} from "../../../model/EnvironmentModel";
import ApiEnvironmentConfig from "../../environment/ApiEnvironmentConfig";
import {getCurrentProjectID} from "@/common/js/utils";
export default {
name: "MsDatabaseConfig",
@ -171,10 +172,6 @@
})
},
validate() {
if (this.currentProject === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['request'].validate((valid) => {
if (valid) {
this.$emit('callback');
@ -190,23 +187,17 @@
},
getEnvironments() {
if (this.currentProject) {
this.environments = [];
this.$get('/api/environment/list/' + this.currentProject.id, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
this.initDataSource();
this.environments = [];
this.$get('/api/environment/list/' + getCurrentProjectID(), response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
}
this.initDataSource();
});
},
openEnvironmentConfig() {
if (!this.currentProject) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.environmentConfig.open(this.currentProject.id);
this.$refs.environmentConfig.open(getCurrentProjectID());
},
initDataSource() {
for (let i in this.environments) {

View File

@ -19,7 +19,7 @@
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<!-- TCP 请求参数 -->
<ms-basis-parameters :request="api.request" :currentProject="currentProject" ref="requestForm"/>
<ms-basis-parameters :request="api.request" ref="requestForm"/>
<!--返回结果-->
<!-- HTTP 请求返回数据 -->
@ -31,7 +31,7 @@
<!-- 加载用例 -->
<el-drawer :visible.sync="visible" direction="btt" :with-header="false" :modal="false" size="50%">
<ms-api-case-list @apiCaseClose="apiCaseClose" @selectTestCase="selectTestCase" :api="api"
:currentProject="currentProject" :loaded="loaded" :refreshSign="refreshSign" :createCase="createCase"
:loaded="loaded" :refreshSign="refreshSign" :createCase="createCase"
ref="caseList"/>
</el-drawer>
>
@ -47,7 +47,7 @@
<script>
import MsApiRequestForm from "../request/http/ApiRequestForm";
import {downloadFile, getUUID} from "@/common/js/utils";
import {downloadFile, getUUID, getCurrentProjectID} from "@/common/js/utils";
import MsApiCaseList from "../ApiCaseList";
import MsContainer from "../../../../common/components/MsContainer";
import MsBottomContainer from "../BottomContainer";
@ -56,7 +56,6 @@
import MsRequestResultTail from "../response/RequestResultTail";
import MsRun from "../Run";
import MsBasisParameters from "../request/dubbo/BasisParameters";
import {REQ_METHOD} from "../../model/JsonData";
export default {
@ -92,7 +91,7 @@
reportId: "",
}
},
props: {apiData: {}, currentProject: {}, currentProtocol: String,},
props: {apiData: {}, currentProtocol: String,},
methods: {
handleCommand(e) {
switch (e) {
@ -184,36 +183,27 @@
}
},
getEnvironments() {
if (this.currentProject) {
this.$get('/api/environment/list/' + this.currentProject.id, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
let hasEnvironment = false;
for (let i in this.environments) {
if (this.environments[i].id === this.api.environmentId) {
this.api.environment = this.environments[i];
hasEnvironment = true;
break;
}
}
if (!hasEnvironment) {
this.api.environmentId = '';
this.api.environment = undefined;
}
this.$get('/api/environment/list/' + getCurrentProjectID(), response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
} else {
this.api.environmentId = '';
this.api.environment = undefined;
}
let hasEnvironment = false;
for (let i in this.environments) {
if (this.environments[i].id === this.api.environmentId) {
this.api.environment = this.environments[i];
hasEnvironment = true;
break;
}
}
if (!hasEnvironment) {
this.api.environmentId = '';
this.api.environment = undefined;
}
});
},
openEnvironmentConfig() {
if (!this.currentProject) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.environmentConfig.open(this.currentProject.id);
this.$refs.environmentConfig.open(getCurrentProjectID());
},
environmentChange(value) {
for (let i in this.environments) {

View File

@ -72,7 +72,7 @@
<!-- 加载用例 -->
<el-drawer :visible.sync="visible" direction="btt" :with-header="false" :modal="false" size="50%" ref="drawer">
<ms-api-case-list @apiCaseClose="apiCaseClose" @selectTestCase="selectTestCase" :api="api" :refreshSign="refreshSign"
:currentProject="currentProject" :loaded="loaded" :createCase="createCase"
:loaded="loaded" :createCase="createCase"
ref="caseList"/>
</el-drawer>
@ -87,14 +87,13 @@
<script>
import MsApiRequestForm from "../request/http/ApiRequestForm";
import {downloadFile, getUUID} from "@/common/js/utils";
import {downloadFile, getUUID, getCurrentProjectID} from "@/common/js/utils";
import MsApiCaseList from "../ApiCaseList";
import MsContainer from "../../../../common/components/MsContainer";
import {parseEnvironment} from "../../model/EnvironmentModel";
import ApiEnvironmentConfig from "../environment/ApiEnvironmentConfig";
import MsRequestResultTail from "../response/RequestResultTail";
import MsRun from "../Run";
import {REQ_METHOD} from "../../model/JsonData";
export default {
@ -126,9 +125,10 @@
},
runData: [],
reportId: "",
projectId: "",
}
},
props: {apiData: {}, currentProject: {}, currentProtocol: String,},
props: {apiData: {}, currentProtocol: String,},
methods: {
handleCommand(e) {
switch (e) {
@ -226,8 +226,8 @@
}
},
getEnvironments() {
if (this.currentProject) {
this.$get('/api/environment/list/' + this.currentProject.id, response => {
if (this.projectId) {
this.$get('/api/environment/list/' + this.projectId, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
@ -251,11 +251,11 @@
}
},
openEnvironmentConfig() {
if (!this.currentProject) {
if (!this.projectId) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.environmentConfig.open(this.currentProject.id);
this.$refs.environmentConfig.open(this.projectId);
},
environmentChange(value) {
for (let i in this.environments) {
@ -279,6 +279,7 @@
}
},
created() {
this.projectId = getCurrentProjectID();
this.api = this.apiData;
this.api.protocol = this.currentProtocol;
this.currentRequest = this.api.request;

View File

@ -18,7 +18,7 @@
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<!-- TCP 请求参数 -->
<ms-basis-parameters :request="api.request" @callback="runTest" :currentProject="currentProject" ref="requestForm"/>
<ms-basis-parameters :request="api.request" @callback="runTest" ref="requestForm"/>
<!--返回结果-->
<!-- HTTP 请求返回数据 -->
@ -30,7 +30,7 @@
<!-- 加载用例 -->
<el-drawer :visible.sync="visible" direction="btt" :with-header="false" :modal="false" size="50%">
<ms-api-case-list @apiCaseClose="apiCaseClose" @selectTestCase="selectTestCase" :api="api" :refreshSign="refreshSign"
:currentProject="currentProject" :loaded="loaded" :createCase="createCase"
:loaded="loaded" :createCase="createCase"
ref="caseList"/>
</el-drawer>
>
@ -46,7 +46,7 @@
<script>
import MsApiRequestForm from "../request/http/ApiRequestForm";
import {downloadFile, getUUID} from "@/common/js/utils";
import {downloadFile, getUUID, getCurrentProjectID} from "@/common/js/utils";
import MsApiCaseList from "../ApiCaseList";
import MsContainer from "../../../../common/components/MsContainer";
import MsBottomContainer from "../BottomContainer";
@ -55,7 +55,6 @@
import MsRequestResultTail from "../response/RequestResultTail";
import MsRun from "../Run";
import MsBasisParameters from "../request/database/BasisParameters";
import {REQ_METHOD} from "../../model/JsonData";
export default {
@ -91,7 +90,7 @@
reportId: "",
}
},
props: {apiData: {}, currentProject: {}, currentProtocol: String,},
props: {apiData: {}, currentProtocol: String,},
methods: {
handleCommand(e) {
switch (e) {
@ -182,36 +181,27 @@
}
},
getEnvironments() {
if (this.currentProject) {
this.$get('/api/environment/list/' + this.currentProject.id, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
let hasEnvironment = false;
for (let i in this.environments) {
if (this.environments[i].id === this.api.environmentId) {
this.api.environment = this.environments[i];
hasEnvironment = true;
break;
}
}
if (!hasEnvironment) {
this.api.environmentId = '';
this.api.environment = undefined;
}
this.$get('/api/environment/list/' + getCurrentProjectID(), response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
} else {
this.api.environmentId = '';
this.api.environment = undefined;
}
let hasEnvironment = false;
for (let i in this.environments) {
if (this.environments[i].id === this.api.environmentId) {
this.api.environment = this.environments[i];
hasEnvironment = true;
break;
}
}
if (!hasEnvironment) {
this.api.environmentId = '';
this.api.environment = undefined;
}
});
},
openEnvironmentConfig() {
if (!this.currentProject) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.environmentConfig.open(this.currentProject.id);
this.$refs.environmentConfig.open(getCurrentProjectID());
},
environmentChange(value) {
for (let i in this.environments) {

View File

@ -19,7 +19,7 @@
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<!-- TCP 请求参数 -->
<ms-basis-parameters :request="api.request" @callback="runTest" :currentProject="currentProject" ref="requestForm"/>
<ms-basis-parameters :request="api.request" @callback="runTest" ref="requestForm"/>
<!--返回结果-->
<!-- HTTP 请求返回数据 -->
@ -31,7 +31,7 @@
<!-- 加载用例 -->
<el-drawer :visible.sync="visible" direction="btt" :with-header="false" :modal="false" size="50%">
<ms-api-case-list @apiCaseClose="apiCaseClose" @selectTestCase="selectTestCase" :api="api" :refreshSign="refreshSign"
:currentProject="currentProject" :loaded="loaded" :createCase="createCase"
:loaded="loaded" :createCase="createCase"
ref="caseList"/>
</el-drawer>
<!-- 环境 -->
@ -45,7 +45,7 @@
<script>
import MsApiRequestForm from "../request/http/ApiRequestForm";
import {downloadFile, getUUID} from "@/common/js/utils";
import {downloadFile, getUUID, getCurrentProjectID} from "@/common/js/utils";
import MsApiCaseList from "../ApiCaseList";
import MsContainer from "../../../../common/components/MsContainer";
import MsBottomContainer from "../BottomContainer";
@ -54,7 +54,6 @@
import MsRequestResultTail from "../response/RequestResultTail";
import MsRun from "../Run";
import MsBasisParameters from "../request/tcp/BasisParameters";
import {REQ_METHOD} from "../../model/JsonData";
export default {
@ -90,7 +89,7 @@
reportId: "",
}
},
props: {apiData: {}, currentProject: {}, currentProtocol: String,},
props: {apiData: {}, currentProtocol: String,},
methods: {
handleCommand(e) {
switch (e) {
@ -181,36 +180,27 @@
}
},
getEnvironments() {
if (this.currentProject) {
this.$get('/api/environment/list/' + this.currentProject.id, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
let hasEnvironment = false;
for (let i in this.environments) {
if (this.environments[i].id === this.api.environmentId) {
this.api.environment = this.environments[i];
hasEnvironment = true;
break;
}
}
if (!hasEnvironment) {
this.api.environmentId = '';
this.api.environment = undefined;
}
this.$get('/api/environment/list/' + getCurrentProjectID(), response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
} else {
this.api.environmentId = '';
this.api.environment = undefined;
}
let hasEnvironment = false;
for (let i in this.environments) {
if (this.environments[i].id === this.api.environmentId) {
this.api.environment = this.environments[i];
hasEnvironment = true;
break;
}
}
if (!hasEnvironment) {
this.api.environmentId = '';
this.api.environment = undefined;
}
});
},
openEnvironmentConfig() {
if (!this.currentProject) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.environmentConfig.open(this.currentProject.id);
this.$refs.environmentConfig.open(getCurrentProjectID());
},
environmentChange(value) {
for (let i in this.environments) {

View File

@ -776,7 +776,7 @@ export class Assertions extends BaseConfig {
this.jsr223 = [];
this.xpath2 = [];
this.duration = undefined;
this.enable = true;
this.set(options);
this.sets({text: Text, regex: Regex, jsonPath: JSONPath, jsr223: AssertionJSR223, xpath2: XPath2}, options);
}
@ -843,6 +843,7 @@ export class JSR223Processor extends BaseConfig {
this.type = "JSR223Processor";
this.script = undefined;
this.language = "beanshell";
this.enable = true;
this.set(options);
}
}
@ -917,7 +918,7 @@ export class Extract extends BaseConfig {
this.regex = [];
this.json = [];
this.xpath = [];
this.enable = true;
this.set(options);
let types = {
json: ExtractJSONPath,

View File

@ -52,7 +52,7 @@
</el-submenu>
<el-menu-item v-show="$store.state.switch.value=='new'"
<el-menu-item v-show="$store.state.switch.value=='old'"
v-permission="['test_manager','test_user','test_viewer']" :index="'/api/monitor/view'">
{{ $t('commons.monitor') }}
</el-menu-item>
@ -116,7 +116,6 @@ export default {
apiTestProjectPath: '',
}
},
watch: {
'$route'(to) {
this.init();

View File

@ -0,0 +1,90 @@
<template>
<div direction="vertical" :class="direction" @mousedown="mouseDown"></div>
</template>
<script>
export default {
name: "MsDragMoveBar",
data() {
return {
lastX: '',
lastY: '',
};
},
props: {
direction: {
type: String,
default() {
return 'vertical';
}
}
},
created() {
document.addEventListener("mouseup", this.mouseUp);
},
destroyed() {
document.removeEventListener("mouseup", this.mouseUp);
},
methods: {
mouseDown(event) {
document.addEventListener("mousemove", this.mouseMove);
this.lastX = event.screenX;
this.lastY = event.screenY;
},
mouseMove(event) {
this.$emit("widthChange", this.lastX - event.screenX);
this.$emit("heightChange", this.lastY - event.screenY);
this.lastX = event.screenX;
this.lastY = event.screenY;
},
mouseUp() {
this.lastX = "";
this.lastY = "";
document.removeEventListener("mousemove", this.mouseMove);
}
}
};
</script>
<style >
.drag-bar {
width: 100%;
height: 2px;
cursor: row-resize;
z-index: 10;
background: #ccc;
}
.horizontal {
width: 2px;
height: 100%;
cursor: col-resize;
z-index: 10;
}
.vertical {
width: 100%;
height: 2px;
cursor: row-resize;
z-index: 10;
}
.vertical:hover {
height: 3px;
background-color: #ccc;
/*-webkit-box-shadow: 0 8px 10px -5px rgba(0,0,0,.2), 0 16px 24px 2px rgba(0,0,0,.14), 0 6px 30px 5px rgba(0,0,0,.12);*/
/*box-shadow: 0 8px 10px -5px rgba(0,0,0,.2), 0 16px 24px 2px rgba(0,0,0,.14), 0 6px 30px 5px rgba(0,0,0,.12);*/
}
.horizontal:hover {
width: 3px;
/*background-color: #7C3985;*/
background-color: #ccc;
}
</style>

View File

@ -0,0 +1,180 @@
<template>
<div id="ms-drawer" class="ms-drawer" :class="directionStyle" :style="{width: w + 'px', height: h + 'px'}" ref="msDrawer">
<ms-drag-move-bar :direction="dragBarDirection" @widthChange="widthChange" @heightChange="heightChange"/>
<div class="ms-drawer-header" >
<slot name="header"></slot>
</div>
<div class="ms-drawer-body">
<slot></slot>
</div>
</div>
</template>
<script>
import MsDragMoveBar from "./MsDragMoveBar";
export default {
name: "MsDrawer",
components: {MsDragMoveBar},
data() {
return {
x: 0,
y: 0,
w: 100,
h: 100,
directionStyle: 'left-style',
dragBarDirection: 'vertical',
}
},
props: {
direction: {
type: String,
default() {
return "left";
}
},
size: {
type: Number,
default() {
return 40;
}
}
},
mounted() {
this.init();
},
methods: {
init() {
// todo
switch (this.direction) {
case 'left':
this.w = this.getWidthPercentage(this.size);
this.h = this.getHeightPercentage(100);
this.x = 0;
this.y = 0;
this.directionStyle = 'left-style';
this.dragBarDirection = 'horizontal';
break;
case 'right':
this.w = this.getWidthPercentage(this.size);
this.h = this.getHeightPercentage(100);
this.x = document.body.clientWidth - this.w;
this.y = 0;
this.directionStyle = 'right-style';
this.dragBarDirection = 'horizontal';
break;
case 'top':
this.w = this.getWidthPercentage(100);
this.h = this.getHeightPercentage(this.size);
this.x = 0;
this.y = 0;
this.directionStyle = 'top-style';
this.dragBarDirection = 'vertical';
break;
case 'bottom':
this.w = this.getWidthPercentage(100);
this.h = this.getHeightPercentage(this.size);
this.x = 0;
this.y = document.body.clientHeight - this.h;
this.directionStyle = 'bottom-style';
this.dragBarDirection = 'vertical';
break;
}
},
resize() {
},
getWidthPercentage(per) {
return document.body.clientWidth * per / 100.0;
},
getHeightPercentage(per) {
return document.body.clientHeight * per / 100.0;
},
widthChange(movement) {
if (this.direction != 'left' && this.direction != 'right') {
return;
}
switch (this.direction) {
case 'top':
this.w -= movement;
break;
case 'bottom':
this.w += movement;
break;
}
this._widthChange();
},
heightChange(movement) {
if (this.direction != 'top' && this.direction != 'bottom') {
return;
}
switch (this.direction) {
case 'top':
this.h -= movement;
break;
case 'bottom':
this.h += movement;
break;
}
this._heightChange();
},
_heightChange() {
if (this.h < 0) {
this.h = 0;
}
if (this.h > document.body.clientHeight) {
this.h = document.body.clientHeight;
}
},
_widthChange() {
if (this.w < 0) {
this.w = 0;
}
if (this.w > document.body.clientWidth) {
this.w = document.body.clientWidth;
}
}
}
}
</script>
<style scoped>
.ms-drawer {
background-color: white;
border: 1px #DCDFE6 solid;
-webkit-box-shadow: 0 8px 10px -5px rgba(0,0,0,.2), 0 16px 24px 2px rgba(0,0,0,.14), 0 6px 30px 5px rgba(0,0,0,.12);
box-shadow: 0 8px 10px -5px rgba(0,0,0,.2), 0 16px 24px 2px rgba(0,0,0,.14), 0 6px 30px 5px rgba(0,0,0,.12);
z-index: 999 !important;
position: fixed;
overflow: auto;
}
.left-style {
top: 0;
left: 0;
}
.right-style {
top: 0;
right: 0;
}
.top-style {
top: 0;
left: 0;
}
.bottom-style {
bottom: 0;
left: 0;
border-top: 5px;
}
.ms-drawer-body {
overflow: scroll;
}
.ms-drawer-header {
position: relative;
}
</style>

View File

@ -8,10 +8,10 @@
<el-dropdown-item command="personal">{{ $t('commons.personal_information') }}</el-dropdown-item>
<el-dropdown-item command="about">{{ $t('commons.about_us') }} <i class="el-icon-info"/></el-dropdown-item>
<el-dropdown-item command="help">{{ $t('commons.help_documentation') }}</el-dropdown-item>
<el-dropdown-item command="old" :disabled=!isReadOnly @click.native="changeBar('old')">
<el-dropdown-item command="old" :disabled=isReadOnly @click.native="changeBar('old')">
{{ $t('commons.cut_back_old_version') }}
</el-dropdown-item>
<el-dropdown-item command="new" :disabled=isReadOnly @click.native="changeBar('new')">
<el-dropdown-item command="new" :disabled=!isReadOnly @click.native="changeBar('new')">
{{ $t('commons.cut_back_new_version') }}
</el-dropdown-item>
<el-dropdown-item command="logout">{{ $t('commons.exit_system') }}</el-dropdown-item>
@ -32,7 +32,7 @@
components: {AboutUs},
data() {
return {
isReadOnly: true
isReadOnly: this.$store.state.isReadOnly.flag
}
},
computed: {
@ -75,6 +75,7 @@
},
changeBar(item) {
this.isReadOnly = !this.isReadOnly
this.$store.commit('setFlag', this.isReadOnly);
this.$store.commit('setValue', item);
}
}

View File

@ -15,7 +15,7 @@
#body {
width: 100%;
height: calc(100vh - 40px);
background-color: #F5F5F5;
/*background-color: #F5F5F5;*/
}
.sidebar {

View File

@ -2,11 +2,6 @@
<ms-container>
<ms-aside-container>
<select-menu
:data="projects"
:current-data="currentProject"
:title="$t('test_track.project')"
@dataChange="changeProject"/>
<node-tree
class="node-tree"
v-loading="result.loading"
@ -17,13 +12,13 @@
:draggable="nodeTreeDraggable"
:select-node.sync="selectNode"
@refreshTable="refreshTable"
:current-project="currentProject"
:current-project="{id:currentProject}"
ref="nodeTree"/>
</ms-aside-container>
<ms-main-container>
<test-case-list
:current-project="currentProject"
:current-project="{id:currentProject}"
:select-node-ids="selectNodeIds"
:select-parent-nodes="selectParentNodes"
@testCaseEdit="editTestCase"
@ -41,7 +36,7 @@
:read-only="testCaseReadOnly"
:tree-nodes="treeNodes"
:select-node="selectNode"
:current-project="currentProject"
:current-project="{id:currentProject}"
ref="testCaseEditDialog">
</test-case-edit>
@ -57,7 +52,7 @@
import NodeTree from '../common/NodeTree';
import TestCaseEdit from './components/TestCaseEdit';
import {CURRENT_PROJECT, ROLE_TEST_MANAGER, ROLE_TEST_USER} from '../../../../common/js/constants';
import {PROJECT_ID, 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";
@ -90,11 +85,15 @@ export default {
nodeTreeDraggable: true,
}
},
activated() {
this.currentProject = localStorage.getItem(PROJECT_ID);
},
mounted() {
this.init(this.$route);
},
watch: {
'$route'(to, from) {
// console.log(this.$route.params.projectId)
this.init(to);
},
currentProject() {
@ -105,7 +104,7 @@ export default {
init(route) {
let path = route.path;
if (path.indexOf("/track/case/edit") >= 0 || path.indexOf("/track/case/create") >= 0) {
this.getProjects();
// this.getProjects();
this.testCaseReadOnly = false;
if (!checkoutTestManagerOrTestUser()) {
this.testCaseReadOnly = true;
@ -113,48 +112,49 @@ export default {
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);
}
// 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);
},
// 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;
@ -182,21 +182,21 @@ export default {
this.testCaseReadOnly = true;
this.$refs.testCaseEditDialog.open(testCase);
},
getProjectByCaseId(caseId) {
return this.$get('/test/case/project/' + caseId, async response => {
this.setCurrentProject(response.data);
});
},
// 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.refreshTable();
this.getNodeTree();
},
openRecentTestCaseEditDialog(caseId) {
if (caseId) {
this.getProjectByCaseId(caseId);
// this.getProjectByCaseId(caseId);
this.$get('/test/case/get/' + caseId, response => {
if (response.data) {
this.$refs.testCaseEditDialog.open(response.data);
@ -206,31 +206,31 @@ export default {
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();
},
// 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.result = this.$get("/case/node/list/" + this.currentProject, response => {
this.treeNodes = response.data;
});
}

View File

@ -489,7 +489,7 @@ export default {
param.nodePath = item.path;
}
});
if (this.currentProject) {
if (this.currentProject.id) {
param.projectId = this.currentProject.id;
}
param.name = param.name.trim();
@ -563,7 +563,7 @@ export default {
},
getTestOptions() {
this.testOptions = [];
if (this.currentProject && this.form.type != '' && this.form.type != 'functional') {
if (this.currentProject.id && this.form.type != '' && this.form.type != 'functional') {
this.result = this.$get('/' + this.form.type + '/list/' + this.currentProject.id, response => {
this.testOptions = response.data;
this.testOptions.unshift({id: 'other', name: this.$t('test_track.case.other')})

View File

@ -302,7 +302,9 @@ export default {
// param.nodeIds = this.selectNodeIds;
this.condition.nodeIds = this.selectNodeIds;
}
this.getData();
if (this.currentProject.id) {
this.getData();
}
},
getData() {
if (this.currentProject) {

View File

@ -135,14 +135,14 @@ export default {
},
init() {
let path = this.$route.path;
if (path.indexOf("/track/case") >= 0 && !!this.$route.params.projectId) {
this.testCaseProjectPath = path;
//
this.isProjectActivation = false;
this.reload();
} else {
this.isProjectActivation = true;
}
// if (path.indexOf("/track/case") >= 0 && !!this.$route.params.projectId) {
// this.testCaseProjectPath = path;
// //
// this.isProjectActivation = false;
// this.reload();
// } else {
// this.isProjectActivation = true;
// }
if (path.indexOf("/track/plan/view") >= 0) {
this.testPlanViewPath = path;
this.reload();
@ -151,6 +151,10 @@ export default {
this.testCaseEditPath = path;
this.reload();
}
if (path.indexOf("/track/review/view") >= 0) {
this.testCaseReviewEditPath = path;
this.reload();
}
},
registerEvents() {
TrackEvent.$on(LIST_CHANGE, () => {

View File

@ -1,6 +1,10 @@
<template>
<test-case-relevance-base ref="baseRelevance">
<test-case-relevance-base
@setProject="setProject"
@save="saveCaseRelevance"
:plan-id="planId"
ref="baseRelevance">
<template v-slot:aside>
<node-tree class="node-tree"
@ -11,7 +15,9 @@
</template>
<ms-table-header :condition.sync="condition" @search="search" title="" :show-create="false"/>
<el-table
v-loading="result.loading"
:data="testCases"
@filter-change="filter"
row-key="id"
@ -58,104 +64,19 @@
<div v-if="!lineStatus" style="text-align: center">{{$t('test_track.review_view.last_page')}}</div>
<div style="text-align: center"> {{total}} </div>
</test-case-relevance-base>
<!--<div>-->
<!--<el-dialog :title="$t('test_track.plan_view.relevance_test_case')"-->
<!--:visible.sync="dialogFormVisible"-->
<!--@close="close"-->
<!--width="60%" v-loading="result.loading"-->
<!--:close-on-click-modal="false"-->
<!--top="50px">-->
<!--<el-container class="main-content">-->
<!--<el-aside class="tree-aside" width="250px">-->
<!--<el-link type="primary" class="project-link" @click="switchProject">{{projectName ? projectName :-->
<!--$t('test_track.switch_project') }}-->
<!--</el-link>-->
<!--<node-tree class="node-tree"-->
<!--@nodeSelectEvent="nodeChange"-->
<!--@refresh="refresh"-->
<!--:tree-nodes="treeNodes"-->
<!--ref="nodeTree"/>-->
<!--</el-aside>-->
<!--<el-container>-->
<!--<el-main class="case-content">-->
<!--<ms-table-header :condition.sync="condition" @search="search" title="" :show-create="false"/>-->
<!--<el-table-->
<!--:data="testCases"-->
<!--@filter-change="filter"-->
<!--row-key="id"-->
<!--@mouseleave.passive="leave"-->
<!--v-el-table-infinite-scroll="scrollLoading"-->
<!--@select-all="handleSelectAll"-->
<!--@select="handleSelectionChange"-->
<!--height="50vh"-->
<!--ref="table">-->
<!--<el-table-column-->
<!--type="selection"></el-table-column>-->
<!--<el-table-column-->
<!--prop="name"-->
<!--:label="$t('test_track.case.name')"-->
<!--style="width: 100%">-->
<!--<template v-slot:default="scope">-->
<!--{{scope.row.name}}-->
<!--</template>-->
<!--</el-table-column>-->
<!--<el-table-column-->
<!--prop="priority"-->
<!--:filters="priorityFilters"-->
<!--column-key="priority"-->
<!--:label="$t('test_track.case.priority')"-->
<!--show-overflow-tooltip>-->
<!--<template v-slot:default="scope">-->
<!--<priority-table-item :value="scope.row.priority"/>-->
<!--</template>-->
<!--</el-table-column>-->
<!--<el-table-column-->
<!--prop="type"-->
<!--:filters="typeFilters"-->
<!--column-key="type"-->
<!--:label="$t('test_track.case.type')"-->
<!--show-overflow-tooltip>-->
<!--<template v-slot:default="scope">-->
<!--<type-table-item :value="scope.row.type"/>-->
<!--</template>-->
<!--</el-table-column>-->
<!--</el-table>-->
<!--<div v-if="!lineStatus" style="text-align: center">{{$t('test_track.review_view.last_page')}}</div>-->
<!--<div style="text-align: center"> {{total}} </div>-->
<!--</el-main>-->
<!--</el-container>-->
<!--</el-container>-->
<!--<template v-slot:footer>-->
<!--<ms-dialog-footer @cancel="dialogFormVisible = false" @confirm="saveCaseRelevance"/>-->
<!--</template>-->
<!--</el-dialog>-->
<!--<switch-project ref="switchProject" @getProjectNode="getProjectNode"/>-->
<!--</div>-->
</template>
<script>
import NodeTree from '../../../../common/NodeTree';
import MsDialogFooter from '../../../../../common/components/MsDialogFooter'
import PriorityTableItem from "../../../../common/tableItems/planview/PriorityTableItem";
import TypeTableItem from "../../../../common/tableItems/planview/TypeTableItem";
import MsTableSearchBar from "../../../../../common/components/MsTableSearchBar";
import MsTableAdvSearchBar from "../../../../../common/components/search/MsTableAdvSearchBar";
import MsTableHeader from "../../../../../common/components/MsTableHeader";
import {TEST_CASE_CONFIGS} from "../../../../../common/components/search/search-components";
import SwitchProject from "../../../../case/components/SwitchProject";
import elTableInfiniteScroll from 'el-table-infinite-scroll';
import TestCaseRelevanceBase from "../base/TestCaseRelevanceBase";
import {_filter} from "../../../../../../../common/js/utils";
@ -165,13 +86,11 @@
components: {
TestCaseRelevanceBase,
NodeTree,
MsDialogFooter,
PriorityTableItem,
TypeTableItem,
MsTableSearchBar,
MsTableAdvSearchBar,
MsTableHeader,
SwitchProject
},
directives: {
'el-table-infinite-scroll': elTableInfiniteScroll
@ -179,7 +98,6 @@
data() {
return {
result: {},
dialogFormVisible: false,
isCheckAll: false,
testCases: [],
selectIds: new Set(),
@ -219,13 +137,12 @@
this.condition.planId = this.planId;
},
selectNodeIds() {
if (this.dialogFormVisible) {
this.search();
}
this.search();
},
projectId() {
this.condition.projectId = this.projectId;
this.getProjectNode();
this.search();
}
},
updated() {
@ -235,8 +152,10 @@
open() {
this.$refs.baseRelevance.open();
},
//
setProject(projectId) {
this.projectId = projectId;
},
saveCaseRelevance() {
@ -251,7 +170,9 @@
this.result = this.$post('/test/plan/relevance', param, () => {
this.selectIds.clear();
this.$success(this.$t('commons.save_success'));
this.dialogFormVisible = false;
this.$refs.baseRelevance.close();
this.$emit('refresh');
});
},
@ -274,7 +195,27 @@
}
if (this.projectId) {
this.condition.projectId = this.projectId;
this.result = this.$post(this.buildPagePath('/test/case/name'), this.condition, response => {
// this.result = this.$post(this.buildPagePath('/test/case/name'), this.condition, response => {
// let data = response.data;
// this.total = data.itemCount;
// let tableData = data.listObject;
// tableData.forEach(item => {
// 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;
// });
this.result = this.$post('/api/definition/list/1/10', this.condition, response => {
let data = response.data;
this.total = data.itemCount;
let tableData = data.listObject;
@ -295,7 +236,6 @@
this.lineStatus = tableData.length === 50 && this.testCases.length < this.total;
});
}
},
handleSelectAll(selection) {
if (selection.length > 0) {
@ -325,7 +265,7 @@
this.close();
},
scrollLoading() {
if (this.dialogFormVisible && this.lineStatus) {
if (this.lineStatus) {
this.currentPage += 1;
this.getTestCases();
}
@ -336,7 +276,7 @@
testPlanId: this.planId,
projectId: this.projectId
};
this.result = this.$post("/case/node/list/all/plan", param, response => {
this.result = this.$get('/api/module/list/' + this.project + '/HTTP', response => {
this.treeNodes = response.data;
});
}
@ -361,24 +301,6 @@
})
})
},
getProject() {
if (this.planId) {
this.result = this.$post("/test/plan/project/", {planId: this.planId}, res => {
let data = res.data;
if (data) {
this.projects = data;
this.projectId = data[0].id;
this.projectName = data[0].name;
this.search();
//
this.getProjectNode(this.projectId)
}
})
}
},
switchProject() {
this.$refs.switchProject.open({id: this.planId, url: '/test/plan/project/', type: 'plan'});
},
getProjectNode(projectId) {
const index = this.projects.findIndex(project => project.id === projectId);
if (index !== -1) {
@ -387,11 +309,13 @@
if (projectId) {
this.projectId = projectId;
}
this.result = this.$post("/case/node/list/all/plan",
{testPlanId: this.planId, projectId: this.projectId}, response => {
this.$refs.nodeTree.result = this.$get('/api/module/list/' + this.projectId + '/HTTP', response => {
this.treeNodes = response.data;
});
// this.$refs.nodeTree.result = this.$post('/api/module/list/' + this.project + '/HTTP',
// {testPlanId: this.planId, projectId: this.projectId}, response => {
// this.treeNodes = response.data;
// });
this.selectNodeIds = [];
}
}
@ -399,53 +323,4 @@
</script>
<style scoped>
.tb-edit .el-input {
display: none;
color: black;
}
.tb-edit .current-row .el-input {
display: block;
}
.tb-edit .current-row .el-input + span {
display: none;
}
.node-tree {
margin-right: 10px;
}
.el-header {
background-color: darkgrey;
color: #333;
line-height: 60px;
}
.case-content {
padding: 0px 20px;
height: 100%;
/*border: 1px solid #EBEEF5;*/
}
.tree-aside {
min-height: 300px;
max-height: 100%;
}
.main-content {
min-height: 300px;
height: 100%;
/*border: 1px solid #EBEEF5;*/
}
.project-link {
float: right;
margin-right: 12px;
margin-bottom: 10px;
}
</style>

View File

@ -1,4 +1,3 @@
import MsProject from "@/business/components/settings/project/MsProject";
const TestTrack = () => import('@/business/components/track/TestTrack')
const TrackHome = () => import('@/business/components/track/home/TrackHome')

@ -1 +1 @@
Subproject commit 8a972a198775b3783ed6e4cef27197e53d1ebdc8
Subproject commit a22a3005d9bd254793fcf634d72539cbdf31be3a

View File

@ -39,10 +39,22 @@ const Switch = {
}
}
const IsReadOnly = {
state: {
flag: true
},
mutations: {
setFlag(state, value) {
state.flag = value;
}
}
}
export default new Vuex.Store({
modules: {
api: API,
common: Common,
switch: Switch,
isReadOnly: IsReadOnly,
}
})

View File

@ -16,6 +16,11 @@ body {
margin: 0;
}
/* 解决 document.body.clientHeight 为0 */
html,body {
height:100%
}
.main-content span.title {
font-size: 16px;
font-weight: 500;