Merge branch 'master' of https://github.com/metersphere/metersphere
This commit is contained in:
commit
65c0bf3f32
|
@ -8,21 +8,29 @@ import java.io.Serializable;
|
||||||
public class ApiScenario implements Serializable {
|
public class ApiScenario implements Serializable {
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
private String apiScenarioId;
|
private String projectId;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
private String scenarioId;
|
||||||
|
|
||||||
|
private String level;
|
||||||
|
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
private String principal;
|
||||||
|
|
||||||
|
private String stepTotal;
|
||||||
|
|
||||||
|
private String followPeople;
|
||||||
|
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
|
private String scenarioDefinition;
|
||||||
|
|
||||||
|
private String userId;
|
||||||
|
|
||||||
private Long createTime;
|
private Long createTime;
|
||||||
|
|
||||||
private Long updateTime;
|
private Long updateTime;
|
||||||
|
|
||||||
private String status;
|
|
||||||
|
|
||||||
private String userId;
|
|
||||||
|
|
||||||
private String triggerMode;
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
}
|
}
|
|
@ -8,27 +8,21 @@ import java.io.Serializable;
|
||||||
public class ApiScenarioReport implements Serializable {
|
public class ApiScenarioReport implements Serializable {
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
private String projectId;
|
private String apiScenarioId;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
private String scenarioId;
|
|
||||||
|
|
||||||
private String level;
|
|
||||||
|
|
||||||
private String status;
|
|
||||||
|
|
||||||
private String principal;
|
|
||||||
|
|
||||||
private String followPeople;
|
|
||||||
|
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
private String scenarioDefinition;
|
|
||||||
|
|
||||||
private String userId;
|
|
||||||
|
|
||||||
private Long createTime;
|
private Long createTime;
|
||||||
|
|
||||||
private Long updateTime;
|
private Long updateTime;
|
||||||
|
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
private String triggerMode;
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
}
|
}
|
|
@ -39,4 +39,12 @@ public interface ExtTestPlanTestCaseMapper {
|
||||||
List<TestPlanCaseDTO> listTestCaseByProjectIds(@Param("ids") List<String> ids);
|
List<TestPlanCaseDTO> listTestCaseByProjectIds(@Param("ids") List<String> ids);
|
||||||
|
|
||||||
TestPlanCaseDTO get(String testPlanTestCaseId);
|
TestPlanCaseDTO get(String testPlanTestCaseId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取测试计划下的 TestPlanTestCaseID 和 TestCaseName
|
||||||
|
* @param request planId 不能为空
|
||||||
|
* @return List<TestPlanCaseDTO>
|
||||||
|
*/
|
||||||
|
List<TestPlanCaseDTO> getTestPlanTestCaseList(@Param("request") QueryTestPlanCaseRequest request);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,9 @@
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="list" resultType="io.metersphere.track.dto.TestPlanCaseDTO">
|
<select id="list" resultType="io.metersphere.track.dto.TestPlanCaseDTO">
|
||||||
select test_case.remark, test_plan_test_case.id as id, test_plan_test_case.*,test_case.*,test_case_node.name as model, project.name as projectName
|
select test_plan_test_case.id as id, test_case.id as caseId, test_case.name, test_case.priority, test_case.type,
|
||||||
|
test_case.node_path, test_case.method, test_case.num, test_plan_test_case.executor, test_plan_test_case.status,
|
||||||
|
test_plan_test_case.update_time, test_case_node.name as model, project.name as projectName, test_plan_test_case.plan_id as planId
|
||||||
from test_plan_test_case
|
from test_plan_test_case
|
||||||
inner join test_case on test_plan_test_case.case_id = test_case.id
|
inner join test_case on test_plan_test_case.case_id = test_case.id
|
||||||
left join test_case_node on test_case_node.id=test_case.node_id
|
left join test_case_node on test_case_node.id=test_case.node_id
|
||||||
|
@ -134,7 +136,8 @@
|
||||||
</include>
|
</include>
|
||||||
</if>
|
</if>
|
||||||
<if test="request.name != null">
|
<if test="request.name != null">
|
||||||
and (test_case.name like CONCAT('%', #{request.name},'%') or test_case.num like CONCAT('%', #{request.name},'%'))
|
and (test_case.name like CONCAT('%', #{request.name},'%') or test_case.num like
|
||||||
|
CONCAT('%',#{request.name},'%'))
|
||||||
</if>
|
</if>
|
||||||
<if test="request.id != null">
|
<if test="request.id != null">
|
||||||
and test_case.id = #{request.id}
|
and test_case.id = #{request.id}
|
||||||
|
@ -210,6 +213,14 @@
|
||||||
</foreach>
|
</foreach>
|
||||||
</if>
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="getTestPlanTestCaseList" resultType="io.metersphere.track.dto.TestPlanCaseDTO">
|
||||||
|
select test_plan_test_case.id as id, test_case.name
|
||||||
|
from test_plan_test_case
|
||||||
|
inner join test_case on test_plan_test_case.case_id = test_case.id
|
||||||
|
where test_plan_test_case.plan_id = #{request.planId}
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="listTestCaseByProjectIds" resultType="io.metersphere.track.dto.TestPlanCaseDTO">
|
<select id="listTestCaseByProjectIds" resultType="io.metersphere.track.dto.TestPlanCaseDTO">
|
||||||
select distinct * from test_plan_test_case, test_case
|
select distinct * from test_plan_test_case, test_case
|
||||||
where test_plan_test_case.case_id = test_case.id
|
where test_plan_test_case.case_id = test_case.id
|
||||||
|
|
|
@ -491,9 +491,9 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
setupElement.setAttribute("testclass", "SetupThreadGroup");
|
setupElement.setAttribute("testclass", "SetupThreadGroup");
|
||||||
setupElement.setAttribute("testname", "setUp Thread Group");
|
setupElement.setAttribute("testname", "setUp Thread Group");
|
||||||
setupElement.setAttribute("enabled", "true");
|
setupElement.setAttribute("enabled", "true");
|
||||||
setupElement.appendChild(createStringProp(document, "MsThreadGroup.on_sample_error", "stoptestnow"));
|
setupElement.appendChild(createStringProp(document, "ThreadGroup.on_sample_error", "stoptestnow"));
|
||||||
Element elementProp = document.createElement("elementProp");
|
Element elementProp = document.createElement("elementProp");
|
||||||
elementProp.setAttribute("name", "MsThreadGroup.main_controller");
|
elementProp.setAttribute("name", "ThreadGroup.main_controller");
|
||||||
elementProp.setAttribute("elementType", "LoopController");
|
elementProp.setAttribute("elementType", "LoopController");
|
||||||
elementProp.setAttribute("guiclass", "LoopControlPanel");
|
elementProp.setAttribute("guiclass", "LoopControlPanel");
|
||||||
elementProp.setAttribute("testclass", "LoopController");
|
elementProp.setAttribute("testclass", "LoopController");
|
||||||
|
@ -502,12 +502,12 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
elementProp.appendChild(createBoolProp(document, "LoopController.continue_forever", false));
|
elementProp.appendChild(createBoolProp(document, "LoopController.continue_forever", false));
|
||||||
elementProp.appendChild(createIntProp(document, "LoopController.loops", 1));
|
elementProp.appendChild(createIntProp(document, "LoopController.loops", 1));
|
||||||
setupElement.appendChild(elementProp);
|
setupElement.appendChild(elementProp);
|
||||||
setupElement.appendChild(createStringProp(document, "MsThreadGroup.num_threads", "1"));
|
setupElement.appendChild(createStringProp(document, "ThreadGroup.num_threads", "1"));
|
||||||
setupElement.appendChild(createStringProp(document, "MsThreadGroup.ramp_time", "1"));
|
setupElement.appendChild(createStringProp(document, "ThreadGroup.ramp_time", "1"));
|
||||||
setupElement.appendChild(createStringProp(document, "MsThreadGroup.duration", ""));
|
setupElement.appendChild(createStringProp(document, "ThreadGroup.duration", ""));
|
||||||
setupElement.appendChild(createStringProp(document, "MsThreadGroup.delay", ""));
|
setupElement.appendChild(createStringProp(document, "ThreadGroup.delay", ""));
|
||||||
setupElement.appendChild(createBoolProp(document, "MsThreadGroup.scheduler", false));
|
setupElement.appendChild(createBoolProp(document, "ThreadGroup.scheduler", false));
|
||||||
setupElement.appendChild(createBoolProp(document, "MsThreadGroup.same_user_on_next_iteration", true));
|
setupElement.appendChild(createBoolProp(document, "ThreadGroup.same_user_on_next_iteration", true));
|
||||||
hashTree.appendChild(setupElement);
|
hashTree.appendChild(setupElement);
|
||||||
|
|
||||||
Element setupHashTree = document.createElement(HASH_TREE_ELEMENT);
|
Element setupHashTree = document.createElement(HASH_TREE_ELEMENT);
|
||||||
|
@ -568,17 +568,17 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
<PostThreadGroup guiclass="PostThreadGroupGui" testclass="PostThreadGroup" testname="tearDown Thread Group" enabled="true">
|
<PostThreadGroup guiclass="PostThreadGroupGui" testclass="PostThreadGroup" testname="tearDown Thread Group" enabled="true">
|
||||||
<stringProp name="MsThreadGroup.on_sample_error">continue</stringProp>
|
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
|
||||||
<elementProp name="MsThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
|
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
|
||||||
<boolProp name="LoopController.continue_forever">false</boolProp>
|
<boolProp name="LoopController.continue_forever">false</boolProp>
|
||||||
<stringProp name="LoopController.loops">1</stringProp>
|
<stringProp name="LoopController.loops">1</stringProp>
|
||||||
</elementProp>
|
</elementProp>
|
||||||
<stringProp name="MsThreadGroup.num_threads">1</stringProp>
|
<stringProp name="ThreadGroup.num_threads">1</stringProp>
|
||||||
<stringProp name="MsThreadGroup.ramp_time">1</stringProp>
|
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
|
||||||
<boolProp name="MsThreadGroup.scheduler">false</boolProp>
|
<boolProp name="ThreadGroup.scheduler">false</boolProp>
|
||||||
<stringProp name="MsThreadGroup.duration"></stringProp>
|
<stringProp name="ThreadGroup.duration"></stringProp>
|
||||||
<stringProp name="MsThreadGroup.delay"></stringProp>
|
<stringProp name="ThreadGroup.delay"></stringProp>
|
||||||
<boolProp name="MsThreadGroup.same_user_on_next_iteration">true</boolProp>
|
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
|
||||||
</PostThreadGroup>
|
</PostThreadGroup>
|
||||||
*/
|
*/
|
||||||
Element tearDownElement = document.createElement("PostThreadGroup");
|
Element tearDownElement = document.createElement("PostThreadGroup");
|
||||||
|
@ -586,15 +586,15 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
tearDownElement.setAttribute("testclass", "PostThreadGroup");
|
tearDownElement.setAttribute("testclass", "PostThreadGroup");
|
||||||
tearDownElement.setAttribute("testname", "tearDown Thread Group");
|
tearDownElement.setAttribute("testname", "tearDown Thread Group");
|
||||||
tearDownElement.setAttribute("enabled", "true");
|
tearDownElement.setAttribute("enabled", "true");
|
||||||
tearDownElement.appendChild(createStringProp(document, "MsThreadGroup.on_sample_error", "continue"));
|
tearDownElement.appendChild(createStringProp(document, "ThreadGroup.on_sample_error", "continue"));
|
||||||
tearDownElement.appendChild(createStringProp(document, "MsThreadGroup.num_threads", "1"));
|
tearDownElement.appendChild(createStringProp(document, "ThreadGroup.num_threads", "1"));
|
||||||
tearDownElement.appendChild(createStringProp(document, "MsThreadGroup.ramp_time", "1"));
|
tearDownElement.appendChild(createStringProp(document, "ThreadGroup.ramp_time", "1"));
|
||||||
tearDownElement.appendChild(createStringProp(document, "MsThreadGroup.duration", ""));
|
tearDownElement.appendChild(createStringProp(document, "ThreadGroup.duration", ""));
|
||||||
tearDownElement.appendChild(createStringProp(document, "MsThreadGroup.delay", ""));
|
tearDownElement.appendChild(createStringProp(document, "ThreadGroup.delay", ""));
|
||||||
tearDownElement.appendChild(createBoolProp(document, "MsThreadGroup.scheduler", false));
|
tearDownElement.appendChild(createBoolProp(document, "ThreadGroup.scheduler", false));
|
||||||
tearDownElement.appendChild(createBoolProp(document, "MsThreadGroup.same_user_on_next_iteration", true));
|
tearDownElement.appendChild(createBoolProp(document, "ThreadGroup.same_user_on_next_iteration", true));
|
||||||
Element elementProp = document.createElement("elementProp");
|
Element elementProp = document.createElement("elementProp");
|
||||||
elementProp.setAttribute("name", "MsThreadGroup.main_controller");
|
elementProp.setAttribute("name", "ThreadGroup.main_controller");
|
||||||
elementProp.setAttribute("elementType", "LoopController");
|
elementProp.setAttribute("elementType", "LoopController");
|
||||||
elementProp.setAttribute("guiclass", "LoopControlPanel");
|
elementProp.setAttribute("guiclass", "LoopControlPanel");
|
||||||
elementProp.setAttribute("testclass", "LoopController");
|
elementProp.setAttribute("testclass", "LoopController");
|
||||||
|
@ -760,8 +760,8 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
threadGroup.setAttribute("guiclass", CONCURRENCY_THREAD_GROUP + "Gui");
|
threadGroup.setAttribute("guiclass", CONCURRENCY_THREAD_GROUP + "Gui");
|
||||||
threadGroup.setAttribute("testclass", CONCURRENCY_THREAD_GROUP);
|
threadGroup.setAttribute("testclass", CONCURRENCY_THREAD_GROUP);
|
||||||
/*
|
/*
|
||||||
<elementProp name="MsThreadGroup.main_controller" elementType="com.blazemeter.jmeter.control.VirtualUserController"/>
|
<elementProp name="ThreadGroup.main_controller" elementType="com.blazemeter.jmeter.control.VirtualUserController"/>
|
||||||
<stringProp name="MsThreadGroup.on_sample_error">continue</stringProp>
|
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
|
||||||
<stringProp name="TargetLevel">2</stringProp>
|
<stringProp name="TargetLevel">2</stringProp>
|
||||||
<stringProp name="RampUp">12</stringProp>
|
<stringProp name="RampUp">12</stringProp>
|
||||||
<stringProp name="Steps">2</stringProp>
|
<stringProp name="Steps">2</stringProp>
|
||||||
|
@ -773,11 +773,11 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
removeChildren(threadGroup);
|
removeChildren(threadGroup);
|
||||||
// elementProp
|
// elementProp
|
||||||
Element elementProp = document.createElement("elementProp");
|
Element elementProp = document.createElement("elementProp");
|
||||||
elementProp.setAttribute("name", "MsThreadGroup.main_controller");
|
elementProp.setAttribute("name", "ThreadGroup.main_controller");
|
||||||
elementProp.setAttribute("elementType", "com.blazemeter.jmeter.control.VirtualUserController");
|
elementProp.setAttribute("elementType", "com.blazemeter.jmeter.control.VirtualUserController");
|
||||||
threadGroup.appendChild(elementProp);
|
threadGroup.appendChild(elementProp);
|
||||||
|
|
||||||
threadGroup.appendChild(createStringProp(document, "MsThreadGroup.on_sample_error", "continue"));
|
threadGroup.appendChild(createStringProp(document, "ThreadGroup.on_sample_error", "continue"));
|
||||||
threadGroup.appendChild(createStringProp(document, "TargetLevel", "2"));
|
threadGroup.appendChild(createStringProp(document, "TargetLevel", "2"));
|
||||||
threadGroup.appendChild(createStringProp(document, "RampUp", "12"));
|
threadGroup.appendChild(createStringProp(document, "RampUp", "12"));
|
||||||
threadGroup.appendChild(createStringProp(document, "Steps", "2"));
|
threadGroup.appendChild(createStringProp(document, "Steps", "2"));
|
||||||
|
@ -785,8 +785,6 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
threadGroup.appendChild(createStringProp(document, "LogFilename", ""));
|
threadGroup.appendChild(createStringProp(document, "LogFilename", ""));
|
||||||
// bzm - Concurrency Thread Group "Thread Iterations Limit:" 设置为空
|
// bzm - Concurrency Thread Group "Thread Iterations Limit:" 设置为空
|
||||||
// threadGroup.appendChild(createStringProp(document, "Iterations", "1"));
|
// threadGroup.appendChild(createStringProp(document, "Iterations", "1"));
|
||||||
// threadGroup.appendChild(createStringProp(document, "Unit", "M"));
|
|
||||||
// 单位改成秒
|
|
||||||
threadGroup.appendChild(createStringProp(document, "Unit", "S"));
|
threadGroup.appendChild(createStringProp(document, "Unit", "S"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -880,24 +878,6 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processVariableThroughputTimer(Element variableThroughputTimer) {
|
private void processVariableThroughputTimer(Element variableThroughputTimer) {
|
||||||
Object durations = context.getProperty("duration");
|
|
||||||
Integer duration;
|
|
||||||
if (durations instanceof List) {
|
|
||||||
Object o = ((List<?>) durations).get(0);
|
|
||||||
duration = (Integer) o;
|
|
||||||
((List<?>) durations).remove(0);
|
|
||||||
} else {
|
|
||||||
duration = (Integer) durations;
|
|
||||||
}
|
|
||||||
Object rpsLimits = context.getProperty("rpsLimit");
|
|
||||||
String rpsLimit;
|
|
||||||
if (rpsLimits instanceof List) {
|
|
||||||
Object o = ((List<?>) rpsLimits).get(0);
|
|
||||||
((List<?>) rpsLimits).remove(0);
|
|
||||||
rpsLimit = o.toString();
|
|
||||||
} else {
|
|
||||||
rpsLimit = rpsLimits.toString();
|
|
||||||
}
|
|
||||||
if (variableThroughputTimer.getChildNodes().getLength() > 0) {
|
if (variableThroughputTimer.getChildNodes().getLength() > 0) {
|
||||||
final NodeList childNodes = variableThroughputTimer.getChildNodes();
|
final NodeList childNodes = variableThroughputTimer.getChildNodes();
|
||||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||||
|
@ -923,9 +903,27 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
stringPropCount++;
|
stringPropCount++;
|
||||||
} else {
|
} else {
|
||||||
stringPropCount = 0;
|
stringPropCount = 0;
|
||||||
|
Object durations = context.getProperty("duration");// 传入的是分钟数, 需要转化成秒数
|
||||||
|
Integer duration;
|
||||||
|
if (durations instanceof List) {
|
||||||
|
Object o = ((List<?>) durations).get(0);
|
||||||
|
duration = (Integer) o;
|
||||||
|
((List<?>) durations).remove(0);
|
||||||
|
} else {
|
||||||
|
duration = (Integer) durations;
|
||||||
|
}
|
||||||
prop.getFirstChild().setNodeValue(String.valueOf(duration));
|
prop.getFirstChild().setNodeValue(String.valueOf(duration));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
Object rpsLimits = context.getProperty("rpsLimit");
|
||||||
|
String rpsLimit;
|
||||||
|
if (rpsLimits instanceof List) {
|
||||||
|
Object o = ((List<?>) rpsLimits).get(0);
|
||||||
|
((List<?>) rpsLimits).remove(0);
|
||||||
|
rpsLimit = o.toString();
|
||||||
|
} else {
|
||||||
|
rpsLimit = rpsLimits.toString();
|
||||||
|
}
|
||||||
prop.getFirstChild().setNodeValue(rpsLimit);
|
prop.getFirstChild().setNodeValue(rpsLimit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,11 @@ public class TestPlanTestCaseController {
|
||||||
return testPlanTestCaseService.list(request);
|
return testPlanTestCaseService.list(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/list/ids")
|
||||||
|
public List<TestPlanCaseDTO> getTestPlanCaseIds(@RequestBody QueryTestPlanCaseRequest request) {
|
||||||
|
return testPlanTestCaseService.list(request);
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/edit")
|
@PostMapping("/edit")
|
||||||
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
||||||
public void editTestCase(@RequestBody TestPlanTestCaseWithBLOBs testPlanTestCase) {
|
public void editTestCase(@RequestBody TestPlanTestCaseWithBLOBs testPlanTestCase) {
|
||||||
|
|
|
@ -372,7 +372,7 @@ public class TestCaseNodeService {
|
||||||
public Map<String, String> createNodes(List<String> nodePaths, String projectId) {
|
public Map<String, String> createNodes(List<String> nodePaths, String projectId) {
|
||||||
List<TestCaseNodeDTO> nodeTrees = getNodeTreeByProjectId(projectId);
|
List<TestCaseNodeDTO> nodeTrees = getNodeTreeByProjectId(projectId);
|
||||||
Map<String, String> pathMap = new HashMap<>();
|
Map<String, String> pathMap = new HashMap<>();
|
||||||
for(String item : nodePaths){
|
for (String item : nodePaths) {
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
throw new ExcelException(Translator.get("test_case_module_not_null"));
|
throw new ExcelException(Translator.get("test_case_module_not_null"));
|
||||||
}
|
}
|
||||||
|
@ -590,6 +590,7 @@ public class TestCaseNodeService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 测试用例同级模块排序
|
* 测试用例同级模块排序
|
||||||
|
*
|
||||||
* @param ids 被拖拽模块相邻的前一个模块 id,
|
* @param ids 被拖拽模块相邻的前一个模块 id,
|
||||||
* 被拖拽的模块 id,
|
* 被拖拽的模块 id,
|
||||||
* 被拖拽模块相邻的后一个模块 id
|
* 被拖拽模块相邻的后一个模块 id
|
||||||
|
@ -635,6 +636,7 @@ public class TestCaseNodeService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按照指定排序方式获取同级模块的列表
|
* 按照指定排序方式获取同级模块的列表
|
||||||
|
*
|
||||||
* @param projectId 所属项目 id
|
* @param projectId 所属项目 id
|
||||||
* @param level node level
|
* @param level node level
|
||||||
* @param parentId node parent id
|
* @param parentId node parent id
|
||||||
|
@ -654,6 +656,7 @@ public class TestCaseNodeService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新同级模块的 pos 值
|
* 刷新同级模块的 pos 值
|
||||||
|
*
|
||||||
* @param projectId project id
|
* @param projectId project id
|
||||||
* @param level node level
|
* @param level node level
|
||||||
* @param parentId node parent id
|
* @param parentId node parent id
|
||||||
|
@ -675,6 +678,7 @@ public class TestCaseNodeService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得同级模块下一个 pos 值
|
* 获得同级模块下一个 pos 值
|
||||||
|
*
|
||||||
* @param projectId project id
|
* @param projectId project id
|
||||||
* @param level node level
|
* @param level node level
|
||||||
* @param parentId node parent id
|
* @param parentId node parent id
|
||||||
|
@ -682,7 +686,7 @@ public class TestCaseNodeService {
|
||||||
*/
|
*/
|
||||||
private double getNextLevelPos(String projectId, int level, String parentId) {
|
private double getNextLevelPos(String projectId, int level, String parentId) {
|
||||||
List<TestCaseNode> list = getPos(projectId, level, parentId, "pos desc");
|
List<TestCaseNode> list = getPos(projectId, level, parentId, "pos desc");
|
||||||
if (!CollectionUtils.isEmpty(list)) {
|
if (!CollectionUtils.isEmpty(list) && list.get(0) != null && list.get(0).getPos() != null) {
|
||||||
return list.get(0).getPos() + 65536;
|
return list.get(0).getPos() + 65536;
|
||||||
} else {
|
} else {
|
||||||
return 65536;
|
return 65536;
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!-- 请求地址 -->
|
<!-- 请求地址 -->
|
||||||
<el-form-item prop="url">
|
<el-form-item prop="path">
|
||||||
<el-input :placeholder="$t('api_test.definition.request.path_info')" v-model="api.request.path" class="ms-htt-width"
|
<el-input :placeholder="$t('api_test.definition.request.path_info')" v-model="api.request.path" class="ms-htt-width"
|
||||||
size="small" :disabled="false"/>
|
size="small" :disabled="false"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -120,7 +120,7 @@
|
||||||
environments: [],
|
environments: [],
|
||||||
rules: {
|
rules: {
|
||||||
method: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
|
method: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
|
||||||
url: [{required: true, message: this.$t('api_test.definition.request.path_info'), trigger: 'blur'}],
|
path: [{required: true, message: this.$t('api_test.definition.request.path_info'), trigger: 'blur'}],
|
||||||
environmentId: [{required: true, message: this.$t('api_test.definition.request.run_env'), trigger: 'change'}],
|
environmentId: [{required: true, message: this.$t('api_test.definition.request.run_env'), trigger: 'change'}],
|
||||||
},
|
},
|
||||||
runData: [],
|
runData: [],
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
<el-form-item :label="$t('load_test.thread_num')">
|
<el-form-item :label="$t('load_test.thread_num')">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:disabled="isReadOnly"
|
:disabled="isReadOnly"
|
||||||
:placeholder="$t('load_test.input_thread_num')"
|
|
||||||
v-model="threadGroup.threadNumber"
|
v-model="threadGroup.threadNumber"
|
||||||
@change="calculateChart(threadGroup)"
|
@change="calculateChart(threadGroup)"
|
||||||
:min="resourcePoolResourceLength"
|
:min="resourcePoolResourceLength"
|
||||||
|
@ -37,7 +36,6 @@
|
||||||
<el-form-item :label="$t('load_test.duration')">
|
<el-form-item :label="$t('load_test.duration')">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:disabled="isReadOnly"
|
:disabled="isReadOnly"
|
||||||
:placeholder="$t('load_test.duration')"
|
|
||||||
v-model="threadGroup.duration"
|
v-model="threadGroup.duration"
|
||||||
:min="1"
|
:min="1"
|
||||||
@change="calculateChart(threadGroup)"
|
@change="calculateChart(threadGroup)"
|
||||||
|
@ -49,7 +47,6 @@
|
||||||
|
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:disabled="isReadOnly || !threadGroup.rpsLimitEnable"
|
:disabled="isReadOnly || !threadGroup.rpsLimitEnable"
|
||||||
:placeholder="$t('load_test.input_rps_limit')"
|
|
||||||
v-model="threadGroup.rpsLimit"
|
v-model="threadGroup.rpsLimit"
|
||||||
@change="calculateChart(threadGroup)"
|
@change="calculateChart(threadGroup)"
|
||||||
:min="1"
|
:min="1"
|
||||||
|
@ -59,7 +56,6 @@
|
||||||
<el-form-item :label="$t('load_test.ramp_up_time_within')">
|
<el-form-item :label="$t('load_test.ramp_up_time_within')">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:disabled="isReadOnly"
|
:disabled="isReadOnly"
|
||||||
placeholder=""
|
|
||||||
:min="1"
|
:min="1"
|
||||||
:max="threadGroup.duration"
|
:max="threadGroup.duration"
|
||||||
v-model="threadGroup.rampUpTime"
|
v-model="threadGroup.rampUpTime"
|
||||||
|
@ -69,7 +65,6 @@
|
||||||
<el-form-item :label="$t('load_test.ramp_up_time_minutes')">
|
<el-form-item :label="$t('load_test.ramp_up_time_minutes')">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:disabled="isReadOnly"
|
:disabled="isReadOnly"
|
||||||
placeholder=""
|
|
||||||
:min="1"
|
:min="1"
|
||||||
:max="Math.min(threadGroup.threadNumber, threadGroup.rampUpTime)"
|
:max="Math.min(threadGroup.threadNumber, threadGroup.rampUpTime)"
|
||||||
v-model="threadGroup.step"
|
v-model="threadGroup.step"
|
||||||
|
@ -465,7 +460,13 @@ export default {
|
||||||
|
|
||||||
for (let i = 0; i < this.threadGroups.length; i++) {
|
for (let i = 0; i < this.threadGroups.length; i++) {
|
||||||
if (!this.threadGroups[i].threadNumber || !this.threadGroups[i].duration
|
if (!this.threadGroups[i].threadNumber || !this.threadGroups[i].duration
|
||||||
|| !this.threadGroups[i].rampUpTime || !this.threadGroups[i].step || !this.threadGroups[i].rpsLimit) {
|
|| !this.threadGroups[i].rampUpTime || !this.threadGroups[i].step) {
|
||||||
|
this.$warning(this.$t('load_test.pressure_config_params_is_empty'));
|
||||||
|
this.$emit('changeActive', '1');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.threadGroups[i].rpsLimitEnable && !this.threadGroups[i].rpsLimit) {
|
||||||
this.$warning(this.$t('load_test.pressure_config_params_is_empty'));
|
this.$warning(this.$t('load_test.pressure_config_params_is_empty'));
|
||||||
this.$emit('changeActive', '1');
|
this.$emit('changeActive', '1');
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<img class="platform" src="../../../../assets/jira.png" alt="Jira"/>
|
<img class="platform" src="../../../../assets/jira.png" alt="Jira"/>
|
||||||
</el-radio>
|
</el-radio>
|
||||||
<el-radio label="Zentao">
|
<el-radio label="Zentao">
|
||||||
<img class="platform" src="../../../../assets/zentao.jpg" alt="Zentao"/>
|
<img class="zentao_platform" src="../../../../assets/zentao.jpg" alt="Zentao"/>
|
||||||
</el-radio>
|
</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</div>
|
</div>
|
||||||
|
@ -66,7 +66,12 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.platform {
|
.platform {
|
||||||
height: 90px;
|
height: 80px;
|
||||||
|
vertical-align: middle
|
||||||
|
}
|
||||||
|
|
||||||
|
.zentao_platform {
|
||||||
|
height: 100px;
|
||||||
vertical-align: middle
|
vertical-align: middle
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -34,7 +34,6 @@ export default {
|
||||||
},
|
},
|
||||||
...requireContext.keys().map(key => requireContext(key).system),
|
...requireContext.keys().map(key => requireContext(key).system),
|
||||||
...requireContext.keys().map(key => requireContext(key).license),
|
...requireContext.keys().map(key => requireContext(key).license),
|
||||||
...requireContext.keys().map(key => requireContext(key).display),
|
|
||||||
{
|
{
|
||||||
path: 'organizationpmnmember',
|
path: 'organizationpmnmember',
|
||||||
component: () => import('@/business/components/settings/organization/OrganizationMember'),
|
component: () => import('@/business/components/settings/organization/OrganizationMember'),
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
<el-tab-pane :label="$t('system_parameter_setting.ldap_setting')" name="ldap">
|
<el-tab-pane :label="$t('system_parameter_setting.ldap_setting')" name="ldap">
|
||||||
<ldap-setting/>
|
<ldap-setting/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
<el-tab-pane v-if="hasLicense()" :label="$t('display.title')" name="display">
|
||||||
|
<ms-display/>
|
||||||
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</el-card>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
@ -19,10 +22,13 @@
|
||||||
import EmailSetting from "./EmailSetting";
|
import EmailSetting from "./EmailSetting";
|
||||||
import LdapSetting from "./LdapSetting";
|
import LdapSetting from "./LdapSetting";
|
||||||
import BaseSetting from "./BaseSetting";
|
import BaseSetting from "./BaseSetting";
|
||||||
|
import MsDisplay from "@/business/components/xpack/display/Display";
|
||||||
|
import {hasLicense} from '@/common/js/utils';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "SystemParameterSetting",
|
name: "SystemParameterSetting",
|
||||||
components: {
|
components: {
|
||||||
|
MsDisplay,
|
||||||
BaseSetting,
|
BaseSetting,
|
||||||
EmailSetting, LdapSetting
|
EmailSetting, LdapSetting
|
||||||
},
|
},
|
||||||
|
@ -30,6 +36,9 @@ export default {
|
||||||
return {
|
return {
|
||||||
activeName: 'base'
|
activeName: 'base'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
hasLicense,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -473,15 +473,16 @@ export default {
|
||||||
},
|
},
|
||||||
getTestCase(index) {
|
getTestCase(index) {
|
||||||
let testCase = this.testCases[index];
|
let testCase = this.testCases[index];
|
||||||
|
// id 为 TestPlanTestCase 的 id
|
||||||
|
this.result = this.$get('/test/plan/case/get/' + testCase.id, response => {
|
||||||
let item = {};
|
let item = {};
|
||||||
Object.assign(item, testCase);
|
Object.assign(item, response.data);
|
||||||
item.results = JSON.parse(item.results);
|
item.results = JSON.parse(item.results);
|
||||||
item.steps = JSON.parse(item.steps);
|
item.steps = JSON.parse(item.steps);
|
||||||
if (item.issues) {
|
if (item.issues) {
|
||||||
item.issues = JSON.parse(item.issues);
|
item.issues = JSON.parse(item.issues);
|
||||||
} else {
|
} else {
|
||||||
item.issues = {};
|
item.issues = {};
|
||||||
item.issues.hasIssues = false;
|
|
||||||
}
|
}
|
||||||
item.steptResults = [];
|
item.steptResults = [];
|
||||||
for (let i = 0; i < item.steps.length; i++) {
|
for (let i = 0; i < item.steps.length; i++) {
|
||||||
|
@ -492,7 +493,10 @@ export default {
|
||||||
item.steptResults.push(item.steps[i]);
|
item.steptResults.push(item.steps[i]);
|
||||||
}
|
}
|
||||||
this.testCase = item;
|
this.testCase = item;
|
||||||
|
this.getRelatedTest();
|
||||||
this.initTest();
|
this.initTest();
|
||||||
|
})
|
||||||
|
|
||||||
this.getIssues(testCase.caseId);
|
this.getIssues(testCase.caseId);
|
||||||
this.stepResultChange();
|
this.stepResultChange();
|
||||||
this.getFileMetaData(testCase);
|
this.getFileMetaData(testCase);
|
||||||
|
@ -521,14 +525,15 @@ export default {
|
||||||
},
|
},
|
||||||
initTest() {
|
initTest() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
if (this.testCase.testId && this.testCase.testId !== 'other') {
|
||||||
if (this.testCase.method === 'auto') {
|
if (this.testCase.method === 'auto') {
|
||||||
if (this.$refs.apiTestDetail && this.testCase.type === 'api') {
|
if (this.$refs.apiTestDetail && this.testCase.type === 'api') {
|
||||||
|
|
||||||
this.$refs.apiTestDetail.init();
|
this.$refs.apiTestDetail.init();
|
||||||
} else if (this.testCase.type === 'performance') {
|
} else if (this.testCase.type === 'performance') {
|
||||||
this.$refs.performanceTestDetail.init();
|
this.$refs.performanceTestDetail.init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
testRun(reportId) {
|
testRun(reportId) {
|
||||||
|
@ -546,13 +551,12 @@ export default {
|
||||||
this.$post('/test/plan/case/edit', {id: this.testCase.id, reportId: reportId});
|
this.$post('/test/plan/case/edit', {id: this.testCase.id, reportId: reportId});
|
||||||
},
|
},
|
||||||
initData(testCase) {
|
initData(testCase) {
|
||||||
this.result = this.$post('/test/plan/case/list/all', this.searchParam, response => {
|
this.result = this.$post('/test/plan/case/list/ids', this.searchParam, response => {
|
||||||
this.testCases = response.data;
|
this.testCases = response.data;
|
||||||
for (let i = 0; i < this.testCases.length; i++) {
|
for (let i = 0; i < this.testCases.length; i++) {
|
||||||
if (this.testCases[i].id === testCase.id) {
|
if (this.testCases[i].id === testCase.id) {
|
||||||
this.index = i;
|
this.index = i;
|
||||||
this.getTestCase(i);
|
this.getTestCase(i);
|
||||||
this.getRelatedTest();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,7 +11,7 @@ import YanProgress from 'yan-progress';
|
||||||
import './permission' // permission control
|
import './permission' // permission control
|
||||||
import i18n from "../i18n/i18n";
|
import i18n from "../i18n/i18n";
|
||||||
import store from "./store";
|
import store from "./store";
|
||||||
import {permission, roles} from './permission'
|
import {permission, roles, xpack} from './permission'
|
||||||
import chart from "../common/js/chart";
|
import chart from "../common/js/chart";
|
||||||
import CalendarHeatmap from "../common/js/calendar-heatmap";
|
import CalendarHeatmap from "../common/js/calendar-heatmap";
|
||||||
import '../common/css/menu-header.css';
|
import '../common/css/menu-header.css';
|
||||||
|
@ -37,6 +37,8 @@ Vue.directive('permission', permission);
|
||||||
// v-roles
|
// v-roles
|
||||||
Vue.directive('roles', roles);
|
Vue.directive('roles', roles);
|
||||||
|
|
||||||
|
Vue.directive('xpack', xpack);
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#app',
|
el: '#app',
|
||||||
router,
|
router,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import router from './components/common/router/router'
|
import router from './components/common/router/router'
|
||||||
import {TokenKey} from '@/common/js/constants';
|
import {TokenKey} from '@/common/js/constants';
|
||||||
import {hasRolePermissions, hasRoles} from "@/common/js/utils";
|
import {hasLicense, hasRolePermissions, hasRoles} from "@/common/js/utils";
|
||||||
import NProgress from 'nprogress' // progress bar
|
import NProgress from 'nprogress' // progress bar
|
||||||
import 'nprogress/nprogress.css' // progress bar style
|
import 'nprogress/nprogress.css' // progress bar style
|
||||||
const whiteList = ['/login']; // no redirect whitelist
|
const whiteList = ['/login']; // no redirect whitelist
|
||||||
|
@ -19,6 +19,20 @@ export const roles = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const xpack = {
|
||||||
|
inserted(el, binding) {
|
||||||
|
checkLicense(el, binding);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function checkLicense(el, binding, type) {
|
||||||
|
let v = hasLicense()
|
||||||
|
|
||||||
|
if (v) {
|
||||||
|
el.parentNode && el.parentNode.removeChild(el)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function checkRolePermission(el, binding, type) {
|
function checkRolePermission(el, binding, type) {
|
||||||
const {value} = binding;
|
const {value} = binding;
|
||||||
if (value && value instanceof Array && value.length > 0) {
|
if (value && value instanceof Array && value.length > 0) {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import {
|
import {
|
||||||
|
LicenseKey,
|
||||||
REFRESH_SESSION_USER_URL,
|
REFRESH_SESSION_USER_URL,
|
||||||
ROLE_ORG_ADMIN,
|
|
||||||
ROLE_ADMIN,
|
ROLE_ADMIN,
|
||||||
|
ROLE_ORG_ADMIN,
|
||||||
ROLE_TEST_MANAGER,
|
ROLE_TEST_MANAGER,
|
||||||
ROLE_TEST_USER,
|
ROLE_TEST_USER,
|
||||||
ROLE_TEST_VIEWER,
|
ROLE_TEST_VIEWER,
|
||||||
TokenKey,
|
TokenKey
|
||||||
LicenseKey
|
|
||||||
} from "./constants";
|
} from "./constants";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {jsPDF} from "jspdf";
|
import {jsPDF} from "jspdf";
|
||||||
|
@ -45,6 +45,11 @@ export function hasRolePermission(role) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function hasLicense() {
|
||||||
|
let v = localStorage.getItem(LicenseKey);
|
||||||
|
return v === 'valid';
|
||||||
|
}
|
||||||
|
|
||||||
//是否含有对应组织或工作空间的角色
|
//是否含有对应组织或工作空间的角色
|
||||||
export function hasRolePermissions(...roles) {
|
export function hasRolePermissions(...roles) {
|
||||||
for (let role of roles) {
|
for (let role of roles) {
|
||||||
|
@ -238,7 +243,7 @@ export function exportPdf(name, canvasList) {
|
||||||
|
|
||||||
// html页面生成的canvas在pdf中图片的宽高
|
// html页面生成的canvas在pdf中图片的宽高
|
||||||
let imgWidth = a4Width;
|
let imgWidth = a4Width;
|
||||||
let imgHeight = a4Width/contentWidth * contentHeight;
|
let imgHeight = a4Width / contentWidth * contentHeight;
|
||||||
|
|
||||||
let pageData = canvas.toDataURL('image/jpeg', 1.0);
|
let pageData = canvas.toDataURL('image/jpeg', 1.0);
|
||||||
|
|
||||||
|
@ -251,7 +256,7 @@ export function exportPdf(name, canvasList) {
|
||||||
if (leftHeight > blankHeight) {
|
if (leftHeight > blankHeight) {
|
||||||
//页面偏移
|
//页面偏移
|
||||||
let position = 0;
|
let position = 0;
|
||||||
while(leftHeight > 0) {
|
while (leftHeight > 0) {
|
||||||
// 本次添加占用的高度
|
// 本次添加占用的高度
|
||||||
let occupation = a4Height - currentHeight;
|
let occupation = a4Height - currentHeight;
|
||||||
pdf.addImage(pageData, 'JPEG', 0, position + currentHeight, imgWidth, imgHeight);
|
pdf.addImage(pageData, 'JPEG', 0, position + currentHeight, imgWidth, imgHeight);
|
||||||
|
@ -259,7 +264,7 @@ export function exportPdf(name, canvasList) {
|
||||||
leftHeight -= occupation;
|
leftHeight -= occupation;
|
||||||
position -= occupation;
|
position -= occupation;
|
||||||
//避免添加空白页
|
//避免添加空白页
|
||||||
if(leftHeight > 0) {
|
if (leftHeight > 0) {
|
||||||
pdf.addPage();
|
pdf.addPage();
|
||||||
currentHeight = 0;
|
currentHeight = 0;
|
||||||
}
|
}
|
||||||
|
@ -277,15 +282,15 @@ export function exportPdf(name, canvasList) {
|
||||||
|
|
||||||
export function windowPrint(id, zoom) {
|
export function windowPrint(id, zoom) {
|
||||||
//根据div标签ID拿到div中的局部内容
|
//根据div标签ID拿到div中的局部内容
|
||||||
let bdhtml=window.document.body.innerHTML;
|
let bdhtml = window.document.body.innerHTML;
|
||||||
let el = document.getElementById(id);
|
let el = document.getElementById(id);
|
||||||
var jubuData = el.innerHTML;
|
var jubuData = el.innerHTML;
|
||||||
document.getElementsByTagName('body')[0].style.zoom=zoom;
|
document.getElementsByTagName('body')[0].style.zoom = zoom;
|
||||||
//把获取的 局部div内容赋给body标签, 相当于重置了 body里的内容
|
//把获取的 局部div内容赋给body标签, 相当于重置了 body里的内容
|
||||||
window.document.body.innerHTML= jubuData;
|
window.document.body.innerHTML = jubuData;
|
||||||
//调用打印功能
|
//调用打印功能
|
||||||
window.print();
|
window.print();
|
||||||
window.document.body.innerHTML=bdhtml;//重新给页面内容赋值;
|
window.document.body.innerHTML = bdhtml;//重新给页面内容赋值;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue