Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
9d5d60c99a
|
@ -26,6 +26,7 @@ import io.metersphere.dto.ScheduleDao;
|
||||||
import io.metersphere.performance.service.PerformanceTestService;
|
import io.metersphere.performance.service.PerformanceTestService;
|
||||||
import io.metersphere.service.CheckPermissionService;
|
import io.metersphere.service.CheckPermissionService;
|
||||||
import io.metersphere.service.ScheduleService;
|
import io.metersphere.service.ScheduleService;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.jorphan.collections.HashTree;
|
import org.apache.jorphan.collections.HashTree;
|
||||||
import org.apache.shiro.authz.annotation.Logical;
|
import org.apache.shiro.authz.annotation.Logical;
|
||||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
|
@ -342,12 +343,16 @@ public class APITestController {
|
||||||
return returnList;
|
return returnList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/runningTask/{projectID}")
|
@GetMapping("/runningTask/{projectID}/{callFrom}")
|
||||||
public List<TaskInfoResult> runningTask(@PathVariable String projectID) {
|
public List<TaskInfoResult> runningTask(@PathVariable String projectID, @PathVariable String callFrom) {
|
||||||
List<String> typeFilter = Arrays.asList( // 首页显示的运行中定时任务,只要这3种,不需要 性能测试、api_test(旧版)
|
List<String> typeFilter = new ArrayList<>();
|
||||||
ScheduleGroup.API_SCENARIO_TEST.name(),
|
if(StringUtils.equals(callFrom, "api_test")) { // 接口测试首页显示的运行中定时任务,只要这3种,不需要 性能测试、api_test(旧版)
|
||||||
ScheduleGroup.SWAGGER_IMPORT.name(),
|
typeFilter.add(ScheduleGroup.API_SCENARIO_TEST.name());
|
||||||
ScheduleGroup.TEST_PLAN_TEST.name());
|
typeFilter.add(ScheduleGroup.SWAGGER_IMPORT.name());
|
||||||
|
typeFilter.add(ScheduleGroup.TEST_PLAN_TEST.name());
|
||||||
|
} else if(StringUtils.equals(callFrom, "track_home")) { // 测试跟踪首页只显示测试计划的定时任务
|
||||||
|
typeFilter.add(ScheduleGroup.TEST_PLAN_TEST.name());
|
||||||
|
}
|
||||||
List<TaskInfoResult> resultList = scheduleService.findRunningTaskInfoByProjectID(projectID, typeFilter);
|
List<TaskInfoResult> resultList = scheduleService.findRunningTaskInfoByProjectID(projectID, typeFilter);
|
||||||
int dataIndex = 1;
|
int dataIndex = 1;
|
||||||
for (TaskInfoResult taskInfo :
|
for (TaskInfoResult taskInfo :
|
||||||
|
|
|
@ -22,9 +22,9 @@ public class MsDefinitionParser extends MsAbstractParser<ApiDefinitionImport> {
|
||||||
String testStr = getApiTestStr(source);
|
String testStr = getApiTestStr(source);
|
||||||
JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField);
|
JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField);
|
||||||
this.projectId = request.getProjectId();
|
this.projectId = request.getProjectId();
|
||||||
if (testObject.get("projectName") != null || testObject.get("projectId") != null ) {
|
if (testObject.get("projectName") != null || testObject.get("projectId") != null ) {// metersphere 格式导入
|
||||||
return parseMsFormat(testStr, request);
|
return parseMsFormat(testStr, request);
|
||||||
} else {
|
} else { // chrome 插件录制格式导入
|
||||||
request.setPlatform(ApiImportPlatform.Plugin.name());
|
request.setPlatform(ApiImportPlatform.Plugin.name());
|
||||||
ApiDefinitionImport apiImport = new ApiDefinitionImport();
|
ApiDefinitionImport apiImport = new ApiDefinitionImport();
|
||||||
apiImport.setProtocol(RequestType.HTTP);
|
apiImport.setProtocol(RequestType.HTTP);
|
||||||
|
|
|
@ -216,6 +216,7 @@ public class ApiDefinitionService {
|
||||||
ApiDefinitionExample example = new ApiDefinitionExample();
|
ApiDefinitionExample example = new ApiDefinitionExample();
|
||||||
if (request.getProtocol().equals(RequestType.HTTP)) {
|
if (request.getProtocol().equals(RequestType.HTTP)) {
|
||||||
example.createCriteria().andMethodEqualTo(request.getMethod()).andStatusNotEqualTo("Trash")
|
example.createCriteria().andMethodEqualTo(request.getMethod()).andStatusNotEqualTo("Trash")
|
||||||
|
.andPathEqualTo(request.getPath())
|
||||||
.andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId());
|
.andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId());
|
||||||
return apiDefinitionMapper.selectByExample(example);
|
return apiDefinitionMapper.selectByExample(example);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -69,17 +69,18 @@
|
||||||
sch.id AS taskID,
|
sch.id AS taskID,
|
||||||
sch.`value` AS rule,
|
sch.`value` AS rule,
|
||||||
sch.`enable` AS `taskStatus`,
|
sch.`enable` AS `taskStatus`,
|
||||||
u.name AS creator,
|
u.`name` AS creator,
|
||||||
sch.update_time AS updateTime,
|
sch.update_time AS updateTime,
|
||||||
sch.type AS taskType,
|
sch.type AS taskType,
|
||||||
sch.group AS taskGroup
|
sch.`group` AS taskGroup,
|
||||||
|
sch.resource_id AS scenarioId
|
||||||
FROM (
|
FROM (
|
||||||
schedule sch left join user u
|
schedule sch left join user u
|
||||||
ON sch.user_id = u.id
|
ON sch.user_id = u.id
|
||||||
)
|
)
|
||||||
WHERE sch.`enable` = true
|
WHERE sch.`enable` = true
|
||||||
AND sch.project_id = #{projectId,jdbcType=VARCHAR}
|
AND sch.project_id = #{projectId,jdbcType=VARCHAR}
|
||||||
and sch.group in
|
and sch.`group` in
|
||||||
<foreach collection="types" item="item" separator="," open="(" close=")">
|
<foreach collection="types" item="item" separator="," open="(" close=")">
|
||||||
#{item}
|
#{item}
|
||||||
</foreach>
|
</foreach>
|
||||||
|
|
|
@ -8,7 +8,7 @@ import java.util.List;
|
||||||
|
|
||||||
public interface ExtTestPlanLoadCaseMapper {
|
public interface ExtTestPlanLoadCaseMapper {
|
||||||
|
|
||||||
List<String> selectIdsNotInPlan(@Param("projectId") String projectId, @Param("planId") String planId);
|
List<String> selectIdsNotInPlan(@Param("request") LoadCaseRequest request);
|
||||||
List<TestPlanLoadCaseDTO> selectTestPlanLoadCaseList(@Param("request") LoadCaseRequest request);
|
List<TestPlanLoadCaseDTO> selectTestPlanLoadCaseList(@Param("request") LoadCaseRequest request);
|
||||||
void updateCaseStatus(@Param("reportId") String reportId, @Param("status") String status);
|
void updateCaseStatus(@Param("reportId") String reportId, @Param("status") String status);
|
||||||
List<String> getStatusByTestPlanId(@Param("planId") String planId);
|
List<String> getStatusByTestPlanId(@Param("planId") String planId);
|
||||||
|
|
|
@ -10,9 +10,12 @@
|
||||||
<select id="selectIdsNotInPlan" resultType="java.lang.String">
|
<select id="selectIdsNotInPlan" resultType="java.lang.String">
|
||||||
select load_test.id
|
select load_test.id
|
||||||
from load_test
|
from load_test
|
||||||
where load_test.project_id = #{projectId}
|
where load_test.project_id = #{request.projectId}
|
||||||
|
<if test="request.name != null and request.name != ''">
|
||||||
|
and load_test.name like CONCAT('%', #{request.name},'%')
|
||||||
|
</if>
|
||||||
and load_test.id not in (
|
and load_test.id not in (
|
||||||
select tplc.load_case_id from test_plan_load_case tplc where tplc.test_plan_id = #{planId}
|
select tplc.load_case_id from test_plan_load_case tplc where tplc.test_plan_id = #{request.testPlanId}
|
||||||
)
|
)
|
||||||
</select>
|
</select>
|
||||||
<select id="selectTestPlanLoadCaseList" resultType="io.metersphere.track.dto.TestPlanLoadCaseDTO">
|
<select id="selectTestPlanLoadCaseList" resultType="io.metersphere.track.dto.TestPlanLoadCaseDTO">
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class TestPlanLoadCaseService {
|
||||||
private LoadTestMapper loadTestMapper;
|
private LoadTestMapper loadTestMapper;
|
||||||
|
|
||||||
public List<LoadTest> relevanceList(LoadCaseRequest request) {
|
public List<LoadTest> relevanceList(LoadCaseRequest request) {
|
||||||
List<String> ids = extTestPlanLoadCaseMapper.selectIdsNotInPlan(request.getProjectId(), request.getTestPlanId());
|
List<String> ids = extTestPlanLoadCaseMapper.selectIdsNotInPlan(request);
|
||||||
if (CollectionUtils.isEmpty(ids)) {
|
if (CollectionUtils.isEmpty(ids)) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,7 +194,6 @@ public class TestPlanService {
|
||||||
testPlan.setActualEndTime(System.currentTimeMillis());
|
testPlan.setActualEndTime(System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
extScheduleMapper.updateNameByResourceID(testPlan.getId(), testPlan.getName());// 同步更新该测试的定时任务的name
|
|
||||||
|
|
||||||
List<String> userIds = new ArrayList<>();
|
List<String> userIds = new ArrayList<>();
|
||||||
userIds.add(testPlan.getPrincipal());
|
userIds.add(testPlan.getPrincipal());
|
||||||
|
@ -204,6 +203,7 @@ public class TestPlanService {
|
||||||
i = testPlanMapper.updateByPrimaryKeySelective(testPlan);
|
i = testPlanMapper.updateByPrimaryKeySelective(testPlan);
|
||||||
}
|
}
|
||||||
else { // 有修改字段的调用,为保证将某些时间置null的情况,使用updateByPrimaryKey
|
else { // 有修改字段的调用,为保证将某些时间置null的情况,使用updateByPrimaryKey
|
||||||
|
extScheduleMapper.updateNameByResourceID(testPlan.getId(), testPlan.getName());// 同步更新该测试的定时任务的name
|
||||||
i = testPlanMapper.updateByPrimaryKey(testPlan); // 更新
|
i = testPlanMapper.updateByPrimaryKey(testPlan); // 更新
|
||||||
}
|
}
|
||||||
if (!StringUtils.isBlank(testPlan.getStatus())) {
|
if (!StringUtils.isBlank(testPlan.getStatus())) {
|
||||||
|
|
|
@ -127,11 +127,18 @@ export default {
|
||||||
let param = {};
|
let param = {};
|
||||||
param.taskID = this.schedule.id;
|
param.taskID = this.schedule.id;
|
||||||
param.enable = flag;
|
param.enable = flag;
|
||||||
|
let that = this;
|
||||||
if(flag == false) {
|
if(flag == false) {
|
||||||
this.$confirm(this.$t('api_test.home_page.running_task_list.confirm.close_title'), this.$t('commons.prompt'), {
|
this.$confirm(this.$t('api_test.home_page.running_task_list.confirm.close_title'), this.$t('commons.prompt'), {
|
||||||
confirmButtonText: this.$t('commons.confirm'),
|
confirmButtonText: this.$t('commons.confirm'),
|
||||||
cancelButtonText: this.$t('commons.cancel'),
|
cancelButtonText: this.$t('commons.cancel'),
|
||||||
type: 'warning'
|
type: 'warning',
|
||||||
|
beforeClose(action, instance, done) {
|
||||||
|
if(action == 'cancel') { // 否则在 messageBox 点击取消后,switch 按钮仍然会被关闭
|
||||||
|
that.schedule.enable = param.enable = true;
|
||||||
|
}
|
||||||
|
done(); // done 是关闭 messageBox 的行为
|
||||||
|
},
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.updateTask(param);
|
this.updateTask(param);
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
|
|
|
@ -240,7 +240,6 @@ import MsTabButton from "@/business/components/common/components/MsTabButton";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
changeRedirectParam(redirectIDParam) {
|
changeRedirectParam(redirectIDParam) {
|
||||||
this.redirectID = redirectIDParam;
|
this.redirectID = redirectIDParam;
|
||||||
},
|
},
|
||||||
|
@ -349,7 +348,7 @@ import MsTabButton from "@/business/components/common/components/MsTabButton";
|
||||||
this.showCasePage = true;
|
this.showCasePage = true;
|
||||||
},
|
},
|
||||||
exportAPI(type) {
|
exportAPI(type) {
|
||||||
if (!this.isApiListEnable) {
|
if (this.activeDom !== 'left') {
|
||||||
this.$warning('用例列表暂不支持导出,请切换成接口列表');
|
this.$warning('用例列表暂不支持导出,请切换成接口列表');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
<ms-failure-test-case-list @redirectPage="redirectPage"/>
|
<ms-failure-test-case-list @redirectPage="redirectPage"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<ms-running-task-list @redirectPage="redirectPage"/>
|
<ms-running-task-list :call-from="'api_test'" @redirectPage="redirectPage"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,9 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
MsTag
|
MsTag
|
||||||
},
|
},
|
||||||
|
props: {
|
||||||
|
callFrom: String,
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
value: '100',
|
value: '100',
|
||||||
|
@ -84,7 +86,7 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
search() {
|
search() {
|
||||||
let projectID = getCurrentProjectID();
|
let projectID = getCurrentProjectID();
|
||||||
this.result = this.$get("/api/runningTask/"+projectID, response => {
|
this.result = this.$get("/api/runningTask/"+projectID+"/"+this.callFrom, response => {
|
||||||
this.tableData = response.data;
|
this.tableData = response.data;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -109,9 +111,9 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
redirect(param){
|
redirect(param){
|
||||||
if(param.taskType === 'testPlan'){
|
if(param.taskGroup === 'TEST_PLAN_TEST'){
|
||||||
this.$emit('redirectPage','testPlanEdit','', param.scenarioId);
|
this.$emit('redirectPage','testPlanEdit','', param.scenarioId);
|
||||||
}else{
|
}else if(param.taskGroup === 'API_SCENARIO_TEST') {
|
||||||
this.$emit('redirectPage','scenario','scenario', 'edit:'+param.scenarioId);
|
this.$emit('redirectPage','scenario','scenario', 'edit:'+param.scenarioId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,29 +46,10 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
importJsonTest: {
|
|
||||||
"root": {
|
|
||||||
"data": {
|
|
||||||
"text": "test111"
|
|
||||||
},
|
|
||||||
"children": [
|
|
||||||
{ "data": { "text": "新闻"}},
|
|
||||||
{ "data": { "text": "网页"} },
|
|
||||||
{ "data": { "text": "贴吧"} },
|
|
||||||
{ "data": { "text": "知道"} },
|
|
||||||
{ "data": { "text": "音乐" } },
|
|
||||||
{ "data": { "text": "图片"} },
|
|
||||||
{ "data": { "text": "视频"} },
|
|
||||||
{ "data": { "text": "地图" } },
|
|
||||||
{ "data": { "text": "百科","expandState":"collapse"}}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"template":"default"
|
|
||||||
},
|
|
||||||
importJson: {
|
importJson: {
|
||||||
root: {
|
root: {
|
||||||
data: {
|
data: {
|
||||||
text: "全部用例",
|
text: this.$t('test_track.review_view.all_case'),
|
||||||
disable: true,
|
disable: true,
|
||||||
id: "root",
|
id: "root",
|
||||||
path: ""
|
path: ""
|
||||||
|
|
|
@ -18,10 +18,10 @@
|
||||||
<el-tab-pane name="default" :label="$t('api_test.definition.case_title')">
|
<el-tab-pane name="default" :label="$t('api_test.definition.case_title')">
|
||||||
<ms-tab-button
|
<ms-tab-button
|
||||||
:active-dom.sync="activeDom"
|
:active-dom.sync="activeDom"
|
||||||
:left-tip="'用例列表'"
|
:left-tip="$t('api_test.definition.case_title')"
|
||||||
:left-content="'CASE'"
|
:left-content="'CASE'"
|
||||||
:right-tip="'脑图'"
|
:right-tip="$t('test_track.case.minder')"
|
||||||
:right-content="'脑图'"
|
:right-content="$t('test_track.case.minder')"
|
||||||
:middle-button-enable="false">
|
:middle-button-enable="false">
|
||||||
<test-case-list
|
<test-case-list
|
||||||
v-if="activeDom === 'left'"
|
v-if="activeDom === 'left'"
|
||||||
|
|
|
@ -18,7 +18,7 @@ name: "TestCaseMinder",
|
||||||
return{
|
return{
|
||||||
testCase: [],
|
testCase: [],
|
||||||
dataMap: new Map(),
|
dataMap: new Map(),
|
||||||
tags: ['用例', '前置条件', '备注'],
|
tags: [this.$t('api_test.definition.request.case'), this.$t('test_track.case.prerequisite'), this.$t('commons.remark')],
|
||||||
result: {}
|
result: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -47,7 +47,6 @@ name: "TestCaseMinder",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
save(data) {
|
save(data) {
|
||||||
console.log(this.dataMap);
|
|
||||||
let saveCases = [];
|
let saveCases = [];
|
||||||
this.buildSaveCase(data.root, saveCases, undefined);
|
this.buildSaveCase(data.root, saveCases, undefined);
|
||||||
let param = {
|
let param = {
|
||||||
|
@ -60,7 +59,7 @@ name: "TestCaseMinder",
|
||||||
},
|
},
|
||||||
buildSaveCase(root, saveCases, parent) {
|
buildSaveCase(root, saveCases, parent) {
|
||||||
let data = root.data;
|
let data = root.data;
|
||||||
if (data.resource && data.resource.indexOf("用例") > -1) {
|
if (data.resource && data.resource.indexOf(this.$t('api_test.definition.request.case')) > -1) {
|
||||||
this._buildSaveCase(root, saveCases, parent);
|
this._buildSaveCase(root, saveCases, parent);
|
||||||
} else {
|
} else {
|
||||||
if (root.children) {
|
if (root.children) {
|
||||||
|
@ -92,9 +91,9 @@ name: "TestCaseMinder",
|
||||||
if (node.children) {
|
if (node.children) {
|
||||||
node.children.forEach((childNode) => {
|
node.children.forEach((childNode) => {
|
||||||
let childData = childNode.data;
|
let childData = childNode.data;
|
||||||
if (childData.resource && childData.resource.indexOf('前置条件') > -1) {
|
if (childData.resource && childData.resource.indexOf(this.$t('test_track.case.prerequisite')) > -1) {
|
||||||
testCase.prerequisite = childData.text;
|
testCase.prerequisite = childData.text;
|
||||||
} else if (childData.resource && childData.resource.indexOf('备注') > -1) {
|
} else if (childData.resource && childData.resource.indexOf(this.$t('commons.remark')) > -1) {
|
||||||
testCase.remark = childData.text;
|
testCase.remark = childData.text;
|
||||||
} else {
|
} else {
|
||||||
// 测试步骤
|
// 测试步骤
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
:tree-nodes="treeNodes"
|
:tree-nodes="treeNodes"
|
||||||
:data-map="dataMap"
|
:data-map="dataMap"
|
||||||
:tags="tags"
|
:tags="tags"
|
||||||
:distinct-tags="[...tags, '未开始']"
|
:distinct-tags="[...tags, $t('test_track.plan.plan_status_prepare')]"
|
||||||
@save="save"
|
@save="save"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
@ -19,7 +19,7 @@ name: "TestPlanMinder",
|
||||||
return{
|
return{
|
||||||
dataMap: new Map(),
|
dataMap: new Map(),
|
||||||
result: {},
|
result: {},
|
||||||
tags: ['通过', '失败', '阻塞', '跳过'],
|
tags: [this.$t('test_track.plan_view.pass'), this.$t('test_track.plan_view.failure'), this.$t('test_track.plan_view.blocking'), this.$t('test_track.plan_view.skip')],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
@ -48,15 +48,15 @@ name: "TestPlanMinder",
|
||||||
this.result = this.$get('/test/plan/case/list/minder/' + this.planId, response => {
|
this.result = this.$get('/test/plan/case/list/minder/' + this.planId, response => {
|
||||||
this.dataMap = getTestCaseDataMap(response.data, true, (data, item) => {
|
this.dataMap = getTestCaseDataMap(response.data, true, (data, item) => {
|
||||||
if (item.stats === 'Pass') {
|
if (item.stats === 'Pass') {
|
||||||
data.resource.push("通过");
|
data.resource.push(this.$t('test_track.plan_view.pass'));
|
||||||
} else if (item.reviewStatus === 'Failure') {
|
} else if (item.reviewStatus === 'Failure') {
|
||||||
data.resource.push("失败");
|
data.resource.push(this.$t('test_track.plan_view.failure'));
|
||||||
} else if (item.reviewStatus === 'Blocking') {
|
} else if (item.reviewStatus === 'Blocking') {
|
||||||
data.resource.push("阻塞");
|
data.resource.push(this.$t('test_track.plan_view.blocking'));
|
||||||
} else if (item.reviewStatus === 'Skip') {
|
} else if (item.reviewStatus === 'Skip') {
|
||||||
data.resource.push("跳过");
|
data.resource.push(this.$t('test_track.plan_view.skip'));
|
||||||
} else {
|
} else {
|
||||||
data.resource.push("未开始");
|
data.resource.push(this.$t('test_track.plan.plan_status_prepare'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -71,7 +71,7 @@ name: "TestPlanMinder",
|
||||||
},
|
},
|
||||||
buildSaveCase(root, saveCases) {
|
buildSaveCase(root, saveCases) {
|
||||||
let data = root.data;
|
let data = root.data;
|
||||||
if (data.resource && data.resource.indexOf("用例") > -1) {
|
if (data.resource && data.resource.indexOf(this.$t('api_test.definition.request.case')) > -1) {
|
||||||
this._buildSaveCase(root, saveCases, parent);
|
this._buildSaveCase(root, saveCases, parent);
|
||||||
} else {
|
} else {
|
||||||
if (root.children) {
|
if (root.children) {
|
||||||
|
@ -90,13 +90,13 @@ name: "TestPlanMinder",
|
||||||
id: data.id,
|
id: data.id,
|
||||||
};
|
};
|
||||||
if (data.resource.length > 1) {
|
if (data.resource.length > 1) {
|
||||||
if (data.resource.indexOf('失败') > -1) {
|
if (data.resource.indexOf(this.$t('test_track.plan_view.failure')) > -1) {
|
||||||
testCase.status = 'Failure';
|
testCase.status = 'Failure';
|
||||||
} else if (data.resource.indexOf('通过') > -1) {
|
} else if (data.resource.indexOf(this.$t('test_track.plan_view.pass')) > -1) {
|
||||||
testCase.status = 'Pass';
|
testCase.status = 'Pass';
|
||||||
} else if (data.resource.indexOf('阻塞') > -1) {
|
} else if (data.resource.indexOf(this.$t('test_track.plan_view.blocking')) > -1) {
|
||||||
testCase.status = 'Blocking';
|
testCase.status = 'Blocking';
|
||||||
} else if (data.resource.indexOf('跳过') > -1) {
|
} else if (data.resource.indexOf(this.$t('test_track.plan_view.skip')) > -1) {
|
||||||
testCase.status = 'Skip';
|
testCase.status = 'Skip';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
:tree-nodes="treeNodes"
|
:tree-nodes="treeNodes"
|
||||||
:data-map="dataMap"
|
:data-map="dataMap"
|
||||||
:tags="tags"
|
:tags="tags"
|
||||||
:distinct-tags="[...tags, '未开始']"
|
:distinct-tags="[...tags, $t('test_track.plan.plan_status_prepare')]"
|
||||||
@save="save"
|
@save="save"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
@ -18,7 +18,7 @@ name: "TestReviewMinder",
|
||||||
data() {
|
data() {
|
||||||
return{
|
return{
|
||||||
dataMap: new Map(),
|
dataMap: new Map(),
|
||||||
tags: ['通过', '不通过'],
|
tags: [this.$t('test_track.plan_view.pass'), this.$t('test_track.plan_view.not_pass')],
|
||||||
result: {}
|
result: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -48,11 +48,11 @@ name: "TestReviewMinder",
|
||||||
this.result = this.$post('/test/review/case/list/all', {reviewId: this.reviewId}, response => {
|
this.result = this.$post('/test/review/case/list/all', {reviewId: this.reviewId}, response => {
|
||||||
this.dataMap = getTestCaseDataMap(response.data, true, (data, item) => {
|
this.dataMap = getTestCaseDataMap(response.data, true, (data, item) => {
|
||||||
if (item.reviewStatus === 'Pass') {
|
if (item.reviewStatus === 'Pass') {
|
||||||
data.resource.push("通过");
|
data.resource.push(this.$t('test_track.plan_view.pass'));
|
||||||
} else if (item.reviewStatus === 'UnPass') {
|
} else if (item.reviewStatus === 'UnPass') {
|
||||||
data.resource.push("不通过");
|
data.resource.push(this.$t('test_track.plan_view.not_pass'));
|
||||||
} else {
|
} else {
|
||||||
data.resource.push("未开始");
|
data.resource.push(this.$t('test_track.plan.plan_status_prepare'));
|
||||||
}
|
}
|
||||||
data.caseId = item.caseId;
|
data.caseId = item.caseId;
|
||||||
});
|
});
|
||||||
|
@ -68,7 +68,7 @@ name: "TestReviewMinder",
|
||||||
},
|
},
|
||||||
buildSaveCase(root, saveCases) {
|
buildSaveCase(root, saveCases) {
|
||||||
let data = root.data;
|
let data = root.data;
|
||||||
if (data.resource && data.resource.indexOf("用例") > -1) {
|
if (data.resource && data.resource.indexOf(this.$t('api_test.definition.request.case')) > -1) {
|
||||||
this._buildSaveCase(root, saveCases);
|
this._buildSaveCase(root, saveCases);
|
||||||
} else {
|
} else {
|
||||||
if (root.children) {
|
if (root.children) {
|
||||||
|
@ -89,9 +89,9 @@ name: "TestReviewMinder",
|
||||||
// name: data.text,
|
// name: data.text,
|
||||||
};
|
};
|
||||||
if (data.resource.length > 1) {
|
if (data.resource.length > 1) {
|
||||||
if (data.resource.indexOf('不通过') > -1) {
|
if (data.resource.indexOf(this.$t('test_track.plan_view.not_pass')) > -1) {
|
||||||
testCase.status = 'UnPass';
|
testCase.status = 'UnPass';
|
||||||
} else if (data.resource.indexOf('通过') > -1) {
|
} else if (data.resource.indexOf(this.$t('test_track.plan_view.pass')) > -1) {
|
||||||
testCase.status = 'Pass';
|
testCase.status = 'Pass';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<ms-tag v-if="value == 'Prepare'" type="info" :content="$t('test_track.plan.plan_status_prepare')"/>
|
<ms-tag v-if="value == 'Prepare'" type="info" :content="$t('test_track.plan.plan_status_prepare')"/>
|
||||||
<ms-tag v-if="value == 'Underway'" type="primary" :content="$t('test_track.plan.plan_status_running')"/>
|
<ms-tag v-if="value == 'Underway'" type="primary" :content="$t('test_track.plan.plan_status_running')"/>
|
||||||
<ms-tag v-if="value == 'Pass'" type="success" :content="$t('test_track.plan_view.pass')"/>
|
<ms-tag v-if="value == 'Pass'" type="success" :content="$t('test_track.plan_view.pass')"/>
|
||||||
<ms-tag v-if="value == 'UnPass'" type="danger" content="未通过"/>
|
<ms-tag v-if="value == 'UnPass'" type="danger" content="$t('test_track.plan_view.not_pass')"/>
|
||||||
<ms-tag v-if="value == 'Failure'" type="danger" :content="$t('test_track.plan_view.failure')"/>
|
<ms-tag v-if="value == 'Failure'" type="danger" :content="$t('test_track.plan_view.failure')"/>
|
||||||
<ms-tag v-if="value == 'Blocking'" type="warning" :content="$t('test_track.plan_view.blocking')"/>
|
<ms-tag v-if="value == 'Blocking'" type="warning" :content="$t('test_track.plan_view.blocking')"/>
|
||||||
<ms-tag v-if="value == 'Skip'" type="info" :content="$t('test_track.plan_view.skip')"/>
|
<ms-tag v-if="value == 'Skip'" type="info" :content="$t('test_track.plan_view.skip')"/>
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
<review-list class="track-card"/>
|
<review-list class="track-card"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<ms-running-task-list class="track-card"/>
|
<ms-running-task-list :call-from="'track_home'" class="track-card" @redirectPage="redirectPage"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ import MsMainContainer from "@/business/components/common/components/MsMainConta
|
||||||
import MsContainer from "@/business/components/common/components/MsContainer";
|
import MsContainer from "@/business/components/common/components/MsContainer";
|
||||||
import CaseCountCard from "@/business/components/track/home/components/CaseCountCard";
|
import CaseCountCard from "@/business/components/track/home/components/CaseCountCard";
|
||||||
import RelevanceCaseCard from "@/business/components/track/home/components/RelevanceCaseCard";
|
import RelevanceCaseCard from "@/business/components/track/home/components/RelevanceCaseCard";
|
||||||
import {getCurrentProjectID, getUUID} from "@/common/js/utils";
|
import {getCurrentProjectID,getUUID} from "@/common/js/utils";
|
||||||
import CaseMaintenance from "@/business/components/track/home/components/CaseMaintenance";
|
import CaseMaintenance from "@/business/components/track/home/components/CaseMaintenance";
|
||||||
import {COUNT_NUMBER, COUNT_NUMBER_SHALLOW} from "@/common/js/constants";
|
import {COUNT_NUMBER, COUNT_NUMBER_SHALLOW} from "@/common/js/constants";
|
||||||
import BugCountCard from "@/business/components/track/home/components/BugCountCard";
|
import BugCountCard from "@/business/components/track/home/components/BugCountCard";
|
||||||
|
@ -187,6 +187,8 @@ export default {
|
||||||
this.caseOption = option;
|
this.caseOption = option;
|
||||||
},
|
},
|
||||||
redirectPage(page,dataType,selectType){
|
redirectPage(page,dataType,selectType){
|
||||||
|
//test_plan 页面跳转
|
||||||
|
this.$router.push('/track/plan/view/'+selectType);
|
||||||
switch (page){
|
switch (page){
|
||||||
case "case":
|
case "case":
|
||||||
this.$router.push({name:'testCase',params:{dataType:dataType,dataSelectRange:selectType, projectId: getCurrentProjectID()}});
|
this.$router.push({name:'testCase',params:{dataType:dataType,dataSelectRange:selectType, projectId: getCurrentProjectID()}});
|
||||||
|
|
|
@ -2,8 +2,17 @@
|
||||||
<div>
|
<div>
|
||||||
<el-card class="table-card" v-loading="result.loading">
|
<el-card class="table-card" v-loading="result.loading">
|
||||||
|
|
||||||
<env-popover :env-map="projectEnvMap" :project-ids="projectIds" @setProjectEnvMap="setProjectEnvMap"
|
<template v-slot:header>
|
||||||
:project-list="projectList" ref="envPopover" class="env-popover"/>
|
<el-row>
|
||||||
|
<el-col :span="8" :offset="11">
|
||||||
|
<el-input :placeholder="$t('api_test.definition.request.select_case')" @blur="search"
|
||||||
|
@keyup.enter.native="search" class="search-input" size="small" v-model="condition.name"/>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<env-popover :env-map="projectEnvMap" :project-ids="projectIds" @setProjectEnvMap="setProjectEnvMap"
|
||||||
|
:project-list="projectList" ref="envPopover" class="env-popover"/>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-table ref="scenarioTable" border :data="tableData" class="adjust-table" @select-all="handleSelectAll" @select="handleSelect">
|
<el-table ref="scenarioTable" border :data="tableData" class="adjust-table" @select-all="handleSelectAll" @select="handleSelect">
|
||||||
<el-table-column type="selection"/>
|
<el-table-column type="selection"/>
|
||||||
|
|
|
@ -11,10 +11,10 @@
|
||||||
<template v-slot:main>
|
<template v-slot:main>
|
||||||
<ms-tab-button
|
<ms-tab-button
|
||||||
:active-dom.sync="activeDom"
|
:active-dom.sync="activeDom"
|
||||||
:left-tip="'用例列表'"
|
:left-tip="$t('api_test.definition.case_title')"
|
||||||
:left-content="'CASE'"
|
:left-content="'CASE'"
|
||||||
:right-tip="'脑图'"
|
:right-tip="$t('test_track.case.minder')"
|
||||||
:right-content="'脑图'"
|
:right-content="$t('test_track.case.minder')"
|
||||||
:middle-button-enable="false">
|
:middle-button-enable="false">
|
||||||
<functional-test-case-list
|
<functional-test-case-list
|
||||||
class="table-list"
|
class="table-list"
|
||||||
|
|
|
@ -13,48 +13,59 @@
|
||||||
ref="nodeTree"/>
|
ref="nodeTree"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<el-card>
|
||||||
|
<template v-slot:header>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="8" :offset="16">
|
||||||
|
<el-input :placeholder="$t('api_test.definition.request.select_case')" @blur="getTestCases"
|
||||||
|
@keyup.enter.native="getTestCases" class="search-input" size="small" v-model="condition.name"/>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-table
|
<el-table
|
||||||
v-loading="result.loading"
|
v-loading="result.loading"
|
||||||
:data="testCases"
|
:data="testCases"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
@select-all="handleSelectAll"
|
@select-all="handleSelectAll"
|
||||||
@select="handleSelectionChange"
|
@select="handleSelectionChange"
|
||||||
height="50vh"
|
height="50vh"
|
||||||
ref="table">
|
ref="table">
|
||||||
<el-table-column
|
<el-table-column
|
||||||
type="selection"/>
|
type="selection"/>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="name"
|
prop="name"
|
||||||
:label="$t('commons.name')"
|
:label="$t('commons.name')"
|
||||||
show-overflow-tooltip>
|
show-overflow-tooltip>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="status"
|
prop="status"
|
||||||
column-key="status"
|
column-key="status"
|
||||||
:filters="statusFilters"
|
:filters="statusFilters"
|
||||||
:label="$t('commons.status')">
|
:label="$t('commons.status')">
|
||||||
<template v-slot:default="{row}">
|
<template v-slot:default="{row}">
|
||||||
<ms-performance-test-status :row="row"/>
|
<ms-performance-test-status :row="row"/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
sortable
|
sortable
|
||||||
prop="createTime"
|
prop="createTime"
|
||||||
:label="$t('commons.create_time')">
|
:label="$t('commons.create_time')">
|
||||||
<template v-slot:default="scope">
|
<template v-slot:default="scope">
|
||||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
sortable
|
sortable
|
||||||
prop="updateTime"
|
prop="updateTime"
|
||||||
:label="$t('commons.update_time')">
|
:label="$t('commons.update_time')">
|
||||||
<template v-slot:default="scope">
|
<template v-slot:default="scope">
|
||||||
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
|
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
|
</el-card>
|
||||||
<ms-table-pagination :change="getTestCases" :current-page.sync="currentPage" :page-size.sync="pageSize"
|
<ms-table-pagination :change="getTestCases" :current-page.sync="currentPage" :page-size.sync="pageSize"
|
||||||
:total="total"/>
|
:total="total"/>
|
||||||
</test-case-relevance-base>
|
</test-case-relevance-base>
|
||||||
|
|
|
@ -13,16 +13,16 @@
|
||||||
class="el-menu-demo header-menu" mode="horizontal" @select="handleSelect"
|
class="el-menu-demo header-menu" mode="horizontal" @select="handleSelect"
|
||||||
:default-active="activeIndex">
|
:default-active="activeIndex">
|
||||||
<el-menu-item index="functional">功能测试用例</el-menu-item>
|
<el-menu-item index="functional">功能测试用例</el-menu-item>
|
||||||
<el-menu-item index="api">接口测试用例</el-menu-item>
|
<!-- <el-menu-item index="api">接口测试用例</el-menu-item>
|
||||||
<el-menu-item index="load">性能测试用例</el-menu-item>
|
<el-menu-item index="load">性能测试用例</el-menu-item>-->
|
||||||
<!-- <el-menu-item index="report">报告统计</el-menu-item>-->
|
<!-- <el-menu-item index="report">报告统计</el-menu-item>-->
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</template>
|
</template>
|
||||||
</ms-test-plan-header-bar>
|
</ms-test-plan-header-bar>
|
||||||
<test-review-function v-if="activeIndex === 'functional'" :redirectCharType="redirectCharType"
|
<test-review-function v-if="activeIndex === 'functional'" :redirectCharType="redirectCharType"
|
||||||
:clickType="clickType" :review-id="reviewId"></test-review-function>
|
:clickType="clickType" :review-id="reviewId"></test-review-function>
|
||||||
<test-review-api v-if="activeIndex === 'api'" :review-id="reviewId"></test-review-api>
|
<!-- <test-review-api v-if="activeIndex === 'api'" :review-id="reviewId"></test-review-api>
|
||||||
<test-review-load v-if="activeIndex === 'load'" :review-id="reviewId"></test-review-load>
|
<test-review-load v-if="activeIndex === 'load'" :review-id="reviewId"></test-review-load>-->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,10 @@
|
||||||
<template v-slot:main>
|
<template v-slot:main>
|
||||||
<ms-tab-button
|
<ms-tab-button
|
||||||
:active-dom.sync="activeDom"
|
:active-dom.sync="activeDom"
|
||||||
:left-tip="'用例列表'"
|
:left-tip="$t('api_test.definition.case_title')"
|
||||||
:left-content="'CASE'"
|
:left-content="'CASE'"
|
||||||
:right-tip="'脑图'"
|
:right-tip="$t('test_track.case.minder')"
|
||||||
:right-content="'脑图'"
|
:right-content="$t('test_track.case.minder')"
|
||||||
:middle-button-enable="false">
|
:middle-button-enable="false">
|
||||||
<test-review-test-case-list
|
<test-review-test-case-list
|
||||||
class="table-list"
|
class="table-list"
|
||||||
|
|
|
@ -82,10 +82,6 @@
|
||||||
</el-container>
|
</el-container>
|
||||||
|
|
||||||
<template v-slot:footer>
|
<template v-slot:footer>
|
||||||
<div style="margin-bottom: 15px">
|
|
||||||
<el-checkbox v-model="checked">同步添加关联的接口和性能测试</el-checkbox>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ms-dialog-footer @cancel="dialogFormVisible = false" @confirm="saveReviewRelevance"/>
|
<ms-dialog-footer @cancel="dialogFormVisible = false" @confirm="saveReviewRelevance"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -203,7 +199,9 @@ export default {
|
||||||
param.reviewId = this.reviewId;
|
param.reviewId = this.reviewId;
|
||||||
param.testCaseIds = [...this.selectIds];
|
param.testCaseIds = [...this.selectIds];
|
||||||
param.request = this.condition;
|
param.request = this.condition;
|
||||||
|
/*
|
||||||
param.checked = this.checked;
|
param.checked = this.checked;
|
||||||
|
*/
|
||||||
// 选择全选则全部加入到评审,无论是否加载完全部
|
// 选择全选则全部加入到评审,无论是否加载完全部
|
||||||
if (this.testReviews.length === param.testCaseIds.length) {
|
if (this.testReviews.length === param.testCaseIds.length) {
|
||||||
param.testCaseIds = ['all'];
|
param.testCaseIds = ['all'];
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="card-container">
|
<div class="card-container">
|
||||||
<ms-table-header :is-,tester-permission="true" :condition.sync="condition" @search="initTableData"
|
<ms-table-header :tester-permission="true" :condition.sync="condition" @search="initTableData"
|
||||||
:show-create="false" :tip="$t('commons.search_by_name_or_id')">
|
:show-create="false" :tip="$t('commons.search_by_name_or_id')">
|
||||||
<template v-slot:button>
|
<template v-slot:button>
|
||||||
<ms-table-button :is-tester-permission="true" icon="el-icon-video-play"
|
<ms-table-button :is-tester-permission="true" icon="el-icon-video-play"
|
||||||
|
|
|
@ -1104,6 +1104,7 @@ export default {
|
||||||
cancel_relevance_success: "Unlinked successfully",
|
cancel_relevance_success: "Unlinked successfully",
|
||||||
switch_project: "Switch project",
|
switch_project: "Switch project",
|
||||||
case: {
|
case: {
|
||||||
|
minder: "Minder",
|
||||||
check_select: "Please check the case",
|
check_select: "Please check the case",
|
||||||
export_all_cases: 'Are you sure you want to export all use cases?',
|
export_all_cases: 'Are you sure you want to export all use cases?',
|
||||||
input_test_case: 'Please enter the associated case name',
|
input_test_case: 'Please enter the associated case name',
|
||||||
|
@ -1312,6 +1313,7 @@ export default {
|
||||||
executor: "Executor",
|
executor: "Executor",
|
||||||
execute_result: "Result",
|
execute_result: "Result",
|
||||||
pass: "Pass",
|
pass: "Pass",
|
||||||
|
not_pass: "UnPass",
|
||||||
failure: "Failure",
|
failure: "Failure",
|
||||||
blocking: "Blocking",
|
blocking: "Blocking",
|
||||||
skip: "Skip",
|
skip: "Skip",
|
||||||
|
|
|
@ -1108,6 +1108,7 @@ export default {
|
||||||
cancel_relevance_success: "取消关联成功",
|
cancel_relevance_success: "取消关联成功",
|
||||||
switch_project: "切换项目",
|
switch_project: "切换项目",
|
||||||
case: {
|
case: {
|
||||||
|
minder: "脑图",
|
||||||
check_select: "请勾选用例",
|
check_select: "请勾选用例",
|
||||||
export_all_cases: '确定要导出全部用例吗?',
|
export_all_cases: '确定要导出全部用例吗?',
|
||||||
input_test_case: '请输入关联用例名称',
|
input_test_case: '请输入关联用例名称',
|
||||||
|
@ -1316,6 +1317,7 @@ export default {
|
||||||
executor: "执行人",
|
executor: "执行人",
|
||||||
execute_result: "执行结果",
|
execute_result: "执行结果",
|
||||||
pass: "通过",
|
pass: "通过",
|
||||||
|
not_pass: "不通过",
|
||||||
failure: "失败",
|
failure: "失败",
|
||||||
blocking: "阻塞",
|
blocking: "阻塞",
|
||||||
skip: "跳过",
|
skip: "跳过",
|
||||||
|
|
|
@ -1106,6 +1106,7 @@ export default {
|
||||||
cancel_relevance_success: "取消關聯成功",
|
cancel_relevance_success: "取消關聯成功",
|
||||||
switch_project: "切換項目",
|
switch_project: "切換項目",
|
||||||
case: {
|
case: {
|
||||||
|
minder: "腦圖",
|
||||||
check_select: "請勾選用例",
|
check_select: "請勾選用例",
|
||||||
export_all_cases: '確定要導出全部用例嗎?',
|
export_all_cases: '確定要導出全部用例嗎?',
|
||||||
input_test_case: '請輸入關聯用例名稱',
|
input_test_case: '請輸入關聯用例名稱',
|
||||||
|
@ -1314,6 +1315,7 @@ export default {
|
||||||
executor: "執行人",
|
executor: "執行人",
|
||||||
execute_result: "執行結果",
|
execute_result: "執行結果",
|
||||||
pass: "通過",
|
pass: "通過",
|
||||||
|
not_pass: "不通過",
|
||||||
failure: "失敗",
|
failure: "失敗",
|
||||||
blocking: "阻塞",
|
blocking: "阻塞",
|
||||||
skip: "跳過",
|
skip: "跳過",
|
||||||
|
|
Loading…
Reference in New Issue