diff --git a/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java b/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java index d7500fdc88..f27e6e0265 100644 --- a/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java +++ b/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java @@ -19,6 +19,7 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; + import java.util.List; @RestController @@ -81,5 +82,10 @@ public class ApiAutomationController { apiAutomationService.run(request); } + @PostMapping("/getReference") + public List getReference(@RequestBody ApiScenarioRequest request) { + return apiAutomationService.getReference(request); + } + } diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/SaveApiScenarioRequest.java b/backend/src/main/java/io/metersphere/api/dto/automation/SaveApiScenarioRequest.java index 9d25b4e257..1256a3c350 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/SaveApiScenarioRequest.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/SaveApiScenarioRequest.java @@ -1,5 +1,6 @@ package io.metersphere.api.dto.automation; +import io.metersphere.api.dto.definition.request.MsTestElement; import lombok.Getter; import lombok.Setter; @@ -36,7 +37,7 @@ public class SaveApiScenarioRequest { private String description; - private String scenarioDefinition; + private MsTestElement scenarioDefinition; List bodyUploadIds; } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java index 48fc7ec826..b49d589d42 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java @@ -7,6 +7,7 @@ import com.alibaba.fastjson.annotation.JSONType; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import io.metersphere.api.dto.scenario.KeyValue; import io.metersphere.api.dto.scenario.environment.EnvironmentConfig; import io.metersphere.api.service.ApiAutomationService; import io.metersphere.api.service.ApiTestEnvironmentService; @@ -36,6 +37,9 @@ public class MsScenario extends MsTestElement { @JSONField(ordinal = 12) private String environmentId; + @JSONField(ordinal = 13) + private List variables; + public void toHashTree(HashTree tree, List hashTree, EnvironmentConfig config) { if (environmentId != null) { ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class); diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsTestElement.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsTestElement.java index 76e6349495..ad11c71b03 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsTestElement.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsTestElement.java @@ -60,6 +60,14 @@ public class MsTestElement { @JSONField(ordinal = 3) private String label; @JSONField(ordinal = 4) + private String resourceId; + @JSONField(ordinal = 5) + private String referenced; + @JSONField(ordinal = 6) + private boolean active; + @JSONField(ordinal = 7) + private String index; + @JSONField(ordinal = 8) private LinkedList hashTree; // 公共环境逐层传递,如果自身有环境 以自身引用环境为准否则以公共环境作为请求环境 diff --git a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java index 6b739e95ad..9495b07219 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -34,6 +34,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; + import java.io.*; import java.util.ArrayList; import java.util.LinkedList; @@ -101,7 +102,7 @@ public class ApiAutomationService { scenario.setFollowPeople(request.getFollowPeople()); scenario.setPrincipal(request.getPrincipal()); scenario.setStepTotal(request.getStepTotal()); - scenario.setScenarioDefinition(request.getScenarioDefinition()); + scenario.setScenarioDefinition(JSON.toJSONString(request.getScenarioDefinition())); scenario.setCreateTime(System.currentTimeMillis()); scenario.setUpdateTime(System.currentTimeMillis()); if (StringUtils.isNotEmpty(request.getStatus())) { @@ -137,7 +138,7 @@ public class ApiAutomationService { scenario.setFollowPeople(request.getFollowPeople()); scenario.setPrincipal(request.getPrincipal()); scenario.setStepTotal(request.getStepTotal()); - scenario.setScenarioDefinition(request.getScenarioDefinition()); + scenario.setScenarioDefinition(JSON.toJSONString(request.getScenarioDefinition())); scenario.setUpdateTime(System.currentTimeMillis()); if (StringUtils.isNotEmpty(request.getStatus())) { scenario.setStatus(request.getStatus()); @@ -299,4 +300,8 @@ public class ApiAutomationService { createAPIReportResult(request.getId()); return request.getId(); } + + public List getReference(ApiScenarioRequest request) { + return extApiScenarioMapper.selectReference(request); + } } diff --git a/backend/src/main/java/io/metersphere/base/domain/MessageTask.java b/backend/src/main/java/io/metersphere/base/domain/MessageTask.java index 56a1d14d7a..03866ff546 100644 --- a/backend/src/main/java/io/metersphere/base/domain/MessageTask.java +++ b/backend/src/main/java/io/metersphere/base/domain/MessageTask.java @@ -1,8 +1,9 @@ package io.metersphere.base.domain; -import java.io.Serializable; import lombok.Data; +import java.io.Serializable; + @Data public class MessageTask implements Serializable { private String id; @@ -27,5 +28,7 @@ public class MessageTask implements Serializable { private Long createTime; + private String template; + private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ApiDataViewMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ApiDataViewMapper.xml index 671a97fdb5..fe6d86d421 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ApiDataViewMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ApiDataViewMapper.xml @@ -15,7 +15,7 @@ - select report_id from api_data_view where response_code != 200 and url=#{apiUrl} and start_time=#{startTime}; + select report_id from api_data_view where url=#{apiUrl} and start_time=#{startTime}; diff --git a/backend/src/main/java/io/metersphere/base/mapper/MessageTaskMapper.java b/backend/src/main/java/io/metersphere/base/mapper/MessageTaskMapper.java index a65b6a46f3..1220f9d2da 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/MessageTaskMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/MessageTaskMapper.java @@ -2,9 +2,10 @@ package io.metersphere.base.mapper; import io.metersphere.base.domain.MessageTask; import io.metersphere.base.domain.MessageTaskExample; -import java.util.List; import org.apache.ibatis.annotations.Param; +import java.util.List; + public interface MessageTaskMapper { long countByExample(MessageTaskExample example); @@ -16,15 +17,21 @@ public interface MessageTaskMapper { int insertSelective(MessageTask record); + List selectByExampleWithBLOBs(MessageTaskExample example); + List selectByExample(MessageTaskExample example); MessageTask selectByPrimaryKey(String id); int updateByExampleSelective(@Param("record") MessageTask record, @Param("example") MessageTaskExample example); + int updateByExampleWithBLOBs(@Param("record") MessageTask record, @Param("example") MessageTaskExample example); + int updateByExample(@Param("record") MessageTask record, @Param("example") MessageTaskExample example); int updateByPrimaryKeySelective(MessageTask record); + int updateByPrimaryKeyWithBLOBs(MessageTask record); + int updateByPrimaryKey(MessageTask record); } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/MessageTaskMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/MessageTaskMapper.xml index c3d7a6ae5e..64d5f3312e 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/MessageTaskMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/MessageTaskMapper.xml @@ -2,17 +2,20 @@ - - - - - - - - - - - + + + + + + + + + + + + + + @@ -25,13 +28,13 @@ and ${criterion.condition} - and ${criterion.condition} #{criterion.value} + AND ${criterion.condition} #{criterion.value} - and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} + AND ${criterion.condition} #{criterion.value} AND #{criterion.secondValue} - and ${criterion.condition} + AND ${criterion.condition} #{listItem} @@ -76,6 +79,25 @@ id, `type`, event, user_id, task_type, webhook, identification, is_set, organization_id, test_id, create_time + + `template` + + - select + , + from message_task where id = #{id,jdbcType=VARCHAR} @@ -107,14 +131,16 @@ - insert into message_task (id, `type`, event, - user_id, task_type, webhook, - identification, is_set, organization_id, - test_id, create_time) - values (#{id,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR}, #{event,jdbcType=VARCHAR}, - #{userId,jdbcType=VARCHAR}, #{taskType,jdbcType=VARCHAR}, #{webhook,jdbcType=VARCHAR}, - #{identification,jdbcType=VARCHAR}, #{isSet,jdbcType=BIT}, #{organizationId,jdbcType=VARCHAR}, - #{testId,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}) + INSERT INTO message_task (id, `type`, event, + user_id, task_type, webhook, + identification, is_set, organization_id, + test_id, create_time, `template` + ) + VALUES (#{id,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR}, #{event,jdbcType=VARCHAR}, + #{userId,jdbcType=VARCHAR}, #{taskType,jdbcType=VARCHAR}, #{webhook,jdbcType=VARCHAR}, + #{identification,jdbcType=VARCHAR}, #{isSet,jdbcType=BIT}, #{organizationId,jdbcType=VARCHAR}, + #{testId,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{template,jdbcType=LONGVARCHAR} + ) insert into message_task @@ -152,6 +178,9 @@ create_time, + + `template`, + @@ -187,6 +216,9 @@ #{createTime,jdbcType=BIGINT}, + + #{template,jdbcType=LONGVARCHAR}, + + + + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/notice/domain/MessageDetail.java b/backend/src/main/java/io/metersphere/notice/domain/MessageDetail.java index 9f4c94ca5f..431a7b67f0 100644 --- a/backend/src/main/java/io/metersphere/notice/domain/MessageDetail.java +++ b/backend/src/main/java/io/metersphere/notice/domain/MessageDetail.java @@ -17,4 +17,5 @@ public class MessageDetail { private Boolean isSet; private String testId; private Long createTime; + private String template; } diff --git a/backend/src/main/java/io/metersphere/notice/sender/AbstractNoticeSender.java b/backend/src/main/java/io/metersphere/notice/sender/AbstractNoticeSender.java index 27da4a75dc..fdde00c1fb 100644 --- a/backend/src/main/java/io/metersphere/notice/sender/AbstractNoticeSender.java +++ b/backend/src/main/java/io/metersphere/notice/sender/AbstractNoticeSender.java @@ -5,7 +5,9 @@ import io.metersphere.commons.utils.LogUtil; import io.metersphere.notice.domain.MessageDetail; import io.metersphere.notice.domain.UserDetail; import io.metersphere.service.UserService; +import org.apache.commons.collections4.MapUtils; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.RegExUtils; import org.apache.commons.lang3.StringUtils; import javax.annotation.Resource; @@ -14,6 +16,7 @@ import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; public abstract class AbstractNoticeSender implements NoticeSender { @@ -21,13 +24,16 @@ public abstract class AbstractNoticeSender implements NoticeSender { private UserService userService; protected String getContext(MessageDetail messageDetail, NoticeModel noticeModel) { + // 如果配置了模版就直接使用模版 + if (StringUtils.isNotBlank(messageDetail.getTemplate())) { + return getContent(messageDetail.getTemplate(), noticeModel.getParamMap()); + } // 处理 userIds 中包含的特殊值 List realUserIds = getRealUserIds(messageDetail.getUserIds(), noticeModel.getRelatedUsers(), messageDetail.getEvent()); messageDetail.setUserIds(realUserIds); // 处理 WeCom Ding context String context = ""; - String status = noticeModel.getStatus(); switch (messageDetail.getEvent()) { case NoticeConstants.Event.CREATE: case NoticeConstants.Event.UPDATE: @@ -48,6 +54,10 @@ public abstract class AbstractNoticeSender implements NoticeSender { } protected String getHtmlContext(MessageDetail messageDetail, NoticeModel noticeModel) { + // 如果配置了模版就直接使用模版 + if (StringUtils.isNotBlank(messageDetail.getTemplate())) { + return getContent(messageDetail.getTemplate(), noticeModel.getParamMap()); + } // 处理 userIds 中包含的特殊值 List realUserIds = getRealUserIds(messageDetail.getUserIds(), noticeModel.getRelatedUsers(), messageDetail.getEvent()); messageDetail.setUserIds(realUserIds); @@ -77,7 +87,20 @@ public abstract class AbstractNoticeSender implements NoticeSender { } catch (IOException e) { LogUtil.error(e); } - return context; + return getContent(context, noticeModel.getParamMap()); + } + + protected String getContent(String template, Map context) { + if (MapUtils.isNotEmpty(context)) { + for (String k : context.keySet()) { + if (context.get(k) != null) { + template = RegExUtils.replaceAll(template, "\\$\\{" + k + "}", context.get(k).toString()); + } else { + template = RegExUtils.replaceAll(template, "\\$\\{" + k + "}", "未设置"); + } + } + } + return template; } protected List getUserPhones(List userIds) { diff --git a/backend/src/main/java/io/metersphere/notice/sender/impl/MailNoticeSender.java b/backend/src/main/java/io/metersphere/notice/sender/impl/MailNoticeSender.java index 5e1c0f3edd..dc61109f9b 100644 --- a/backend/src/main/java/io/metersphere/notice/sender/impl/MailNoticeSender.java +++ b/backend/src/main/java/io/metersphere/notice/sender/impl/MailNoticeSender.java @@ -5,8 +5,6 @@ import io.metersphere.notice.domain.MessageDetail; import io.metersphere.notice.sender.AbstractNoticeSender; import io.metersphere.notice.sender.NoticeModel; import io.metersphere.notice.service.MailService; -import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.RegExUtils; import org.springframework.mail.javamail.JavaMailSenderImpl; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Component; @@ -15,14 +13,13 @@ import javax.annotation.Resource; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import java.util.List; -import java.util.Map; @Component public class MailNoticeSender extends AbstractNoticeSender { @Resource private MailService mailService; - private void sendMail(MessageDetail messageDetail, String template, NoticeModel noticeModel) throws MessagingException { + private void sendMail(MessageDetail messageDetail, String context, NoticeModel noticeModel) throws MessagingException { JavaMailSenderImpl javaMailSender = mailService.getMailSender(); MimeMessage mimeMessage = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); @@ -31,25 +28,11 @@ public class MailNoticeSender extends AbstractNoticeSender { List emails = super.getUserEmails(messageDetail.getUserIds()); String[] users = emails.toArray(new String[0]); LogUtil.info("收件人地址: " + emails); - helper.setText(this.getContent(template, noticeModel.getParamMap()), true); + helper.setText(context, true); helper.setTo(users); javaMailSender.send(mimeMessage); } - - public String getContent(String template, Map context) { - if (MapUtils.isNotEmpty(context)) { - for (String k : context.keySet()) { - if (context.get(k) != null) { - template = RegExUtils.replaceAll(template, "\\$\\{" + k + "}", context.get(k).toString()); - } else { - template = RegExUtils.replaceAll(template, "\\$\\{" + k + "}", "未设置"); - } - } - } - return template; - } - @Override public void send(MessageDetail messageDetail, NoticeModel noticeModel) { String context = super.getHtmlContext(messageDetail, noticeModel); diff --git a/backend/src/main/java/io/metersphere/notice/service/NoticeSendService.java b/backend/src/main/java/io/metersphere/notice/service/NoticeSendService.java index 1adc46a06b..3aea7a17cc 100644 --- a/backend/src/main/java/io/metersphere/notice/service/NoticeSendService.java +++ b/backend/src/main/java/io/metersphere/notice/service/NoticeSendService.java @@ -2,7 +2,6 @@ package io.metersphere.notice.service; import com.alibaba.nacos.client.utils.StringUtils; import io.metersphere.commons.constants.NoticeConstants; -import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.notice.domain.MessageDetail; import io.metersphere.notice.sender.NoticeModel; import io.metersphere.notice.sender.NoticeSender; @@ -22,10 +21,8 @@ public class NoticeSendService { private WeComNoticeSender weComNoticeSender; @Resource private DingNoticeSender dingNoticeSender; - - private void event(String event) { - - } + @Resource + private NoticeService noticeService; private NoticeSender getNoticeSender(MessageDetail messageDetail) { NoticeSender noticeSender = null; @@ -47,8 +44,6 @@ public class NoticeSendService { } public void send(String taskType, NoticeModel noticeModel) { - NoticeService noticeService = CommonBeanFactory.getBean(NoticeService.class); - assert noticeService != null; List messageDetails; switch (taskType) { case NoticeConstants.Mode.API: diff --git a/backend/src/main/java/io/metersphere/notice/service/NoticeService.java b/backend/src/main/java/io/metersphere/notice/service/NoticeService.java index d4abf85876..0ab7b30d26 100644 --- a/backend/src/main/java/io/metersphere/notice/service/NoticeService.java +++ b/backend/src/main/java/io/metersphere/notice/service/NoticeService.java @@ -33,14 +33,17 @@ public class NoticeService { SessionUser user = SessionUtils.getUser(); String orgId = user.getLastOrganizationId(); long time = System.currentTimeMillis(); - String identification = UUID.randomUUID().toString(); - messageDetail.getUserIds().forEach(m -> { - checkUserIdExist(m, messageDetail, orgId); + String identification = messageDetail.getIdentification(); + if (StringUtils.isBlank(identification)) { + identification = UUID.randomUUID().toString(); + } + for (String userId : messageDetail.getUserIds()) { + checkUserIdExist(userId, messageDetail, orgId); MessageTask messageTask = new MessageTask(); messageTask.setId(UUID.randomUUID().toString()); messageTask.setEvent(messageDetail.getEvent()); messageTask.setTaskType(messageDetail.getTaskType()); - messageTask.setUserId(m); + messageTask.setUserId(userId); messageTask.setType(messageDetail.getType()); messageTask.setWebhook(messageDetail.getWebhook()); messageTask.setIdentification(identification); @@ -48,8 +51,15 @@ public class NoticeService { messageTask.setOrganizationId(orgId); messageTask.setTestId(messageDetail.getTestId()); messageTask.setCreateTime(time); + setTemplate(messageDetail, messageTask); messageTaskMapper.insert(messageTask); - }); + } + } + + private void setTemplate(MessageDetail messageDetail, MessageTask messageTask) { + if (StringUtils.isNotBlank(messageDetail.getTemplate())) { + messageTask.setTemplate(messageDetail.getTemplate()); + } } private void checkUserIdExist(String userId, MessageDetail list, String orgId) { @@ -80,7 +90,7 @@ public class NoticeService { public List searchMessageByTestId(String testId) { MessageTaskExample example = new MessageTaskExample(); example.createCriteria().andTestIdEqualTo(testId); - List messageTaskLists = messageTaskMapper.selectByExample(example); + List messageTaskLists = messageTaskMapper.selectByExampleWithBLOBs(example); List scheduleMessageTask = new ArrayList<>(); Map> MessageTaskMap = messageTaskLists.stream().collect(Collectors.groupingBy(MessageTask::getIdentification)); MessageTaskMap.forEach((k, v) -> { @@ -100,7 +110,7 @@ public class NoticeService { example.createCriteria() .andTaskTypeEqualTo(type) .andOrganizationIdEqualTo(orgId); - List messageTaskLists = messageTaskMapper.selectByExample(example); + List messageTaskLists = messageTaskMapper.selectByExampleWithBLOBs(example); Map> messageTaskMap = messageTaskLists.stream() .collect(Collectors.groupingBy(NoticeService::fetchGroupKey)); @@ -130,6 +140,7 @@ public class NoticeService { messageDetail.setType(m.getType()); messageDetail.setIsSet(m.getIsSet()); messageDetail.setCreateTime(m.getCreateTime()); + messageDetail.setTemplate(m.getTemplate()); } if (CollectionUtils.isNotEmpty(userIds)) { messageDetail.setUserIds(new ArrayList<>(userIds)); diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index bb494fc68a..905ca8af61 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit bb494fc68a2367359c9048fa7250c7618de4afb6 +Subproject commit 905ca8af61ce966d26109e9c5c8c0aee3ca1324e diff --git a/backend/src/main/resources/db/migration/V48__notice_template.sql b/backend/src/main/resources/db/migration/V48__notice_template.sql new file mode 100644 index 0000000000..9e0ee80fc5 --- /dev/null +++ b/backend/src/main/resources/db/migration/V48__notice_template.sql @@ -0,0 +1,13 @@ +ALTER TABLE message_task + MODIFY identification varchar(50) NOT NULL; + +ALTER TABLE message_task + MODIFY organization_id varchar(50) NULL; + +ALTER TABLE message_task + MODIFY test_id varchar(50) NULL; + +ALTER TABLE message_task + ADD template TEXT NULL; + +DROP TABLE IF EXISTS notice; \ No newline at end of file diff --git a/frontend/src/business/App.vue b/frontend/src/business/App.vue index 4efdc55ae0..8bc9c05ee2 100644 --- a/frontend/src/business/App.vue +++ b/frontend/src/business/App.vue @@ -86,6 +86,7 @@ export default { background-color: rgb(44, 42, 72); color: rgb(245, 245, 245); font-size: 14px; + height: 40px; } .logo { diff --git a/frontend/src/business/components/api/automation/scenario/ApiCustomize.vue b/frontend/src/business/components/api/automation/scenario/ApiCustomize.vue index 32ee6990b7..41c0501d7e 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiCustomize.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiCustomize.vue @@ -56,7 +56,7 @@ }, editApi(row) { let name = this.request.name; - Object.assign(this.request, JSON.parse(row.request)); + Object.assign(this.request, row.request); this.request.name = name; this.request.resourceId = getUUID(); this.$emit('addCustomizeApi', this.request); diff --git a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue index bcd3e5a51d..07d2a80dc4 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue @@ -46,12 +46,13 @@ - + @@ -76,10 +77,11 @@ import MsTag from "../../../common/components/MsTag"; import {getUUID} from "@/common/js/utils"; import MsApiReportDetail from "../report/ApiReportDetail"; + import MsScenarioExtendButtons from "@/business/components/api/automation/scenario/ScenarioExtendBtns"; export default { name: "MsApiScenarioList", - components: {ShowMoreBtn, MsTablePagination, MsTableHeader, MsTag, MsApiReportDetail}, + components: {MsScenarioExtendButtons, ShowMoreBtn, MsTablePagination, MsTableHeader, MsTag, MsApiReportDetail}, props: { currentProject: Object, currentModule: Object, diff --git a/frontend/src/business/components/api/automation/scenario/ApiScenarioVariables.vue b/frontend/src/business/components/api/automation/scenario/ApiScenarioVariables.vue new file mode 100644 index 0000000000..8c7f0947b0 --- /dev/null +++ b/frontend/src/business/components/api/automation/scenario/ApiScenarioVariables.vue @@ -0,0 +1,111 @@ + + + + + diff --git a/frontend/src/business/components/api/automation/scenario/ApiVariableInput.vue b/frontend/src/business/components/api/automation/scenario/ApiVariableInput.vue new file mode 100644 index 0000000000..53059578a3 --- /dev/null +++ b/frontend/src/business/components/api/automation/scenario/ApiVariableInput.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue index 50bd67ebbe..8036d093fc 100644 --- a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue +++ b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue @@ -125,10 +125,12 @@ {{currentScenario.name ===undefined || ''? $t('api_test.scenario.name') : currentScenario.name}} - {{$t('api_test.automation.step_total')}}:{{scenarioDefinition.length}} + {{$t('api_test.automation.step_total')}}:{{scenarioDefinition.length}} - {{$t('api_test.automation.scenario_total')}}: + {{$t('api_test.automation.scenario_total')}}: + {{this.currentScenario.variables!=undefined?this.currentScenario.variables.length-1: 0}} + {{$t('api_test.definition.request.run_env')}}: @@ -263,6 +265,9 @@ + + + @@ -288,6 +293,7 @@ import MsImportApiScenario from "./ImportApiScenario"; import MsApiScenarioComponent from "./ApiScenarioComponent"; import MsApiReportDetail from "../report/ApiReportDetail"; + import MsScenarioParameters from "./ScenarioParameters"; export default { @@ -297,7 +303,15 @@ currentProject: {}, currentScenario: {}, }, - components: {ApiEnvironmentConfig, MsApiReportDetail, MsAddTag, MsRun, MsApiScenarioComponent, MsImportApiScenario, MsJsr233Processor, MsConstantTimer, MsIfController, MsApiAssertions, MsApiExtract, MsApiDefinition, MsApiComponent, MsApiCustomize}, + components: { + ApiEnvironmentConfig, MsScenarioParameters, + MsApiReportDetail, MsAddTag, MsRun, + MsApiScenarioComponent, MsImportApiScenario, + MsJsr233Processor, MsConstantTimer, + MsIfController, MsApiAssertions, + MsApiExtract, MsApiDefinition, + MsApiComponent, MsApiCustomize + }, data() { return { props: { @@ -648,9 +662,6 @@ if (valid) { this.setParameter(); let bodyFiles = this.getBodyUploadFiles(this.currentScenario); - console.log(bodyFiles) - console.log(this.currentScenario.bodyUploadIds) - this.$fileUpload(this.path, null, bodyFiles, this.currentScenario, () => { this.$success(this.$t('commons.save_success')); this.path = "/api/automation/update"; @@ -685,7 +696,7 @@ this.currentScenario.modulePath = this.getPath(this.currentScenario.apiScenarioModuleId); // 构建一个场景对象 方便引用处理 let scenario = {id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario", referenced: 'Created', environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition}; - this.currentScenario.scenarioDefinition = JSON.stringify(scenario); + this.currentScenario.scenarioDefinition = scenario; this.currentScenario.tagId = JSON.stringify(this.currentScenario.tagId); if (this.currentModule != null) { this.currentScenario.modulePath = this.currentModule.method !== undefined ? this.currentModule.method : null; @@ -695,6 +706,13 @@ runRefresh() { this.debugVisible = true; this.isReloadData = false; + }, + showScenarioParameters() { + this.$refs.scenarioParameters.open(this.currentScenario.variables); + }, + addParameters(data) { + this.currentScenario.variables = data; + this.reload(); } } } diff --git a/frontend/src/business/components/api/automation/scenario/ReferenceView.vue b/frontend/src/business/components/api/automation/scenario/ReferenceView.vue new file mode 100644 index 0000000000..a57c532467 --- /dev/null +++ b/frontend/src/business/components/api/automation/scenario/ReferenceView.vue @@ -0,0 +1,62 @@ + + + + + diff --git a/frontend/src/business/components/api/automation/scenario/ScenarioExtendBtns.vue b/frontend/src/business/components/api/automation/scenario/ScenarioExtendBtns.vue new file mode 100644 index 0000000000..fa42193b8b --- /dev/null +++ b/frontend/src/business/components/api/automation/scenario/ScenarioExtendBtns.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/frontend/src/business/components/api/automation/scenario/ScenarioParameters.vue b/frontend/src/business/components/api/automation/scenario/ScenarioParameters.vue new file mode 100644 index 0000000000..b250fbd08d --- /dev/null +++ b/frontend/src/business/components/api/automation/scenario/ScenarioParameters.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/frontend/src/business/components/api/definition/components/ApiCaseList.vue b/frontend/src/business/components/api/definition/components/ApiCaseList.vue index 1ac808a75b..3833153408 100644 --- a/frontend/src/business/components/api/definition/components/ApiCaseList.vue +++ b/frontend/src/business/components/api/definition/components/ApiCaseList.vue @@ -190,6 +190,7 @@ api: { type: Object }, + createCase: String, visible: { type: Boolean, default: false, @@ -217,7 +218,6 @@ } }, - watch: { // 初始化 api() { @@ -237,13 +237,35 @@ this.currentRow.cases = []; } this.getApiTest(); + }, + createCase() { + this.sysAddition(); } }, created() { - this.getApiTest(); this.getEnvironments(); + if (this.createCase) { + this.sysAddition(); + } else { + this.getApiTest(); + } }, methods: { + sysAddition() { + let condition = {}; + condition.projectId = this.api.projectId; + condition.apiDefinitionId = this.api.id; + condition.priority = this.priorityValue; + condition.name = this.name; + this.$post("/api/testcase/list", condition, response => { + for (let index in response.data) { + let test = response.data[index]; + test.request = JSON.parse(test.request); + } + this.apiCaseList = response.data; + this.addCase(); + }); + }, getResult(data) { if (RESULT_MAP.get(data)) { return RESULT_MAP.get(data); diff --git a/frontend/src/business/components/api/definition/components/ApiConfig.vue b/frontend/src/business/components/api/definition/components/ApiConfig.vue index c49b229cbd..3ece1706c5 100644 --- a/frontend/src/business/components/api/definition/components/ApiConfig.vue +++ b/frontend/src/business/components/api/definition/components/ApiConfig.vue @@ -91,35 +91,38 @@ this.maintainerOptions = response.data; }); }, - initSql() { + setRequest() { if (this.currentApi.request != undefined && this.currentApi.request != null) { - this.request = JSON.parse(this.currentApi.request); + if (Object.prototype.toString.call(this.currentApi.request).match(/\[object (\w+)\]/)[1].toLowerCase() === 'object') { + this.request = this.currentApi.request; + } else { + this.request = JSON.parse(this.currentApi.request); + } this.currentApi.request = this.request; - } else { + return true; + } + return false; + }, + initSql() { + if (!this.setRequest()) { this.request = createComponent("JDBCSampler"); + this.currentApi.request = this.request; } }, initDubbo() { - if (this.currentApi.request != undefined && this.currentApi.request != null) { - this.request = JSON.parse(this.currentApi.request); - this.currentApi.request = this.request; - } else { + if (!this.setRequest()) { this.request = createComponent("DubboSampler"); + this.currentApi.request = this.request; } }, initTcp() { - if (this.currentApi.request != undefined && this.currentApi.request != null) { - this.request = JSON.parse(this.currentApi.request); - this.currentApi.request = this.request; - } else { + if (!this.setRequest()) { this.request = createComponent("TCPSampler"); + this.currentApi.request = this.request; } }, initHttp() { - if (this.currentApi.request != undefined && this.currentApi.request != null) { - this.request = JSON.parse(this.currentApi.request); - this.currentApi.request = this.request; - } else { + if (!this.setRequest()) { this.request = createComponent("HTTPSamplerProxy"); this.currentApi.request = this.request; } diff --git a/frontend/src/business/components/api/definition/components/debug/DebugDubboPage.vue b/frontend/src/business/components/api/definition/components/debug/DebugDubboPage.vue index 35052f1162..942bd4a88d 100644 --- a/frontend/src/business/components/api/definition/components/debug/DebugDubboPage.vue +++ b/frontend/src/business/components/api/definition/components/debug/DebugDubboPage.vue @@ -97,7 +97,7 @@ this.$refs.debugResult.reload(); }, saveAs() { - let obj = {request: JSON.stringify(this.request)}; + let obj = {request: this.request}; this.$emit('saveAs', obj); } } diff --git a/frontend/src/business/components/api/definition/components/debug/DebugHttpPage.vue b/frontend/src/business/components/api/definition/components/debug/DebugHttpPage.vue index 2ddca9dd97..a2d405339e 100644 --- a/frontend/src/business/components/api/definition/components/debug/DebugHttpPage.vue +++ b/frontend/src/business/components/api/definition/components/debug/DebugHttpPage.vue @@ -120,7 +120,7 @@ saveAs() { this.$refs['debugForm'].validate((valid) => { if (valid) { - this.debugForm.request = JSON.stringify(this.request); + this.debugForm.request = this.request; this.debugForm.userId = getCurrentUser().id; this.debugForm.status = "Underway"; this.debugForm.protocol = this.currentProtocol; diff --git a/frontend/src/business/components/api/definition/components/debug/DebugJdbcPage.vue b/frontend/src/business/components/api/definition/components/debug/DebugJdbcPage.vue index c45ec3830a..9402c1930b 100644 --- a/frontend/src/business/components/api/definition/components/debug/DebugJdbcPage.vue +++ b/frontend/src/business/components/api/definition/components/debug/DebugJdbcPage.vue @@ -99,7 +99,7 @@ this.$refs.debugResult.reload(); }, saveAs() { - let obj = {request: JSON.stringify(this.request)}; + let obj = {request: this.request}; this.$emit('saveAs', obj); } } diff --git a/frontend/src/business/components/api/definition/components/debug/DebugTcpPage.vue b/frontend/src/business/components/api/definition/components/debug/DebugTcpPage.vue index 5ae5a76242..f014471d7a 100644 --- a/frontend/src/business/components/api/definition/components/debug/DebugTcpPage.vue +++ b/frontend/src/business/components/api/definition/components/debug/DebugTcpPage.vue @@ -98,7 +98,7 @@ this.$refs.debugResult.reload(); }, saveAs() { - let obj = {request: JSON.stringify(this.request)}; + let obj = {request: this.request}; this.$emit('saveAs', obj); } } diff --git a/frontend/src/business/components/api/definition/components/runtest/RunTestDubboPage.vue b/frontend/src/business/components/api/definition/components/runtest/RunTestDubboPage.vue index 993f615cea..c603889b9d 100644 --- a/frontend/src/business/components/api/definition/components/runtest/RunTestDubboPage.vue +++ b/frontend/src/business/components/api/definition/components/runtest/RunTestDubboPage.vue @@ -31,7 +31,7 @@ > @@ -78,6 +78,7 @@ loaded: false, loading: false, currentRequest: {}, + createCase: "", refreshSign: "", responseData: {type: 'HTTP', responseResult: {}, subRequestResults: []}, reqOptions: REQ_METHOD, @@ -153,9 +154,10 @@ return bodyUploadFiles; }, saveAsCase() { - this.visible = false; + //用于触发创建操作 + this.createCase = getUUID(); + this.visible = true; this.loaded = false; - this.$refs.caseList.addCase(); }, saveAsApi() { let data = {}; diff --git a/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue b/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue index e40bef3346..5603ed8ff7 100644 --- a/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue +++ b/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue @@ -70,9 +70,9 @@ - + @@ -113,8 +113,9 @@ api: {}, loaded: false, loading: false, + createCase: "", currentRequest: {}, - refreshSign:"", + refreshSign: "", responseData: {type: 'HTTP', responseResult: {}, subRequestResults: []}, reqOptions: REQ_METHOD, environments: [], @@ -194,7 +195,9 @@ return bodyUploadFiles; }, saveAsCase() { - this.visible = false; + //用于触发创建操作 + this.createCase = getUUID(); + this.visible = true; this.loaded = false; }, saveAsApi() { @@ -301,7 +304,8 @@ border-radius: 4px; border-left: 4px solid #783887; } - /deep/.el-drawer{ + + /deep/ .el-drawer { overflow: auto; } diff --git a/frontend/src/business/components/api/definition/components/runtest/RunTestSQLPage.vue b/frontend/src/business/components/api/definition/components/runtest/RunTestSQLPage.vue index 928426f4e4..255c149965 100644 --- a/frontend/src/business/components/api/definition/components/runtest/RunTestSQLPage.vue +++ b/frontend/src/business/components/api/definition/components/runtest/RunTestSQLPage.vue @@ -30,9 +30,10 @@ - > + + > @@ -79,6 +80,7 @@ responseData: {type: 'HTTP', responseResult: {}, subRequestResults: []}, reqOptions: REQ_METHOD, refreshSign: "", + createCase: "", environments: [], rules: { method: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}], @@ -151,9 +153,9 @@ return bodyUploadFiles; }, saveAsCase() { - this.visible = false; + this.createCase = getUUID(); + this.visible = true; this.loaded = false; - this.$refs.caseList.addCase(); }, saveAsApi() { let data = {}; @@ -249,7 +251,8 @@ border-radius: 4px; border-left: 4px solid #783887; } - /deep/.el-drawer{ + + /deep/ .el-drawer { overflow: auto; } diff --git a/frontend/src/business/components/api/definition/components/runtest/RunTestTCPPage.vue b/frontend/src/business/components/api/definition/components/runtest/RunTestTCPPage.vue index aeea40e840..daa77a1ae2 100644 --- a/frontend/src/business/components/api/definition/components/runtest/RunTestTCPPage.vue +++ b/frontend/src/business/components/api/definition/components/runtest/RunTestTCPPage.vue @@ -31,7 +31,7 @@ @@ -80,6 +80,7 @@ reqOptions: REQ_METHOD, environments: [], refreshSign: "", + createCase: "", rules: { method: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}], url: [{required: true, message: this.$t('api_test.definition.request.path_info'), trigger: 'blur'}], @@ -151,9 +152,9 @@ return bodyUploadFiles; }, saveAsCase() { - this.visible = false; + this.createCase = getUUID(); + this.visible = true; this.loaded = false; - this.$refs.caseList.addCase(); }, saveAsApi() { let data = {}; diff --git a/frontend/src/business/components/api/head/ApiHeaderMenus.vue b/frontend/src/business/components/api/head/ApiHeaderMenus.vue index 5d87830b41..497ad39762 100644 --- a/frontend/src/business/components/api/head/ApiHeaderMenus.vue +++ b/frontend/src/business/components/api/head/ApiHeaderMenus.vue @@ -1,18 +1,18 @@