Merge branch 'master' of https://github.com/metersphere/metersphere
This commit is contained in:
commit
cdf1b73253
|
@ -10,6 +10,7 @@ import io.metersphere.api.dto.definition.*;
|
|||
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
|
||||
import io.metersphere.api.service.ApiDefinitionService;
|
||||
import io.metersphere.base.domain.ApiDefinition;
|
||||
import io.metersphere.base.domain.Schedule;
|
||||
import io.metersphere.commons.constants.RoleConstants;
|
||||
import io.metersphere.commons.json.JSONSchemaGenerator;
|
||||
import io.metersphere.commons.utils.PageUtils;
|
||||
|
@ -139,6 +140,11 @@ public class ApiDefinitionController {
|
|||
return apiDefinitionService.apiTestImport(file, request);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/schedule/create")
|
||||
public void createSchedule(@RequestBody Schedule request) {
|
||||
apiDefinitionService.createSchedule(request);
|
||||
}
|
||||
|
||||
@PostMapping("/getReference")
|
||||
public ReferenceDTO getReference(@RequestBody ApiScenarioRequest request) {
|
||||
return apiDefinitionService.getReference(request);
|
||||
|
@ -165,5 +171,4 @@ public class ApiDefinitionController {
|
|||
public String preview(@RequestBody String jsonSchema) {
|
||||
return JSONSchemaGenerator.getJson(jsonSchema);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,10 +24,14 @@ import io.metersphere.base.mapper.ext.ExtApiScenarioMapper;
|
|||
import io.metersphere.base.mapper.ext.ExtTestPlanMapper;
|
||||
import io.metersphere.commons.constants.APITestStatus;
|
||||
import io.metersphere.commons.constants.ApiRunMode;
|
||||
import io.metersphere.commons.constants.ScheduleGroup;
|
||||
import io.metersphere.commons.constants.ScheduleType;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.*;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.job.sechedule.SwaggerUrlImportJob;
|
||||
import io.metersphere.service.FileService;
|
||||
import io.metersphere.service.ScheduleService;
|
||||
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
|
||||
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
@ -73,6 +77,8 @@ public class ApiDefinitionService {
|
|||
private ExtTestPlanMapper extTestPlanMapper;
|
||||
@Resource
|
||||
private ProjectMapper projectMapper;
|
||||
@Resource
|
||||
private ScheduleService scheduleService;
|
||||
|
||||
private static Cache cache = Cache.newHardMemoryCache(0, 3600 * 24);
|
||||
|
||||
|
@ -587,4 +593,19 @@ public class ApiDefinitionService {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*swagger定时导入*/
|
||||
public void createSchedule(Schedule request) {
|
||||
Schedule schedule = scheduleService.buildApiTestSchedule(request);
|
||||
schedule.setJob(SwaggerUrlImportJob.class.getName());
|
||||
schedule.setGroup(ScheduleGroup.SWAGGER_IMPORT.name());
|
||||
schedule.setType(ScheduleType.CRON.name());
|
||||
scheduleService.addSchedule(schedule);
|
||||
this.addOrUpdateSwaggerImportCronJob(request);
|
||||
|
||||
}
|
||||
|
||||
private void addOrUpdateSwaggerImportCronJob(Schedule request) {
|
||||
scheduleService.addOrUpdateCronJob(request, SwaggerUrlImportJob.getJobKey(request.getResourceId()), SwaggerUrlImportJob.getTriggerKey(request.getResourceId()), SwaggerUrlImportJob.class);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
package io.metersphere.base.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class Schedule implements Serializable {
|
||||
private String id;
|
||||
|
@ -35,4 +36,6 @@ public class Schedule implements Serializable {
|
|||
|
||||
//定时任务来源: 测试计划/测试场景
|
||||
private String scheduleFrom;
|
||||
|
||||
private String swaggerUrl;
|
||||
}
|
|
@ -33,4 +33,6 @@ public interface ApiDefinitionExecResultMapper {
|
|||
int updateByPrimaryKeyWithBLOBs(ApiDefinitionExecResult record);
|
||||
|
||||
int updateByPrimaryKey(ApiDefinitionExecResult record);
|
||||
|
||||
String selectExecResult(String resourceId);
|
||||
}
|
|
@ -210,6 +210,9 @@
|
|||
<include refid="Example_Where_Clause" />
|
||||
</if>
|
||||
</select>
|
||||
<select id="selectExecResult" resultType="java.lang.String">
|
||||
select ader.status from api_definition_exec_result ader where ader.resource_id=#{resourceId}
|
||||
</select>
|
||||
<update id="updateByExampleSelective" parameterType="map">
|
||||
update api_definition_exec_result
|
||||
<set>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
package io.metersphere.commons.constants;
|
||||
|
||||
public enum ScheduleGroup {
|
||||
API_TEST, PERFORMANCE_TEST, API_SCENARIO_TEST,TEST_PLAN_TEST
|
||||
API_TEST, PERFORMANCE_TEST, API_SCENARIO_TEST, TEST_PLAN_TEST, SWAGGER_IMPORT
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package io.metersphere.job.sechedule;
|
||||
|
||||
import io.metersphere.api.dto.ApiTestImportRequest;
|
||||
import io.metersphere.api.service.ApiDefinitionService;
|
||||
import io.metersphere.commons.constants.ScheduleGroup;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobKey;
|
||||
import org.quartz.TriggerKey;
|
||||
|
||||
public class SwaggerUrlImportJob extends MsScheduleJob {
|
||||
private ApiDefinitionService apiDefinitionService;
|
||||
|
||||
public SwaggerUrlImportJob() {
|
||||
apiDefinitionService = (ApiDefinitionService) CommonBeanFactory.getBean(ApiDefinitionService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
void businessExecute(JobExecutionContext context) {
|
||||
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
|
||||
String resourceId = jobDataMap.getString("resourceId");
|
||||
String swaggerUrl = jobDataMap.getString("swaggerUrl");
|
||||
ApiTestImportRequest request = new ApiTestImportRequest();
|
||||
request.setProjectId(resourceId);
|
||||
request.setSwaggerUrl(swaggerUrl);
|
||||
apiDefinitionService.apiTestImport(null, request);
|
||||
}
|
||||
|
||||
public static JobKey getJobKey(String resourceId) {
|
||||
return new JobKey(resourceId, ScheduleGroup.SWAGGER_IMPORT.name());
|
||||
}
|
||||
|
||||
public static TriggerKey getTriggerKey(String resourceId) {
|
||||
return new TriggerKey(resourceId, ScheduleGroup.SWAGGER_IMPORT.name());
|
||||
}
|
||||
}
|
|
@ -104,6 +104,7 @@ public class ScheduleService {
|
|||
|
||||
public void startEnableSchedules() {
|
||||
List<Schedule> Schedules = getEnableSchedule();
|
||||
|
||||
Schedules.forEach(schedule -> {
|
||||
try {
|
||||
if (schedule.getEnable()) {
|
||||
|
@ -122,7 +123,7 @@ public class ScheduleService {
|
|||
public Schedule buildApiTestSchedule(Schedule request) {
|
||||
Schedule schedule = new Schedule();
|
||||
schedule.setResourceId(request.getResourceId());
|
||||
schedule.setEnable(request.getEnable());
|
||||
schedule.setEnable(true);
|
||||
schedule.setValue(request.getValue().trim());
|
||||
schedule.setKey(request.getResourceId());
|
||||
schedule.setUserId(SessionUtils.getUser().getId());
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit c2ed883e9be6fc7e01589f81916bf4ddc62148c0
|
||||
Subproject commit 7f7808c6f0457dd2df6b19a1622558f3f8122646
|
|
@ -30,10 +30,13 @@
|
|||
<el-table-column prop="level" :label="$t('api_test.automation.case_level')"
|
||||
show-overflow-tooltip>
|
||||
<template v-slot:default="scope">
|
||||
<ms-tag v-if="scope.row.level == 'P0'" type="info" effect="plain" content="P0"/>
|
||||
<ms-tag v-if="scope.row.level == 'P1'" type="warning" effect="plain" content="P1"/>
|
||||
<ms-tag v-if="scope.row.level == 'P2'" type="success" effect="plain" content="P2"/>
|
||||
<ms-tag v-if="scope.row.level == 'P3'" type="danger" effect="plain" content="P3"/>
|
||||
<priority-table-item :value="scope.row.level"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" :label="$t('test_track.plan.plan_status')"
|
||||
show-overflow-tooltip>
|
||||
<template v-slot:default="scope">
|
||||
<plan-status-table-item :value="scope.row.status"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="tags" :label="$t('api_test.automation.tag')" width="200px">
|
||||
|
@ -115,10 +118,14 @@
|
|||
import MsTableSelectAll from "../../../common/components/table/MsTableSelectAll";
|
||||
import {API_CASE_CONFIGS} from "@/business/components/common/components/search/search-components";
|
||||
import MsTableOperatorButton from "@/business/components/common/components/MsTableOperatorButton";
|
||||
import PriorityTableItem from "../../../track/common/tableItems/planview/PriorityTableItem";
|
||||
import PlanStatusTableItem from "../../../track/common/tableItems/plan/PlanStatusTableItem";
|
||||
|
||||
export default {
|
||||
name: "MsApiScenarioList",
|
||||
components: {
|
||||
PlanStatusTableItem,
|
||||
PriorityTableItem,
|
||||
MsTableSelectAll,
|
||||
MsTablePagination,
|
||||
MsTableMoreBtn,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
{{description}}
|
||||
</span>
|
||||
<div class="kv-row" v-for="(item, index) in items" :key="index">
|
||||
<el-row type="flex" :gutter="20" justify="space-between" align="middle">
|
||||
<el-row type="flex" :gutter="5" justify="space-between" align="middle">
|
||||
<el-col class="kv-checkbox">
|
||||
<input type="checkbox" v-if="!isDisable(index)" @change="change" :value="item.uuid" v-model="item.enable"
|
||||
:disabled="isDisable(index) || isReadOnly"/>
|
||||
|
@ -18,6 +18,15 @@
|
|||
<el-input :disabled="isReadOnly" v-model="item.value" size="small" @change="change"
|
||||
:placeholder="$t('api_test.value')" show-word-limit/>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<el-input v-model="item.description" size="small" maxlength="200"
|
||||
:placeholder="$t('commons.description')" show-word-limit>
|
||||
</el-input>
|
||||
</el-col>
|
||||
<el-col class="kv-copy">
|
||||
<el-button size="mini" class="el-icon-document-copy" circle @click="copy(item, index)"
|
||||
:disabled="isDisable(index) || isReadOnly"/>
|
||||
</el-col>
|
||||
<el-col class="kv-delete">
|
||||
<el-button size="mini" class="el-icon-delete-solid" circle @click="remove(index)"
|
||||
:disabled="isDisable(index) || isReadOnly"/>
|
||||
|
@ -59,6 +68,11 @@
|
|||
this.items.splice(index, 1);
|
||||
this.$emit('change', this.items);
|
||||
},
|
||||
copy: function (item, index) {
|
||||
let copy = {};
|
||||
Object.assign(copy, item);
|
||||
this.items.splice(index + 1, 0, copy);
|
||||
},
|
||||
change: function () {
|
||||
let isNeedCreate = true;
|
||||
let removeIndex = -1;
|
||||
|
@ -105,7 +119,7 @@
|
|||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.kv-delete {
|
||||
.kv-delete,.kv-copy {
|
||||
width: 60px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -3,17 +3,17 @@
|
|||
:visible.sync="visible" class="api-import" v-loading="result.loading" @close="close">
|
||||
|
||||
<div class="header-bar">
|
||||
<div>{{$t('api_test.api_import.data_format')}}</div>
|
||||
<div>{{ $t('api_test.api_import.data_format') }}</div>
|
||||
<el-radio-group v-model="selectedPlatformValue">
|
||||
<el-radio v-for="(item, index) in platforms" :key="index" :label="item.value">{{item.name}}</el-radio>
|
||||
<el-radio v-for="(item, index) in platforms" :key="index" :label="item.value">{{ item.name }}</el-radio>
|
||||
</el-radio-group>
|
||||
|
||||
<div class="operate-button">
|
||||
<el-button class="save-button" type="primary" plain @click="save">
|
||||
{{$t('commons.save')}}
|
||||
{{ $t('commons.save') }}
|
||||
</el-button>
|
||||
<el-button class="cancel-button" type="warning" plain @click="visible = false">
|
||||
{{$t('commons.cancel')}}
|
||||
{{ $t('commons.cancel') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -34,7 +34,7 @@
|
|||
multiple>
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text" v-html="$t('load_test.upload_tips')"></div>
|
||||
<div class="el-upload__tip" slot="tip">{{$t('api_test.api_import.file_size_limit')}}</div>
|
||||
<div class="el-upload__tip" slot="tip">{{ $t('api_test.api_import.file_size_limit') }}</div>
|
||||
</el-upload>
|
||||
|
||||
<el-form-item :label="'Swagger URL'" prop="wgerUrl" v-if="isSwagger2 && swaggerUrlEable" class="swagger-url">
|
||||
|
@ -48,14 +48,23 @@
|
|||
</el-switch>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="isSwagger2 && swaggerUrlEable">
|
||||
<el-switch
|
||||
v-model="swaggerSynchronization"
|
||||
@click.native="scheduleEdit"
|
||||
:active-text="$t('api_test.api_import.timing_synchronization')">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
<schedule-import ref="scheduleEdit"></schedule-import>
|
||||
|
||||
</el-form>
|
||||
|
||||
<div class="format-tip">
|
||||
<div>
|
||||
<span>{{$t('api_test.api_import.tip')}}:{{selectedPlatform.tip}}</span>
|
||||
<span>{{ $t('api_test.api_import.tip') }}:{{ selectedPlatform.tip }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{$t('api_test.api_import.export_tip')}}:{{selectedPlatform.exportTip}}</span>
|
||||
<span>{{ $t('api_test.api_import.export_tip') }}:{{ selectedPlatform.exportTip }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -63,217 +72,223 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
|
||||
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
|
||||
import {getCurrentProjectID} from "../../../../../../common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "ApiImport",
|
||||
components: {MsDialogFooter},
|
||||
props: {
|
||||
saved: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
swaggerUrlEable: false,
|
||||
showEnvironmentSelect: true,
|
||||
platforms: [
|
||||
{
|
||||
name: 'Metersphere',
|
||||
value: 'Metersphere',
|
||||
tip: this.$t('api_test.api_import.ms_tip'),
|
||||
exportTip: this.$t('api_test.api_import.ms_export_tip'),
|
||||
suffixes: new Set(['json'])
|
||||
},
|
||||
{
|
||||
name: 'Postman',
|
||||
value: 'Postman',
|
||||
tip: this.$t('api_test.api_import.postman_tip'),
|
||||
exportTip: this.$t('api_test.api_import.post_export_tip'),
|
||||
suffixes: new Set(['json'])
|
||||
},
|
||||
{
|
||||
name: 'Swagger',
|
||||
value: 'Swagger2',
|
||||
tip: this.$t('api_test.api_import.swagger_tip'),
|
||||
exportTip: this.$t('api_test.api_import.swagger_export_tip'),
|
||||
suffixes: new Set(['json'])
|
||||
}
|
||||
],
|
||||
selectedPlatform: {},
|
||||
selectedPlatformValue: 'Metersphere',
|
||||
result: {},
|
||||
projects: [],
|
||||
environments: [],
|
||||
useEnvironment: false,
|
||||
formData: {
|
||||
file: undefined,
|
||||
swaggerUrl: ''
|
||||
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
|
||||
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
|
||||
import {getCurrentProjectID} from "../../../../../../common/js/utils";
|
||||
import ScheduleImport from "@/business/components/api/definition/components/import/ImportScheduleEdit";
|
||||
export default {
|
||||
name: "ApiImport",
|
||||
components: {ScheduleImport, MsDialogFooter},
|
||||
props: {
|
||||
saved: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
swaggerUrlEable: false,
|
||||
swaggerSynchronization:false,
|
||||
showEnvironmentSelect: true,
|
||||
platforms: [
|
||||
{
|
||||
name: 'Metersphere',
|
||||
value: 'Metersphere',
|
||||
tip: this.$t('api_test.api_import.ms_tip'),
|
||||
exportTip: this.$t('api_test.api_import.ms_export_tip'),
|
||||
suffixes: new Set(['json'])
|
||||
},
|
||||
rules: {},
|
||||
currentModule: {},
|
||||
fileList: []
|
||||
}
|
||||
},
|
||||
activated() {
|
||||
this.selectedPlatform = this.platforms[0];
|
||||
},
|
||||
watch: {
|
||||
selectedPlatformValue() {
|
||||
for (let i in this.platforms) {
|
||||
if (this.platforms[i].value === this.selectedPlatformValue) {
|
||||
this.selectedPlatform = this.platforms[i];
|
||||
break;
|
||||
}
|
||||
{
|
||||
name: 'Postman',
|
||||
value: 'Postman',
|
||||
tip: this.$t('api_test.api_import.postman_tip'),
|
||||
exportTip: this.$t('api_test.api_import.post_export_tip'),
|
||||
suffixes: new Set(['json'])
|
||||
},
|
||||
{
|
||||
name: 'Swagger',
|
||||
value: 'Swagger2',
|
||||
tip: this.$t('api_test.api_import.swagger_tip'),
|
||||
exportTip: this.$t('api_test.api_import.swagger_export_tip'),
|
||||
suffixes: new Set(['json'])
|
||||
}
|
||||
],
|
||||
selectedPlatform: {},
|
||||
selectedPlatformValue: 'Metersphere',
|
||||
result: {},
|
||||
projects: [],
|
||||
environments: [],
|
||||
useEnvironment: false,
|
||||
formData: {
|
||||
file: undefined,
|
||||
swaggerUrl: ''
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isSwagger2() {
|
||||
return this.selectedPlatformValue === 'Swagger2';
|
||||
rules: {},
|
||||
currentModule: {},
|
||||
fileList: []
|
||||
}
|
||||
},
|
||||
activated() {
|
||||
this.selectedPlatform = this.platforms[0];
|
||||
},
|
||||
watch: {
|
||||
selectedPlatformValue() {
|
||||
for (let i in this.platforms) {
|
||||
if (this.platforms[i].value === this.selectedPlatformValue) {
|
||||
this.selectedPlatform = this.platforms[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open(module) {
|
||||
this.currentModule = module;
|
||||
this.visible = true;
|
||||
listenGoBack(this.close);
|
||||
},
|
||||
upload(file) {
|
||||
this.formData.file = file.file;
|
||||
},
|
||||
handleExceed(files, fileList) {
|
||||
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
|
||||
},
|
||||
handleRemove(file, fileList) {
|
||||
this.formData.file = undefined;
|
||||
},
|
||||
uploadValidate(file, fileList) {
|
||||
let suffix = file.name.substring(file.name.lastIndexOf('.') + 1);
|
||||
if (this.selectedPlatform.suffixes && !this.selectedPlatform.suffixes.has(suffix)) {
|
||||
this.$warning(this.$t('api_test.api_import.suffixFormatErr'));
|
||||
},
|
||||
computed: {
|
||||
isSwagger2() {
|
||||
return this.selectedPlatformValue === 'Swagger2';
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
scheduleEdit(){
|
||||
if(this.swaggerSynchronization){
|
||||
this.$refs.scheduleEdit.open(this.buildParam());
|
||||
}
|
||||
},
|
||||
open(module) {
|
||||
this.currentModule = module;
|
||||
this.visible = true;
|
||||
listenGoBack(this.close);
|
||||
},
|
||||
upload(file) {
|
||||
this.formData.file = file.file;
|
||||
},
|
||||
handleExceed(files, fileList) {
|
||||
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
|
||||
},
|
||||
handleRemove(file, fileList) {
|
||||
this.formData.file = undefined;
|
||||
},
|
||||
uploadValidate(file, fileList) {
|
||||
let suffix = file.name.substring(file.name.lastIndexOf('.') + 1);
|
||||
if (this.selectedPlatform.suffixes && !this.selectedPlatform.suffixes.has(suffix)) {
|
||||
this.$warning(this.$t('api_test.api_import.suffixFormatErr'));
|
||||
return false;
|
||||
}
|
||||
if (file.size / 1024 / 1024 > 20) {
|
||||
this.$warning(this.$t('test_track.case.import.upload_limit_size'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
save() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (valid) {
|
||||
if ((this.selectedPlatformValue != 'Swagger2' || (this.selectedPlatformValue == 'Swagger2' && !this.swaggerUrlEable)) && !this.formData.file) {
|
||||
this.$warning(this.$t('commons.please_upload'));
|
||||
return;
|
||||
}
|
||||
let param = this.buildParam();
|
||||
this.result = this.$fileUpload('/api/definition/import', param.file, null, this.buildParam(), response => {
|
||||
let res = response.data;
|
||||
this.$success(this.$t('test_track.case.import.success'));
|
||||
this.visible = false;
|
||||
this.$emit('refresh', res);
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (file.size / 1024 / 1024 > 20) {
|
||||
this.$warning(this.$t('test_track.case.import.upload_limit_size'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
save() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (valid) {
|
||||
if ((this.selectedPlatformValue != 'Swagger2' || (this.selectedPlatformValue == 'Swagger2' && !this.swaggerUrlEable)) && !this.formData.file) {
|
||||
this.$warning(this.$t('commons.please_upload'));
|
||||
return;
|
||||
}
|
||||
let param = this.buildParam();
|
||||
this.result = this.$fileUpload('/api/definition/import', param.file, null, this.buildParam(), response => {
|
||||
let res = response.data;
|
||||
this.$success(this.$t('test_track.case.import.success'));
|
||||
this.visible = false;
|
||||
this.$emit('refresh', res);
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
buildParam() {
|
||||
let param = {};
|
||||
Object.assign(param, this.formData);
|
||||
param.platform = this.selectedPlatformValue;
|
||||
param.saved = this.saved;
|
||||
if (this.currentModule) {
|
||||
param.moduleId = this.currentModule.id;
|
||||
param.modulePath = this.currentModule.path;
|
||||
}
|
||||
param.projectId = getCurrentProjectID();
|
||||
if (!this.swaggerUrlEable) {
|
||||
param.swaggerUrl = undefined;
|
||||
}
|
||||
return param;
|
||||
},
|
||||
close() {
|
||||
this.formData = {
|
||||
file: undefined,
|
||||
swaggerUrl: ''
|
||||
};
|
||||
this.fileList = [];
|
||||
removeGoBackListener(this.close);
|
||||
this.visible = false;
|
||||
});
|
||||
},
|
||||
buildParam() {
|
||||
let param = {};
|
||||
Object.assign(param, this.formData);
|
||||
param.platform = this.selectedPlatformValue;
|
||||
param.saved = this.saved;
|
||||
if (this.currentModule) {
|
||||
param.moduleId = this.currentModule.id;
|
||||
param.modulePath = this.currentModule.path;
|
||||
}
|
||||
param.projectId = getCurrentProjectID();
|
||||
if (!this.swaggerUrlEable) {
|
||||
param.swaggerUrl = undefined;
|
||||
}
|
||||
return param;
|
||||
},
|
||||
close() {
|
||||
this.formData = {
|
||||
file: undefined,
|
||||
swaggerUrl: ''
|
||||
};
|
||||
this.fileList = [];
|
||||
removeGoBackListener(this.close);
|
||||
this.visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.api-import >>> .el-dialog {
|
||||
min-width: 700px;
|
||||
}
|
||||
.api-import >>> .el-dialog {
|
||||
min-width: 700px;
|
||||
}
|
||||
|
||||
.format-tip {
|
||||
background: #EDEDED;
|
||||
}
|
||||
.format-tip {
|
||||
background: #EDEDED;
|
||||
}
|
||||
|
||||
.api-upload {
|
||||
text-align: center;
|
||||
margin: auto 0;
|
||||
}
|
||||
.api-upload {
|
||||
text-align: center;
|
||||
margin: auto 0;
|
||||
}
|
||||
|
||||
.api-upload >>> .el-upload {
|
||||
width: 100%;
|
||||
max-width: 350px;
|
||||
}
|
||||
.api-upload >>> .el-upload {
|
||||
width: 100%;
|
||||
max-width: 350px;
|
||||
}
|
||||
|
||||
.api-upload >>> .el-upload-dragger {
|
||||
width: 100%;
|
||||
}
|
||||
.api-upload >>> .el-upload-dragger {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.el-radio-group {
|
||||
margin: 10px 0;
|
||||
}
|
||||
.el-radio-group {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.header-bar, .format-tip, .el-form {
|
||||
border: solid #E1E1E1 1px;
|
||||
margin: 10px 0;
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.header-bar, .format-tip, .el-form {
|
||||
border: solid #E1E1E1 1px;
|
||||
margin: 10px 0;
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.header-bar {
|
||||
padding: 10px 30px;
|
||||
}
|
||||
.header-bar {
|
||||
padding: 10px 30px;
|
||||
}
|
||||
|
||||
.api-import >>> .el-dialog__body {
|
||||
padding: 15px 25px;
|
||||
}
|
||||
.api-import >>> .el-dialog__body {
|
||||
padding: 15px 25px;
|
||||
}
|
||||
|
||||
.operate-button {
|
||||
float: right;
|
||||
}
|
||||
.operate-button {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.save-button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.save-button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.el-form {
|
||||
padding: 30px 10px;
|
||||
}
|
||||
.el-form {
|
||||
padding: 30px 10px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
float: right;
|
||||
}
|
||||
.dialog-footer {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.swagger-url-disable {
|
||||
margin-top: 10px;
|
||||
.swagger-url-disable {
|
||||
margin-top: 10px;
|
||||
|
||||
margin-left: 80px;
|
||||
}
|
||||
margin-left: 80px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,213 @@
|
|||
<template>
|
||||
<el-dialog :close-on-click-modal="false" width="60%" class="schedule-edit" :visible.sync="dialogVisible"
|
||||
append-to-body @close="close">
|
||||
<template>
|
||||
<div>
|
||||
<el-tabs v-model="activeName">
|
||||
<el-tab-pane :label="$t('schedule.edit_timer_task')" name="first">
|
||||
<el-form :model="form" :rules="rules" ref="from">
|
||||
<el-form-item
|
||||
prop="cronValue">
|
||||
<el-input :disabled="isReadOnly" v-model="form.cronValue" class="inp"
|
||||
:placeholder="$t('schedule.please_input_cron_expression')"/>
|
||||
<el-button :disabled="isReadOnly" type="primary" @click="saveCron" v-tester>{{
|
||||
$t('commons.save')
|
||||
}}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-link :disabled="isReadOnly" type="primary" @click="showCronDialog">
|
||||
{{ $t('schedule.generate_expression') }}
|
||||
</el-link>
|
||||
</el-form-item>
|
||||
<crontab-result :ex="form.cronValue" ref="crontabResult"/>
|
||||
</el-form>
|
||||
<el-dialog width="60%" :title="$t('schedule.generate_expression')" :visible.sync="showCron"
|
||||
:modal="false">
|
||||
<crontab @hide="showCron=false" @fill="crontabFill" :expression="schedule.value"
|
||||
ref="crontab"/>
|
||||
</el-dialog>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {checkoutTestManagerOrTestUser, getCurrentUser, listenGoBack, removeGoBackListener} from "@/common/js/utils";
|
||||
import Crontab from "@/business/components/common/cron/Crontab";
|
||||
import CrontabResult from "@/business/components/common/cron/CrontabResult";
|
||||
import {cronValidate} from "@/common/js/cron";
|
||||
|
||||
function defaultCustomValidate() {
|
||||
return {pass: true};
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "ImportScheduleEdit",
|
||||
components: {CrontabResult, Crontab},
|
||||
|
||||
props: {
|
||||
customValidate: {
|
||||
type: Function,
|
||||
default: defaultCustomValidate
|
||||
},
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
watch: {
|
||||
'schedule.value'() {
|
||||
this.form.cronValue = this.schedule.value;
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const validateCron = (rule, cronValue, callback) => {
|
||||
let customValidate = this.customValidate(this.getIntervalTime());
|
||||
if (!cronValue) {
|
||||
callback(new Error(this.$t('commons.input_content')));
|
||||
} else if (!cronValidate(cronValue)) {
|
||||
callback(new Error(this.$t('schedule.cron_expression_format_error')));
|
||||
} else if (!customValidate.pass) {
|
||||
callback(new Error(customValidate.info));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
return {
|
||||
operation: true,
|
||||
dialogVisible: false,
|
||||
schedule: {
|
||||
value: "",
|
||||
},
|
||||
showCron: false,
|
||||
form: {
|
||||
cronValue: ""
|
||||
},
|
||||
activeName: 'first',
|
||||
swaggerUrl:String,
|
||||
projectId:String,
|
||||
rules: {
|
||||
cronValue: [{required: true, validator: validateCron, trigger: 'blur'}],
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
currentUser: () => {
|
||||
return getCurrentUser();
|
||||
},
|
||||
open(param) {
|
||||
let paramTestId = "";
|
||||
paramTestId=param.projectId
|
||||
this.findSchedule(paramTestId);
|
||||
this.project=param.projectId;
|
||||
this.swaggerUrl=param.swaggerUrl;
|
||||
this.dialogVisible = true;
|
||||
this.form.cronValue = this.schedule.value;
|
||||
listenGoBack(this.close);
|
||||
this.activeName = 'first';
|
||||
},
|
||||
findSchedule(paramTestId) {
|
||||
let scheduleResourceID = paramTestId;
|
||||
let taskType="SWAGGER_IMPORT";
|
||||
this.result = this.$get("/schedule/findOne/" + scheduleResourceID + "/" +taskType, response => {
|
||||
if (response.data != null) {
|
||||
this.schedule = response.data;
|
||||
} else {
|
||||
this.schedule = {};
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
crontabFill(value, resultList) {
|
||||
//确定后回传的值
|
||||
this.form.cronValue = value;
|
||||
this.$refs.crontabResult.resultList = resultList;
|
||||
this.$refs['from'].validate();
|
||||
},
|
||||
showCronDialog() {
|
||||
this.showCron = true;
|
||||
},
|
||||
saveCron() {
|
||||
this.$refs['from'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.intervalShortValidate();
|
||||
let formCronValue = this.form.cronValue
|
||||
this.schedule.enable = true;
|
||||
this.schedule.value = formCronValue;
|
||||
this.saveSchedule();
|
||||
this.dialogVisible = false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
saveSchedule() {
|
||||
this.checkScheduleEdit();
|
||||
let param = {};
|
||||
param = this.schedule;
|
||||
param.resourceId =this.project;
|
||||
param.swaggerUrl=this.swaggerUrl;
|
||||
let url = '/api/definition/schedule/create';
|
||||
this.$post(url, param, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
});
|
||||
},
|
||||
checkScheduleEdit() {
|
||||
if (this.create) {
|
||||
this.$message(this.$t('api_test.environment.please_save_test'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
close() {
|
||||
this.dialogVisible = false;
|
||||
this.form.cronValue = '';
|
||||
this.$refs['from'].resetFields();
|
||||
if (!this.schedule.value) {
|
||||
this.$refs.crontabResult.resultList = [];
|
||||
}
|
||||
removeGoBackListener(this.close);
|
||||
},
|
||||
intervalShortValidate() {
|
||||
if (this.getIntervalTime() < 3 * 60 * 1000) {
|
||||
// return false;
|
||||
this.$info(this.$t('schedule.cron_expression_interval_short_error'));
|
||||
}
|
||||
return true;
|
||||
},
|
||||
resultListChange() {
|
||||
this.$refs['from'].validate();
|
||||
},
|
||||
getIntervalTime() {
|
||||
let resultList = this.$refs.crontabResult.resultList;
|
||||
let time1 = new Date(resultList[0]);
|
||||
let time2 = new Date(resultList[1]);
|
||||
return time2 - time1;
|
||||
},
|
||||
|
||||
},
|
||||
computed: {
|
||||
isTesterPermission() {
|
||||
return checkoutTestManagerOrTestUser();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.inp {
|
||||
width: 50%;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -829,6 +829,9 @@ export default {
|
|||
swagger_export_tip: "Export jSON-formatted files via Swagger website",
|
||||
suffixFormatErr: "The file format does not meet the requirements",
|
||||
swagger_url_import: "Import using URL",
|
||||
timing_synchronization:"Timing synchronization",
|
||||
next_synchronization_time:"Next synchronization time",
|
||||
|
||||
},
|
||||
home_page: {
|
||||
unit_of_measurement: "",
|
||||
|
|
|
@ -831,6 +831,10 @@ export default {
|
|||
swagger_export_tip: "通过 Swagger 页面导出",
|
||||
suffixFormatErr: "文件格式不符合要求",
|
||||
swagger_url_import: "使用URL导入",
|
||||
timing_synchronization:"定时同步",
|
||||
next_synchronization_time:"下次同步时间"
|
||||
|
||||
|
||||
},
|
||||
home_page: {
|
||||
unit_of_measurement: "个",
|
||||
|
|
|
@ -830,6 +830,9 @@ export default {
|
|||
swagger_export_tip: "通過 Swagger 頁面導出",
|
||||
suffixFormatErr: "文件格式不符合要求",
|
||||
swagger_url_import: "使用URL導入",
|
||||
timing_synchronization:"定時同步",
|
||||
next_synchronization_time:"下次同步時間",
|
||||
|
||||
},
|
||||
home_page: {
|
||||
unit_of_measurement: "個",
|
||||
|
|
Loading…
Reference in New Issue