Merge branch 'master' of https://github.com/metersphere/metersphere
This commit is contained in:
commit
c4197029f7
|
@ -2,15 +2,21 @@ package io.metersphere.api.controller;
|
|||
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import io.metersphere.api.dto.APITestResult;
|
||||
import io.metersphere.api.dto.automation.*;
|
||||
import io.metersphere.api.dto.definition.RunDefinitionRequest;
|
||||
import io.metersphere.api.service.ApiAutomationService;
|
||||
import io.metersphere.base.domain.ApiScenario;
|
||||
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
|
||||
import io.metersphere.base.domain.ApiTest;
|
||||
import io.metersphere.base.domain.Schedule;
|
||||
import io.metersphere.commons.constants.RoleConstants;
|
||||
import io.metersphere.commons.constants.ScheduleGroup;
|
||||
import io.metersphere.commons.utils.BeanUtils;
|
||||
import io.metersphere.commons.utils.PageUtils;
|
||||
import io.metersphere.commons.utils.Pager;
|
||||
import io.metersphere.commons.utils.SessionUtils;
|
||||
import io.metersphere.service.ScheduleService;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
@ -27,6 +33,7 @@ public class ApiAutomationController {
|
|||
@Resource
|
||||
ApiAutomationService apiAutomationService;
|
||||
|
||||
|
||||
@PostMapping("/list/{goPage}/{pageSize}")
|
||||
public Pager<List<ApiScenarioDTO>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiScenarioRequest request) {
|
||||
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||
|
@ -96,5 +103,16 @@ public class ApiAutomationController {
|
|||
return apiAutomationService.addScenarioToPlan(request);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping(value = "/schedule/update")
|
||||
public void updateSchedule(@RequestBody Schedule request) {
|
||||
apiAutomationService.updateSchedule(request);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/schedule/create")
|
||||
public void createSchedule(@RequestBody Schedule request) {
|
||||
apiAutomationService.createSchedule(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -21,5 +21,7 @@ public class RunScenarioRequest {
|
|||
|
||||
private String executeType;
|
||||
|
||||
private String reportUserID;
|
||||
|
||||
private List<String> scenarioIds;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONObject;
|
|||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.Gson;
|
||||
import io.metersphere.api.dto.automation.*;
|
||||
import io.metersphere.api.dto.datacount.ApiDataCountResult;
|
||||
import io.metersphere.api.dto.definition.RunDefinitionRequest;
|
||||
|
@ -12,21 +13,19 @@ import io.metersphere.api.dto.definition.request.*;
|
|||
import io.metersphere.api.dto.scenario.KeyValue;
|
||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.base.domain.ApiScenario;
|
||||
import io.metersphere.base.domain.ApiScenarioExample;
|
||||
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
|
||||
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.ApiScenarioMapper;
|
||||
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.ReportTriggerMode;
|
||||
import io.metersphere.commons.constants.*;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.DateUtils;
|
||||
import io.metersphere.commons.utils.ServiceUtils;
|
||||
import io.metersphere.commons.utils.SessionUtils;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.job.sechedule.ApiScenarioTestJob;
|
||||
import io.metersphere.job.sechedule.ApiTestJob;
|
||||
import io.metersphere.service.ScheduleService;
|
||||
import io.metersphere.track.dto.TestPlanDTO;
|
||||
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
@ -54,11 +53,15 @@ public class ApiAutomationService {
|
|||
private ApiDefinitionService apiDefinitionService;
|
||||
@Resource
|
||||
private ExtApiScenarioMapper extApiScenarioMapper;
|
||||
// @Resource
|
||||
// private ApiTagMapper apiTagMapper;
|
||||
@Resource
|
||||
private JMeterService jMeterService;
|
||||
@Resource
|
||||
private ApiTestEnvironmentService environmentService;
|
||||
@Resource
|
||||
private ScheduleService scheduleService;
|
||||
@Resource
|
||||
private ApiScenarioReportService apiReportService;
|
||||
@Resource
|
||||
private ExtTestPlanMapper extTestPlanMapper;
|
||||
|
@ -184,14 +187,19 @@ public class ApiAutomationService {
|
|||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
private void createAPIScenarioReportResult(String id, String triggerMode, String execType, String projectId) {
|
||||
private void createAPIScenarioReportResult(String id, String triggerMode, String execType, String projectId,String userID) {
|
||||
APIScenarioReportResult report = new APIScenarioReportResult();
|
||||
report.setId(id);
|
||||
report.setName("测试执行结果");
|
||||
report.setCreateTime(System.currentTimeMillis());
|
||||
report.setUpdateTime(System.currentTimeMillis());
|
||||
report.setStatus(APITestStatus.Running.name());
|
||||
report.setUserId(SessionUtils.getUserId());
|
||||
if(StringUtils.isNotEmpty(userID)){
|
||||
report.setUserId(userID);
|
||||
}else {
|
||||
report.setUserId(SessionUtils.getUserId());
|
||||
}
|
||||
|
||||
report.setTriggerMode(triggerMode);
|
||||
report.setExecuteType(execType);
|
||||
report.setProjectId(projectId);
|
||||
|
@ -210,10 +218,12 @@ public class ApiAutomationService {
|
|||
MsTestPlan testPlan = new MsTestPlan();
|
||||
testPlan.setHashTree(new LinkedList<>());
|
||||
HashTree jmeterTestPlanHashTree = new ListedHashTree();
|
||||
String projectID = request.getProjectId();
|
||||
for (ApiScenarioWithBLOBs item : apiScenarios) {
|
||||
MsThreadGroup group = new MsThreadGroup();
|
||||
group.setLabel(item.getName());
|
||||
group.setName(item.getName());
|
||||
projectID = item.getProjectId();
|
||||
try {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
|
@ -245,7 +255,7 @@ public class ApiAutomationService {
|
|||
jMeterService.runDefinition(request.getId(), jmeterTestPlanHashTree, request.getReportId(), ApiRunMode.SCENARIO.name());
|
||||
|
||||
createAPIScenarioReportResult(request.getId(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(),
|
||||
request.getExecuteType(), request.getProjectId());
|
||||
request.getExecuteType(), projectID,request.getReportUserID());
|
||||
return request.getId();
|
||||
}
|
||||
|
||||
|
@ -271,7 +281,8 @@ public class ApiAutomationService {
|
|||
request.getTestElement().getJmx(hashTree);
|
||||
// 调用执行方法
|
||||
jMeterService.runDefinition(request.getId(), hashTree, request.getReportId(), ApiRunMode.SCENARIO.name());
|
||||
createAPIScenarioReportResult(request.getId(), ReportTriggerMode.MANUAL.name(), request.getExecuteType(), request.getProjectId());
|
||||
createAPIScenarioReportResult(request.getId(), ReportTriggerMode.MANUAL.name(), request.getExecuteType(), request.getProjectId(),
|
||||
SessionUtils.getUserId());
|
||||
return request.getId();
|
||||
}
|
||||
|
||||
|
@ -347,4 +358,28 @@ public class ApiAutomationService {
|
|||
public List<ApiDataCountResult> countRunResultByProjectID(String projectId) {
|
||||
return extApiScenarioMapper.countRunResultByProjectID(projectId);
|
||||
}
|
||||
|
||||
public void createSchedule(Schedule request) {
|
||||
|
||||
Schedule schedule = scheduleService.buildApiTestSchedule(request);
|
||||
schedule.setJob(ApiScenarioTestJob.class.getName());
|
||||
schedule.setGroup(ScheduleGroup.API_SCENARIO_TEST.name());
|
||||
schedule.setType(ScheduleType.CRON.name());
|
||||
|
||||
scheduleService.addSchedule(schedule);
|
||||
this.addOrUpdateApiScenarioCronJob(request);
|
||||
|
||||
}
|
||||
|
||||
public void updateSchedule(Schedule request) {
|
||||
scheduleService.editSchedule(request);
|
||||
this.addOrUpdateApiScenarioCronJob(request);
|
||||
}
|
||||
|
||||
private void addOrUpdateApiScenarioCronJob(Schedule request) {
|
||||
scheduleService.addOrUpdateCronJob(
|
||||
request, ApiScenarioTestJob.getJobKey(request.getResourceId()), ApiScenarioTestJob.getTriggerKey(request.getResourceId()), ApiScenarioTestJob.class);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
package io.metersphere.commons.constants;
|
||||
|
||||
public enum ScheduleGroup {
|
||||
API_TEST, PERFORMANCE_TEST
|
||||
API_TEST, PERFORMANCE_TEST, API_SCENARIO_TEST
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
package io.metersphere.job.sechedule;
|
||||
|
||||
import io.metersphere.api.dto.SaveAPITestRequest;
|
||||
import io.metersphere.api.dto.automation.ExecuteType;
|
||||
import io.metersphere.api.dto.automation.RunScenarioRequest;
|
||||
import io.metersphere.api.service.APITestService;
|
||||
import io.metersphere.api.service.ApiAutomationService;
|
||||
import io.metersphere.commons.constants.ReportTriggerMode;
|
||||
import io.metersphere.commons.constants.ScheduleGroup;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import org.quartz.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 情景测试Job
|
||||
* @author song.tianyang
|
||||
* @Date 2020/12/22 2:59 下午
|
||||
* @Description
|
||||
*/
|
||||
public class ApiScenarioTestJob extends MsScheduleJob {
|
||||
private String projectID;
|
||||
private List<String> scenarioIds;
|
||||
|
||||
private ApiAutomationService apiAutomationService;
|
||||
public ApiScenarioTestJob() {
|
||||
apiAutomationService = (ApiAutomationService) CommonBeanFactory.getBean(ApiAutomationService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException {
|
||||
JobKey jobKey = context.getTrigger().getJobKey();
|
||||
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
|
||||
String resourceId = jobDataMap.getString("resourceId");
|
||||
this.userId = jobDataMap.getString("userId");
|
||||
this.expression = jobDataMap.getString("expression");
|
||||
this.projectID = jobDataMap.getString("projectId");
|
||||
|
||||
if(resourceId!=null){
|
||||
scenarioIds = new ArrayList<>();
|
||||
scenarioIds.add(resourceId);
|
||||
}
|
||||
|
||||
LogUtil.info(jobKey.getGroup() + " Running: " + resourceId);
|
||||
LogUtil.info("CronExpression: " + expression);
|
||||
businessExecute(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
void businessExecute(JobExecutionContext context) {
|
||||
RunScenarioRequest request = new RunScenarioRequest();
|
||||
String id = UUID.randomUUID().toString();
|
||||
request.setId(id);
|
||||
request.setReportId(id);
|
||||
request.setProjectId(projectID);
|
||||
request.setTriggerMode(ReportTriggerMode.MANUAL.name());
|
||||
request.setExecuteType(ExecuteType.Completed.name());
|
||||
request.setScenarioIds(this.scenarioIds);
|
||||
request.setReportUserID(this.userId);
|
||||
|
||||
apiAutomationService.run(request);
|
||||
}
|
||||
|
||||
public static JobKey getJobKey(String testId) {
|
||||
return new JobKey(testId, ScheduleGroup.API_SCENARIO_TEST.name());
|
||||
}
|
||||
|
||||
public static TriggerKey getTriggerKey(String testId) {
|
||||
return new TriggerKey(testId, ScheduleGroup.API_SCENARIO_TEST.name());
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ import org.quartz.JobExecutionContext;
|
|||
import org.quartz.JobKey;
|
||||
import org.quartz.TriggerKey;
|
||||
|
||||
|
||||
public class ApiTestJob extends MsScheduleJob {
|
||||
|
||||
private APITestService apiTestService;
|
||||
|
@ -34,3 +33,4 @@ public class ApiTestJob extends MsScheduleJob {
|
|||
return new TriggerKey(testId, ScheduleGroup.API_TEST.name());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
package io.metersphere.job.sechedule;
|
||||
|
||||
import io.metersphere.commons.constants.ScheduleGroup;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import org.python.antlr.ast.Str;
|
||||
import org.quartz.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Component
|
||||
public class ScheduleManager {
|
||||
|
@ -291,4 +295,5 @@ public class ScheduleManager {
|
|||
jobDataMap.put("userId", userId);
|
||||
return jobDataMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import io.metersphere.dto.ScheduleDao;
|
|||
import io.metersphere.job.sechedule.ApiTestJob;
|
||||
import io.metersphere.job.sechedule.ScheduleManager;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.quartz.JobDetail;
|
||||
import org.quartz.JobKey;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.quartz.TriggerKey;
|
||||
|
@ -64,6 +65,7 @@ public class ScheduleService {
|
|||
}
|
||||
|
||||
public Schedule getScheduleByResource(String resourceId, String group) {
|
||||
|
||||
ScheduleExample example = new ScheduleExample();
|
||||
example.createCriteria().andResourceIdEqualTo(resourceId).andGroupEqualTo(group);
|
||||
List<Schedule> schedules = scheduleMapper.selectByExample(example);
|
||||
|
|
|
@ -5,20 +5,20 @@
|
|||
</el-link>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="ref">{{ $t('api_test.automation.view_ref') }}</el-dropdown-item>
|
||||
<!-- <el-dropdown-item command="schedule">{{ $t('api_test.automation.schedule') }}</el-dropdown-item>-->
|
||||
<el-dropdown-item command="schedule">{{ $t('api_test.automation.schedule') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
<ms-reference-view ref="viewRef"/>
|
||||
<!-- <ms-schedule-maintain ref="scheduleMaintain" />-->
|
||||
<ms-schedule-maintain ref="scheduleMaintain" />
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsReferenceView from "@/business/components/api/automation/scenario/ReferenceView";
|
||||
// import MsScheduleMaintain from "@/business/components/api/automation/schedule/ScheduleMaintain"
|
||||
import MsScheduleMaintain from "@/business/components/api/automation/schedule/ScheduleMaintain"
|
||||
|
||||
export default {
|
||||
name: "MsScenarioExtendButtons",
|
||||
components: { MsReferenceView},
|
||||
components: { MsReferenceView,MsScheduleMaintain},
|
||||
props: {
|
||||
row: Object
|
||||
},
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
<template>
|
||||
<el-dialog :close-on-click-modal="false" width="60%" class="schedule-edit" :visible.sync="dialogVisible"
|
||||
@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">{{
|
||||
$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-tab-pane :label="$t('schedule.task_notification')" name="second">
|
||||
<ms-schedule-notification :is-tester-permission="isTesterPermission" :test-id="testId"
|
||||
:schedule-receiver-options="scheduleReceiverOptions"/>
|
||||
</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";
|
||||
import MsScheduleNotification from "./ScheduleNotification";
|
||||
|
||||
function defaultCustomValidate() {
|
||||
return {pass: true};
|
||||
}
|
||||
|
||||
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
|
||||
|
||||
export default {
|
||||
name: "MsScheduleMaintain",
|
||||
components: {CrontabResult, Crontab, MsScheduleNotification},
|
||||
|
||||
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 {
|
||||
scheduleReceiverOptions: [],
|
||||
operation: true,
|
||||
dialogVisible: false,
|
||||
schedule: {
|
||||
value : "",
|
||||
},
|
||||
testId:String,
|
||||
showCron: false,
|
||||
form: {
|
||||
cronValue: ""
|
||||
},
|
||||
activeName: 'first',
|
||||
rules: {
|
||||
cronValue: [{required: true, validator: validateCron, trigger: 'blur'}],
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
currentUser: () => {
|
||||
return getCurrentUser();
|
||||
},
|
||||
initUserList() {
|
||||
let param = {
|
||||
name: '',
|
||||
organizationId: this.currentUser().lastOrganizationId
|
||||
};
|
||||
|
||||
if (this.isTesterPermission) {
|
||||
this.result = this.$post('user/org/member/list/all', param, response => {
|
||||
this.scheduleReceiverOptions = response.data
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
buildParam() {
|
||||
let param = {};
|
||||
param.notices = this.tableData
|
||||
param.testId = this.testId
|
||||
return param;
|
||||
},
|
||||
open(row) {
|
||||
this.testId = row.id;
|
||||
this.findSchedule(row.id);
|
||||
this.initUserList();
|
||||
this.dialogVisible = true;
|
||||
this.form.cronValue = this.schedule.value;
|
||||
listenGoBack(this.close);
|
||||
this.activeName = 'first'
|
||||
},
|
||||
findSchedule(){
|
||||
var scenarioID = this.testId;
|
||||
this.result = this.$get("/schedule/findOne/"+scenarioID+"/API_SCENARIO_TEST", 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.testId;
|
||||
let url = '/api/automation/schedule/create';
|
||||
if (param.id) {
|
||||
url = '/api/automation/schedule/update';
|
||||
}
|
||||
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;
|
||||
},
|
||||
saveNotice() {
|
||||
let param = this.buildParam();
|
||||
this.result = this.$post("notice/save", param, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
})
|
||||
},
|
||||
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>
|
|
@ -0,0 +1,251 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col :span="10">
|
||||
<el-button :disabled="!isTesterPermission" icon="el-icon-circle-plus-outline" plain size="mini"
|
||||
@click="handleAddTaskModel">
|
||||
{{ $t('organization.message.create_new_notification') }}
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-table
|
||||
:data="scheduleTask"
|
||||
class="tb-edit"
|
||||
border
|
||||
:cell-style="rowClass"
|
||||
:header-cell-style="headClass">
|
||||
<el-table-column :label="$t('schedule.event')" prop="events" min-width="13%">
|
||||
<template slot-scope="scope">
|
||||
<el-select v-model="scope.row.event" size="mini"
|
||||
:placeholder="$t('organization.message.select_events')"
|
||||
prop="events" :disabled="!scope.row.isSet">
|
||||
<el-option
|
||||
v-for="item in scheduleEventOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('schedule.receiver')" prop="userIds" min-width="18%">
|
||||
<template v-slot:default="{row}">
|
||||
<el-select v-model="row.userIds" filterable multiple size="mini"
|
||||
:placeholder="$t('commons.please_select')" style="width: 100%;" :disabled="!row.isSet">
|
||||
<el-option
|
||||
v-for="item in scheduleReceiverOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('schedule.receiving_mode')" prop="type" min-width="15%">
|
||||
<template slot-scope="scope">
|
||||
<el-select v-model="scope.row.type" :placeholder="$t('organization.message.select_receiving_method')"
|
||||
size="mini"
|
||||
:disabled="!scope.row.isSet" @change="handleEdit(scope.$index, scope.row)"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in receiveTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="webhook" min-width="20%" prop="webhook">
|
||||
<template v-slot:default="scope">
|
||||
<el-input v-model="scope.row.webhook" placeholder="webhook地址" size="mini"
|
||||
:disabled="!scope.row.isSet||!scope.row.isReadOnly"></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.operating')" prop="result" min-width="25%">
|
||||
<template v-slot:default="scope">
|
||||
<el-button
|
||||
type="success"
|
||||
size="mini"
|
||||
v-if="scope.row.isSet"
|
||||
v-xpack
|
||||
@click="handleTemplate(scope.$index,scope.row)"
|
||||
>{{ $t('organization.message.template') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="mini"
|
||||
v-show="scope.row.isSet"
|
||||
:disabled="!isTesterPermission"
|
||||
@click="handleAddTask(scope.$index,scope.row)"
|
||||
>{{ $t('commons.add') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
v-show="scope.row.isSet"
|
||||
:disabled="!isTesterPermission"
|
||||
@click.native.prevent="removeRowTask(scope.$index,scheduleTask)"
|
||||
>{{ $t('commons.cancel') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="mini"
|
||||
v-show="!scope.row.isSet"
|
||||
:disabled="!isTesterPermission"
|
||||
@click="handleEditTask(scope.$index,scope.row)"
|
||||
>{{ $t('commons.edit') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
v-show="!scope.row.isSet"
|
||||
:disabled="!isTesterPermission"
|
||||
@click.native.prevent="deleteRowTask(scope.$index,scope.row)"
|
||||
></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- <notice-template v-xpack ref="noticeTemplate"/>-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {hasLicense} from "@/common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "ScheduleNotification",
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
testId: String,
|
||||
scheduleReceiverOptions: Array,
|
||||
isTesterPermission: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
scheduleTask: [{
|
||||
taskType: "scheduleTask",
|
||||
event: "",
|
||||
userIds: [],
|
||||
type: [],
|
||||
webhook: "",
|
||||
isSet: true,
|
||||
identification: "",
|
||||
isReadOnly: false,
|
||||
testId: this.testId,
|
||||
}],
|
||||
scheduleEventOptions: [
|
||||
{value: 'EXECUTE_SUCCESSFUL', label: this.$t('schedule.event_success')},
|
||||
{value: 'EXECUTE_FAILED', label: this.$t('schedule.event_failed')}
|
||||
],
|
||||
receiveTypeOptions: [
|
||||
{value: 'EMAIL', label: this.$t('organization.message.mail')},
|
||||
{value: 'NAIL_ROBOT', label: this.$t('organization.message.nail_robot')},
|
||||
{value: 'WECHAT_ROBOT', label: this.$t('organization.message.enterprise_wechat_robot')}
|
||||
],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initForm()
|
||||
},
|
||||
methods: {
|
||||
initForm() {
|
||||
this.result = this.$get('/notice/search/message/' + this.testId, response => {
|
||||
// console.log(response.data);
|
||||
this.scheduleTask = response.data;
|
||||
})
|
||||
},
|
||||
handleEdit(index, data) {
|
||||
data.isReadOnly = true;
|
||||
if (data.type === 'EMAIL') {
|
||||
data.isReadOnly = !data.isReadOnly;
|
||||
data.webhook = '';
|
||||
}
|
||||
},
|
||||
handleAddTaskModel() {
|
||||
let Task = {};
|
||||
Task.event = [];
|
||||
Task.userIds = [];
|
||||
Task.type = '';
|
||||
Task.webhook = '';
|
||||
Task.isSet = true;
|
||||
Task.identification = '';
|
||||
Task.taskType = 'SCHEDULE_TASK';
|
||||
Task.testId = this.testId;
|
||||
this.scheduleTask.push(Task);
|
||||
},
|
||||
handleEditTask(index, data) {
|
||||
data.isSet = true;
|
||||
data.testId = this.testId;
|
||||
if (data.type === 'EMAIL') {
|
||||
data.isReadOnly = false;
|
||||
data.webhook = '';
|
||||
} else {
|
||||
data.isReadOnly = true;
|
||||
}
|
||||
},
|
||||
handleAddTask(index, data) {
|
||||
if (data.event && data.userIds.length > 0 && data.type) {
|
||||
// console.log(data.type)
|
||||
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
|
||||
if (!data.webhook) {
|
||||
this.$warning(this.$t('organization.message.message_webhook'));
|
||||
} else {
|
||||
this.addTask(data)
|
||||
}
|
||||
} else {
|
||||
this.addTask(data)
|
||||
}
|
||||
} else {
|
||||
this.$warning(this.$t('organization.message.message'));
|
||||
}
|
||||
},
|
||||
addTask(data) {
|
||||
this.result = this.$post("/notice/save/message/task", data, () => {
|
||||
this.initForm()
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
})
|
||||
},
|
||||
removeRowTask(index, data) { //移除
|
||||
if (!data[index].identification) {
|
||||
data.splice(index, 1)
|
||||
} else {
|
||||
data[index].isSet = false;
|
||||
}
|
||||
},
|
||||
deleteRowTask(index, data) { //删除
|
||||
this.result = this.$get("/notice/delete/message/" + data.identification, response => {
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
this.initForm()
|
||||
})
|
||||
},
|
||||
rowClass() {
|
||||
return "text-align:center"
|
||||
},
|
||||
headClass() {
|
||||
return "text-align:center;background:'#ededed'"
|
||||
},
|
||||
handleTemplate(index, row) {
|
||||
if (hasLicense()) {
|
||||
this.$refs.noticeTemplate.open(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-row {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -83,14 +83,14 @@
|
|||
{{apiCountData.runningCount}}
|
||||
</span>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<el-col style="margin-top: 5px;">
|
||||
<span class="default-property">
|
||||
{{$t('api_test.home_page.detail_card.not_started')}}
|
||||
{{"\xa0\xa0"}}
|
||||
{{apiCountData.notStartedCount}}
|
||||
</span>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<el-col style="margin-top: 5px;">
|
||||
<span class="main-property">
|
||||
{{$t('api_test.home_page.detail_card.finished')}}
|
||||
{{"\xa0\xa0"}}
|
||||
|
@ -157,10 +157,11 @@ export default {
|
|||
box-shadow: 0 0px 0px 0 rgba(0,0,0,.1);
|
||||
}
|
||||
.default-property{
|
||||
|
||||
font-size: 12px
|
||||
}
|
||||
.main-property{
|
||||
color: #F39021;
|
||||
font-size: 12px
|
||||
}
|
||||
|
||||
.el-card /deep/ .el-card__header {
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
<span class="count-number">
|
||||
{{sceneCountData.allApiDataCountNumber}}
|
||||
</span>
|
||||
{{$t('api_test.home_page.unit_of_measurement')}}
|
||||
<span style="color: #6C317C;">
|
||||
{{$t('api_test.home_page.unit_of_measurement')}}
|
||||
</span>
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
|
@ -65,12 +67,14 @@
|
|||
{{sceneCountData.unexecuteCount}}
|
||||
</span>
|
||||
</el-col>
|
||||
<el-col>
|
||||
{{$t('api_test.home_page.detail_card.execution_failed')}}
|
||||
{{"\xa0\xa0"}}
|
||||
{{sceneCountData.executionFailedCount}}
|
||||
<el-col style="margin-top: 5px;">
|
||||
<span class="defaultProperty">
|
||||
{{$t('api_test.home_page.detail_card.execution_failed')}}
|
||||
{{"\xa0\xa0"}}
|
||||
{{sceneCountData.executionFailedCount}}
|
||||
</span>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<el-col style="margin-top: 5px;">
|
||||
<span class="main-property">
|
||||
{{$t('api_test.home_page.detail_card.execution_pass')}}
|
||||
{{"\xa0\xa0"}}
|
||||
|
@ -141,10 +145,11 @@ export default {
|
|||
box-shadow: 0 0px 0px 0 rgba(0,0,0,.1);
|
||||
}
|
||||
.defaultProperty{
|
||||
|
||||
font-size: 12px
|
||||
}
|
||||
.main-property{
|
||||
color: #F39021;
|
||||
font-size: 12px
|
||||
}
|
||||
|
||||
.el-card /deep/ .el-card__header {
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
<span class="count-number">
|
||||
{{scheduleTaskCountData.allApiDataCountNumber}}
|
||||
</span>
|
||||
{{$t('api_test.home_page.unit_of_measurement')}}
|
||||
<span style="color: #6C317C;">
|
||||
{{$t('api_test.home_page.unit_of_measurement')}}
|
||||
</span>
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
|
@ -66,9 +68,9 @@
|
|||
{{scheduleTaskCountData.failedCount}}
|
||||
</span>
|
||||
</el-col>
|
||||
<el-col style=" height: 20px">
|
||||
<el-col style=" height: 20px;margin-top: 3px;">
|
||||
</el-col>
|
||||
<el-col>
|
||||
<el-col style="margin-top: 5px;">
|
||||
<span class="main-property">
|
||||
{{$t('api_test.home_page.detail_card.success')}}
|
||||
{{"\xa0\xa0"}}
|
||||
|
@ -146,10 +148,11 @@ export default {
|
|||
box-shadow: 0 0px 0px 0 rgba(0,0,0,.1);
|
||||
}
|
||||
.default-property{
|
||||
|
||||
font-size: 12px
|
||||
}
|
||||
.main-property{
|
||||
color: #F39021;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.el-card /deep/ .el-card__header {
|
||||
|
|
|
@ -99,9 +99,9 @@
|
|||
{{testCaseCountData.uncoverageCount}}
|
||||
</span>
|
||||
</el-col>
|
||||
<el-col style=" height: 20px">
|
||||
<el-col style=" height: 20px;margin-top: 3px;">
|
||||
</el-col>
|
||||
<el-col>
|
||||
<el-col style="margin-top: 5px;">
|
||||
<span class="main-property">
|
||||
{{$t('api_test.home_page.detail_card.coverage')}}
|
||||
{{"\xa0\xa0"}}
|
||||
|
@ -176,10 +176,11 @@ export default {
|
|||
box-shadow: 0 0px 0px 0 rgba(0,0,0,.1);
|
||||
}
|
||||
.default-property{
|
||||
|
||||
font-size: 12px
|
||||
}
|
||||
.main-property{
|
||||
color: #F39021;
|
||||
font-size: 12px
|
||||
}
|
||||
|
||||
.el-card /deep/ .el-card__header {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<link rel="shortcut icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title>MeterSphere</title>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<link rel="shortcut icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title>MeterSphere</title>
|
||||
</head>
|
||||
<body>
|
||||
|
|
Loading…
Reference in New Issue