Merge remote-tracking branch 'origin/master'

This commit is contained in:
wenyann 2021-01-28 14:07:19 +08:00
commit 4102e2e667
17 changed files with 162 additions and 98 deletions

View File

@ -217,7 +217,7 @@ public class ApiAutomationService {
ids.add(scenarioId);
deleteApiScenarioReport(ids);
scheduleService.deleteByResourceId(scenarioId);
scheduleService.deleteScheduleAndJobByResourceId(scenarioId,ScheduleGroup.API_SCENARIO_TEST.name());
TestPlanApiScenarioExample example = new TestPlanApiScenarioExample();
example.createCriteria().andApiScenarioIdEqualTo(scenarioId);
List<TestPlanApiScenario> testPlanApiScenarioList = testPlanApiScenarioMapper.selectByExample(example);
@ -282,6 +282,10 @@ public class ApiAutomationService {
public void removeToGc(List<String> apiIds) {
extApiScenarioMapper.removeToGc(apiIds);
//将这些场景的定时任务删除掉
for (String id : apiIds) {
scheduleService.deleteScheduleAndJobByResourceId(id,ScheduleGroup.API_SCENARIO_TEST.name());
}
}
public void reduction(List<SaveApiScenarioRequest> requests) {

View File

@ -33,5 +33,4 @@ public interface ScheduleMapper {
int updateByPrimaryKeyWithBLOBs(Schedule record);
int updateByPrimaryKey(Schedule record);
}

View File

@ -18,10 +18,7 @@ import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.controller.request.OrderRequest;
import io.metersphere.controller.request.QueryScheduleRequest;
import io.metersphere.dto.ScheduleDao;
import io.metersphere.job.sechedule.ApiScenarioTestJob;
import io.metersphere.job.sechedule.ApiTestJob;
import io.metersphere.job.sechedule.ScheduleManager;
import io.metersphere.job.sechedule.TestPlanTestJob;
import io.metersphere.job.sechedule.*;
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobKey;
import org.quartz.SchedulerException;
@ -98,6 +95,25 @@ public class ScheduleService {
return scheduleMapper.deleteByExample(scheduleExample);
}
public int deleteScheduleAndJobByResourceId(String resourceId,String group) {
ScheduleExample scheduleExample = new ScheduleExample();
scheduleExample.createCriteria().andResourceIdEqualTo(resourceId);
removeJob(resourceId,group);
return scheduleMapper.deleteByExample(scheduleExample);
}
public void removeJob(String resourceId,String group) {
if(StringUtils.equals(ScheduleGroup.API_SCENARIO_TEST.name(),group)){
scheduleManager.removeJob(ApiScenarioTestJob.getJobKey(resourceId), ApiScenarioTestJob.getTriggerKey(resourceId));
}else if(StringUtils.equals(ScheduleGroup.TEST_PLAN_TEST.name(),group)){
scheduleManager.removeJob(TestPlanTestJob.getJobKey(resourceId), TestPlanTestJob.getTriggerKey(resourceId));
}else if(StringUtils.equals(ScheduleGroup.SWAGGER_IMPORT.name(),group)){
scheduleManager.removeJob(SwaggerUrlImportJob.getJobKey(resourceId), SwaggerUrlImportJob.getTriggerKey(resourceId));
}else{
scheduleManager.removeJob(ApiTestJob.getJobKey(resourceId), ApiTestJob.getTriggerKey(resourceId));
}
}
public List<Schedule> listSchedule() {
ScheduleExample example = new ScheduleExample();
return scheduleMapper.selectByExample(example);

View File

@ -28,6 +28,7 @@ import io.metersphere.dto.BaseSystemConfigDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.notice.sender.NoticeModel;
import io.metersphere.notice.service.NoticeSendService;
import io.metersphere.service.ScheduleService;
import io.metersphere.service.SystemParameterService;
import io.metersphere.track.Factory.ReportComponentFactory;
import io.metersphere.track.domain.ReportComponent;
@ -62,6 +63,8 @@ public class TestPlanService {
@Resource
ExtTestPlanMapper extTestPlanMapper;
@Resource
ScheduleService scheduleService;
@Resource
ExtTestPlanTestCaseMapper extTestPlanTestCaseMapper;
@Resource
TestCaseMapper testCaseMapper;
@ -315,6 +318,10 @@ public class TestPlanService {
testPlanProjectService.deleteTestPlanProjectByPlanId(planId);
testPlanApiCaseService.deleteByPlanId(planId);
testPlanScenarioCaseService.deleteByPlanId(planId);
//删除定时任务
scheduleService.deleteScheduleAndJobByResourceId(planId,ScheduleGroup.TEST_PLAN_TEST.name());
int num = testPlanMapper.deleteByPrimaryKey(planId);
List<String> relatedUsers = new ArrayList<>();
AddTestPlanRequest testPlans = new AddTestPlanRequest();

BIN
frontend/src/assets/info.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

After

Width:  |  Height:  |  Size: 169 KiB

View File

@ -286,8 +286,7 @@
},
response: {}
}
}
,
},
created() {
if (!this.currentScenario.apiScenarioModuleId) {
this.currentScenario.apiScenarioModuleId = "";
@ -857,6 +856,9 @@
if (this.currentScenario.tags != undefined && !(this.currentScenario.tags instanceof Array)) {
this.currentScenario.tags = JSON.parse(this.currentScenario.tags);
}
if (!this.currentScenario.variables) {
this.currentScenario.variables = [];
}
if (this.currentScenario.id) {
this.result = this.$get("/api/automation/getApiScenario/" + this.currentScenario.id, response => {
if (response.data) {
@ -1044,7 +1046,7 @@
.ms-tree >>> .el-icon-caret-right:before {
content: '\e723';
font-size: 18px;
font-size: 20px;
}
.ms-tree >>> .el-tree-node__expand-icon.is-leaf {
@ -1058,6 +1060,6 @@
.ms-tree >>> .el-tree-node__expand-icon.expanded.el-icon-caret-right:before {
color: #7C3985;
content: "\e722";
font-size: 18px;
font-size: 20px;
}
</style>

View File

@ -37,15 +37,17 @@
</el-tooltip>
</div>
</div>
<div class="header">
<el-collapse-transition>
<div v-if="data.active && showCollapse" :draggable="draggable">
<fieldset :disabled="data.disabled" class="ms-fieldset">
<el-divider></el-divider>
<slot></slot>
</fieldset>
</div>
</el-collapse-transition>
</div>
<el-collapse-transition>
<div v-if="data.active && showCollapse" :draggable="draggable">
<fieldset :disabled="data.disabled" style="border: 0px">
<el-divider></el-divider>
<slot></slot>
</fieldset>
</div>
</el-collapse-transition>
</el-card>
</template>
@ -148,5 +150,12 @@
.enable-switch {
margin-right: 10px;
}
fieldset {
padding: 0px;
margin: 0px;
min-width: 100%;
min-inline-size: 0px;
border: 0px;
}
</style>

View File

@ -76,18 +76,20 @@
</el-select>
<el-input size="small" v-model="controller.whileController.value" :placeholder="$t('api_test.value')" v-if="!hasEmptyOperator" style="width: 20%;margin-left: 20px"/>
<span class="ms-span ms-radio">{{$t('loop.timeout')}}</span>
<el-input-number size="small" v-model="controller.whileController.timeout" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="1" :step="1000"/>
<el-input-number size="small" v-model="controller.whileController.timeout" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="3000" :step="1000"/>
<span class="ms-span ms-radio">ms</span>
</div>
<p class="tip">{{$t('api_test.definition.request.res_param')}} </p>
<el-tabs v-model="activeName">
<el-tab-pane :label="item.name" :name="item.name" v-for="(item,index) in requestResult.scenarios" :key="index">
<div v-for="(result,i) in item.requestResults" :key="i" style="margin-bottom: 5px">
<api-response-component :result="result"/>
</div>
</el-tab-pane>
</el-tabs>
<div>
<el-tabs v-model="activeName" closable class="ms-tabs">
<el-tab-pane :label="item.name" :name="item.name" v-for="(item,index) in requestResult.scenarios" :key="index">
<div v-for="(result,i) in item.requestResults" :key="i" style="margin-bottom: 5px">
<api-response-component :result="result"/>
</div>
</el-tab-pane>
</el-tabs>
</div>
</api-base-component>
@ -331,6 +333,11 @@
margin: 20px 0;
}
.ms-tabs >>> .el-icon-close:before {
content: "";
}
.icon.is-active {
transform: rotate(90deg);
}

View File

@ -30,6 +30,11 @@
this.$refs.nameInput.focus();
});
},
watch: {
editData() {
this.$refs.nameInput.focus();
}
}
}
</script>

View File

@ -124,7 +124,7 @@ import MsContainer from "../../../../common/components/MsContainer";
import MsBottomContainer from "../BottomContainer";
import ShowMoreBtn from "../../../../track/case/components/ShowMoreBtn";
import MsBatchEdit from "../basis/BatchEdit";
import {API_METHOD_COLOUR, CASE_PRIORITY, REQ_METHOD} from "../../model/JsonData";
import {API_METHOD_COLOUR, CASE_PRIORITY, DUBBO_METHOD, REQ_METHOD, SQL_METHOD, TCP_METHOD} from "../../model/JsonData";
import {getBodyUploadFiles, getCurrentProjectID} from "@/common/js/utils";
import ApiListContainer from "./ApiListContainer";
@ -409,6 +409,15 @@ export default {
// }
},
handleEditBatch() {
if(this.currentProtocol =='HTTP'){
this.valueArr.method = REQ_METHOD;
}else if(this.currentProtocol =='TCP'){
this.valueArr.method = TCP_METHOD;
}else if(this.currentProtocol =='SQL'){
this.valueArr.method = SQL_METHOD;
}else if(this.currentProtocol =='DUBBO'){
this.valueArr.method = DUBBO_METHOD;
}
this.$refs.batchEdit.open();
},
batchEdit(form) {

View File

@ -162,11 +162,10 @@
import MsBottomContainer from "../BottomContainer";
import ShowMoreBtn from "../../../../track/case/components/ShowMoreBtn";
import MsBatchEdit from "../basis/BatchEdit";
import {API_METHOD_COLOUR, API_STATUS, REQ_METHOD} from "../../model/JsonData";
import {API_METHOD_COLOUR, API_STATUS, REQ_METHOD,TCP_METHOD,SQL_METHOD,DUBBO_METHOD} from "../../model/JsonData";
import {_filter, _sort, getCurrentProjectID} from "@/common/js/utils";
import {WORKSPACE_ID} from '@/common/js/constants';
import ApiListContainer from "./ApiListContainer";
// import MsTableSelectAll from "../../../../common/components/table/MsTableSelectAll";
import MsTableHeaderSelectPopover from "@/business/components/common/components/table/MsTableHeaderSelectPopover";
import ApiStatus from "@/business/components/api/definition/components/list/ApiStatus";
import MsTableAdvSearchBar from "@/business/components/common/components/search/MsTableAdvSearchBar";
@ -513,6 +512,15 @@
}
},
handleEditBatch() {
if(this.currentProtocol =='HTTP'){
this.valueArr.method = REQ_METHOD;
}else if(this.currentProtocol =='TCP'){
this.valueArr.method = TCP_METHOD;
}else if(this.currentProtocol =='SQL'){
this.valueArr.method = SQL_METHOD;
}else if(this.currentProtocol =='DUBBO'){
this.valueArr.method = DUBBO_METHOD;
}
this.$refs.batchEdit.open();
},
batchEdit(form) {

View File

@ -235,15 +235,22 @@
this.$refs.environmentConfig.open(getCurrentProjectID());
},
initDataSource() {
let flag = false;
for (let i in this.environments) {
if (this.environments[i].id === this.request.environmentId) {
this.databaseConfigsOptions = [];
this.environments[i].config.databaseConfigs.forEach(item => {
if (item.id === this.request.dataSourceId) {
flag = true;
}
this.databaseConfigsOptions.push(item);
});
break;
}
}
if (!flag) {
this.request.dataSourceId = undefined;
}
},
setDataSource() {
for (let item of this.databaseConfigsOptions) {

View File

@ -44,6 +44,15 @@ export const REQ_METHOD = [
{id: 'HEAD', label: 'HEAD'},
{id: 'CONNECT', label: 'CONNECT'}
]
export const TCP_METHOD = [
{id: 'TCP', label: 'TCP'}
]
export const SQL_METHOD = [
{id: 'SQL', label: 'SQL'}
]
export const DUBBO_METHOD = [
{id: 'dubbo://', label: 'dubbo://'},
]
export const CASE_PRIORITY = [
{id: 'P0', label: 'P0'},

View File

@ -89,9 +89,6 @@
selectRows: new Set()
}
},
created() {
this.search();
},
watch: {
selectNodeIds() {
this.search();
@ -102,6 +99,9 @@
},
methods: {
search() {
if (!this.projectId) {
return;
}
this.selectRows = new Set();
this.loading = true;

View File

@ -75,6 +75,9 @@
methods: {
open() {
this.$refs.baseRelevance.open();
if (this.$refs.apiScenarioList) {
this.$refs.apiScenarioList.search();
}
},
setProject(projectId) {
this.projectId = projectId;

View File

@ -47,7 +47,7 @@
<div class="divider"/>
<el-col :span="12">
<img :src="'/display/file/loginImage'" style="height: 568px; width: 100%">
<img class="login-image" :src="'/display/file/loginImage'">
</el-col>
</el-row>
@ -66,15 +66,6 @@ const auth = requireComponent.keys().length > 0 ? requireComponent("./auth/Auth.
export default {
name: "Login",
data() {
/*let validateEmail = (rule, value, callback) => {
// eslint-disable-next-line no-useless-escape
let EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if (!EMAIL_REGEX.test(value)) {
callback(new Error('邮箱格式不正确'));
} else {
callback();
}
};*/
return {
result: {},
form: {
@ -192,66 +183,51 @@ export default {
<style scoped>
.container {
min-width: 800px;
max-width: 1440px;
height: 568px;
margin: calc((100vh - 568px) / 2) auto 0;
width: 1440px;
height: 810px;
margin: calc((100vh - 810px) / 2) auto 0;
background-color: #FFFFFF;
}
.image {
background: url(../assets/info.png);
.el-col:nth-child(3) {
align-items: center;
display: flex;
}
.login-logo {
background: url(../assets/logo-dark-MeterSphere.svg);
}
.logo-header {
background: url(../assets/logo-light-MeterSphere.svg);
}
.el-col {
height: 568px;
.title img {
width: 293px;
margin-top: 165px;
}
.title-img {
font-size: 32px;
letter-spacing: 0;
text-align: center;
}
.login-image {
height: 365px;
width: 567px;
margin: auto;
display: block;
}
.welcome {
margin-top: 10px;
margin-bottom: 50px;
font-size: 18px;
margin-top: 12px;
margin-bottom: 75px;
font-size: 14px;
color: #843697;
line-height: 18px;
line-height: 14px;
text-align: center;
}
.form {
padding: 0 40px;
}
.title {
height: 50%;
}
.content {
height: 50%;
padding: 0px 90px;
margin-top: -20px;
}
.btn {
margin-top: 40px;
padding: 0 40px;
.form,.btn {
padding: 0;
width: 443px;
margin: auto;
}
.btn > .submit {
width: 100%;
border-radius: 50px;
border-radius: 70px;
border-color: #8B479B;
background-color: #8B479B;
}
@ -266,11 +242,8 @@ export default {
background-color: rgba(139, 71, 155, 0.8);
}
.msg {
margin-top: 10px;
padding: 0 40px;
color: red;
text-align: center;
.el-form-item:first-child {
margin-top: 60px;
}
/deep/ .el-radio__input.is-checked .el-radio__inner {
@ -284,23 +257,25 @@ export default {
}
/deep/ .el-input__inner {
border-radius: 70px !important;
background: #f6f3f8 !important;
border-color: #f6f3f8;
border-radius: 50px !important;
border-color: #f6f3f8 !important;
/*谷歌浏览器默认填充的颜色无法替换,使用下列样式填充*/
box-shadow: inset 0 0 0 1000px #f6f3f8 !important;
}
.el-input,.el-button {
width: 443px;
}
/deep/ .el-input__inner:focus {
border: 1px solid #783887;
border: 1px solid #783887 !important;
}
.divider {
border: 1px solid #f6f3f8;
margin: 20px;
}
.title img {
height: 60px;
margin-top: 120px;
height: 480px;
margin: 165px 0px;
}
.welcome span:first-child {
@ -314,7 +289,7 @@ export default {
body {
font-family: -apple-system, BlinkMacSystemFont, "Neue Haas Grotesk Text Pro", "Arial Nova", "Segoe UI", "Helvetica Neue", ".PingFang SC", "PingFang SC", "Source Han Sans SC", "Noto Sans CJK SC", "Source Han Sans CN", "Noto Sans SC", "Source Han Sans TC", "Noto Sans CJK TC", "Hiragino Sans GB", sans-serif;
font-size: 14px;
background-color: #F5F5F5;
/*background-color: #F5F5F5;*/
line-height: 26px;
color: #2B415C;
-webkit-font-smoothing: antialiased;

View File

@ -4,6 +4,10 @@ import 'element-ui/lib/theme-chalk/index.css';
import Login from "./Login.vue";
import Ajax from "../common/js/ajax";
import i18n from "../i18n/i18n";
// 引用静态资源,去掉打包将缺失图片
import infoImg from "../assets/info.png";
import loginLogo from "../assets/logo-dark-MeterSphere.svg";
import logoHeader from "../assets/logo-light-MeterSphere.svg";
Vue.config.productionTip = false;