refactor: 消息通知

This commit is contained in:
Captain.B 2021-08-10 11:33:23 +08:00 committed by 刘瑞斌
parent 3021e87f4d
commit bfd2fe12b3
107 changed files with 5014 additions and 786 deletions

View File

@ -335,7 +335,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.20</version>
<version>1.21</version>
</dependency>
<dependency>
@ -432,7 +432,7 @@
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.3.5</version>
<version>1.5.0</version>
</dependency>
<!-- xmind export-->
<dependency>

View File

@ -10,10 +10,12 @@ import io.metersphere.api.dto.automation.ExecuteType;
import io.metersphere.api.jmeter.TestResult;
import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.api.service.MsResultService;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@ -47,6 +49,8 @@ public class APIScenarioReportController {
@PostMapping("/delete")
@MsAuditLog(module = "api_automation_report", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#request.id)", msClass = ApiScenarioReportService.class)
@SendNotice(taskType = NoticeConstants.TaskType.API_REPORT_TASK, event = NoticeConstants.Event.DELETE, target = "#targetClass.get(#request.id)", targetClass = ApiScenarioReportService.class,
mailTemplate = "api/ReportDelete", subject = "接口报告通知")
public void delete(@RequestBody DeleteAPIReportRequest request) {
apiReportService.delete(request);
}

View File

@ -16,6 +16,7 @@ import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter;
import io.metersphere.api.service.*;
import io.metersphere.base.domain.*;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.utils.CronUtils;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
@ -24,6 +25,7 @@ import io.metersphere.controller.request.BaseQueryRequest;
import io.metersphere.controller.request.QueryScheduleRequest;
import io.metersphere.controller.request.ScheduleRequest;
import io.metersphere.dto.ScheduleDao;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.service.CheckPermissionService;
import io.metersphere.service.ScheduleService;
import org.apache.jorphan.collections.HashTree;
@ -359,10 +361,12 @@ public class APITestController {
}
@PostMapping(value = "/schedule/updateEnableByPrimyKey")
public void updateScheduleEnableByPrimyKey(@RequestBody ScheduleInfoRequest request) {
@SendNotice(taskType = NoticeConstants.TaskType.API_HOME_TASK, event = NoticeConstants.Event.CLOSE_SCHEDULE, mailTemplate = "api/ScheduleClose", subject = "接口测试通知")
public Schedule updateScheduleEnableByPrimyKey(@RequestBody ScheduleInfoRequest request) {
Schedule schedule = scheduleService.getSchedule(request.getTaskID());
schedule.setEnable(request.isEnable());
apiAutomationService.updateSchedule(schedule);
return schedule;
}
@PostMapping(value = "/historicalDataUpgrade")

View File

@ -11,14 +11,12 @@ import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.base.domain.ApiScenario;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.commons.constants.TriggerMode;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.controller.request.ScheduleRequest;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
import io.metersphere.track.request.testplan.FileOperationRequest;
import org.apache.commons.lang3.StringUtils;
@ -89,6 +87,7 @@ public class ApiAutomationController {
@PostMapping(value = "/create")
@MsAuditLog(module = "api_automation", type = OperLogConstants.CREATE, title = "#request.name", content = "#msClass.getLogDetails(#request.id)", msClass = ApiAutomationService.class)
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_READ_CREATE)
@SendNotice(taskType = NoticeConstants.TaskType.API_AUTOMATION_TASK, event = NoticeConstants.Event.CREATE, mailTemplate = "api/AutomationCreate", subject = "接口自动化通知")
public ApiScenario create(@RequestPart("request") SaveApiScenarioRequest request, @RequestPart(value = "bodyFiles", required = false) List<MultipartFile> bodyFiles,
@RequestPart(value = "scenarioFiles", required = false) List<MultipartFile> scenarioFiles) {
return apiAutomationService.create(request, bodyFiles, scenarioFiles);
@ -97,9 +96,10 @@ public class ApiAutomationController {
@PostMapping(value = "/update")
@MsAuditLog(module = "api_automation", type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#request.id)", title = "#request.name", content = "#msClass.getLogDetails(#request.id)", msClass = ApiAutomationService.class)
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_READ_EDIT)
public void update(@RequestPart("request") SaveApiScenarioRequest request, @RequestPart(value = "bodyFiles", required = false) List<MultipartFile> bodyFiles,
@RequestPart(value = "scenarioFiles", required = false) List<MultipartFile> scenarioFiles) {
apiAutomationService.update(request, bodyFiles, scenarioFiles);
@SendNotice(taskType = NoticeConstants.TaskType.API_AUTOMATION_TASK, event = NoticeConstants.Event.UPDATE, mailTemplate = "api/AutomationUpdate", subject = "接口自动化通知")
public ApiScenario update(@RequestPart("request") SaveApiScenarioRequest request, @RequestPart(value = "bodyFiles", required = false) List<MultipartFile> bodyFiles,
@RequestPart(value = "scenarioFiles", required = false) List<MultipartFile> scenarioFiles) {
return apiAutomationService.update(request, bodyFiles, scenarioFiles);
}
@GetMapping("/delete/{id}")
@ -123,12 +123,16 @@ public class ApiAutomationController {
@PostMapping("/removeToGc")
@MsAuditLog(module = "api_automation", type = OperLogConstants.GC, beforeEvent = "#msClass.getLogDetails(#ids)", msClass = ApiAutomationService.class)
@SendNotice(taskType = NoticeConstants.TaskType.API_AUTOMATION_TASK, target = "#targetClass.getApiScenarios(#ids)", targetClass = ApiAutomationService.class,
event = NoticeConstants.Event.DELETE, mailTemplate = "api/AutomationDelete", subject = "接口自动化通知")
public void removeToGc(@RequestBody List<String> ids) {
apiAutomationService.removeToGc(ids);
}
@PostMapping("/removeToGcByBatch")
@MsAuditLog(module = "api_automation", type = OperLogConstants.BATCH_GC, beforeEvent = "#msClass.getLogDetails(#request.ids)", msClass = ApiAutomationService.class)
@SendNotice(taskType = NoticeConstants.TaskType.API_AUTOMATION_TASK, target = "#targetClass.getApiScenarios(#request.ids)", targetClass = ApiAutomationService.class,
event = NoticeConstants.Event.DELETE, mailTemplate = "api/AutomationDelete", subject = "接口自动化通知")
public void removeToGcByBatch(@RequestBody ApiScenarioBatchRequest request) {
apiAutomationService.removeToGcByBatch(request);
}

View File

@ -18,6 +18,7 @@ import io.metersphere.base.domain.ApiDefinition;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.commons.json.JSONSchemaGenerator;
@ -25,6 +26,7 @@ import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.controller.request.ScheduleRequest;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.service.CheckPermissionService;
import io.metersphere.service.ScheduleService;
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
@ -89,6 +91,7 @@ public class ApiDefinitionController {
@PostMapping(value = "/create", consumes = {"multipart/form-data"})
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ_CREATE_API)
@MsAuditLog(module = "api_definition", type = OperLogConstants.CREATE, title = "#request.name", content = "#msClass.getLogDetails(#request.id)", msClass = ApiDefinitionService.class)
@SendNotice(taskType = NoticeConstants.TaskType.API_DEFINITION_TASK, event = NoticeConstants.Event.CREATE, mailTemplate = "api/DefinitionCreate", subject = "接口定义通知")
public ApiDefinitionWithBLOBs create(@RequestPart("request") SaveApiDefinitionRequest request, @RequestPart(value = "files", required = false) List<MultipartFile> bodyFiles) {
checkPermissionService.checkProjectOwner(request.getProjectId());
return apiDefinitionService.create(request, bodyFiles);
@ -97,6 +100,7 @@ public class ApiDefinitionController {
@PostMapping(value = "/update", consumes = {"multipart/form-data"})
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ_EDIT_API)
@MsAuditLog(module = "api_definition", type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#request.id)", title = "#request.name", content = "#msClass.getLogDetails(#request.id)", msClass = ApiDefinitionService.class)
@SendNotice(taskType = NoticeConstants.TaskType.API_DEFINITION_TASK, event = NoticeConstants.Event.UPDATE, mailTemplate = "api/DefinitionUpdate", subject = "接口定义通知")
public ApiDefinitionWithBLOBs update(@RequestPart("request") SaveApiDefinitionRequest request, @RequestPart(value = "files", required = false) List<MultipartFile> bodyFiles) {
checkPermissionService.checkProjectOwner(request.getProjectId());
return apiDefinitionService.update(request, bodyFiles);
@ -134,6 +138,8 @@ public class ApiDefinitionController {
@PostMapping("/removeToGc")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ_DELETE_API)
@MsAuditLog(module = "api_definition", type = OperLogConstants.GC, beforeEvent = "#msClass.getLogDetails(#ids)", msClass = ApiDefinitionService.class)
@SendNotice(taskType = NoticeConstants.TaskType.API_DEFINITION_TASK, target = "#targetClass.getBLOBs(#ids)", targetClass = ApiDefinitionService.class,
event = NoticeConstants.Event.DELETE, mailTemplate = "api/DefinitionDelete", subject = "接口定义通知")
public void removeToGc(@RequestBody List<String> ids) {
apiDefinitionService.removeToGc(ids);
}

View File

@ -8,10 +8,12 @@ import io.metersphere.api.dto.definition.*;
import io.metersphere.api.service.ApiTestCaseService;
import io.metersphere.base.domain.ApiTestCase;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
import io.metersphere.track.service.TestPlanApiCaseService;
import org.springframework.web.bind.annotation.*;
@ -81,12 +83,14 @@ public class ApiTestCaseController {
@PostMapping(value = "/create", consumes = {"multipart/form-data"})
@MsAuditLog(module = "api_definition", type = OperLogConstants.CREATE, title = "#request.name", content = "#msClass.getLogDetails(#request)", msClass = ApiTestCaseService.class)
@SendNotice(taskType = NoticeConstants.TaskType.API_DEFINITION_TASK, event = NoticeConstants.Event.CASE_CREATE, mailTemplate = "api/CaseCreate", subject = "接口用例通知")
public ApiTestCase create(@RequestPart("request") SaveApiTestCaseRequest request, @RequestPart(value = "files", required = false) List<MultipartFile> bodyFiles) {
return apiTestCaseService.create(request, bodyFiles);
}
@PostMapping(value = "/update", consumes = {"multipart/form-data"})
@MsAuditLog(module = "api_definition", type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#request)", title = "#request.name", content = "#msClass.getLogDetails(#request)", msClass = ApiTestCaseService.class)
@SendNotice(taskType = NoticeConstants.TaskType.API_DEFINITION_TASK, event = NoticeConstants.Event.CASE_UPDATE, mailTemplate = "api/CaseUpdate", subject = "接口用例通知")
public ApiTestCase update(@RequestPart("request") SaveApiTestCaseRequest request, @RequestPart(value = "files", required = false) List<MultipartFile> bodyFiles) {
return apiTestCaseService.update(request, bodyFiles);
}
@ -99,9 +103,11 @@ public class ApiTestCaseController {
@GetMapping("/deleteToGc/{id}")
@MsAuditLog(module = "api_definition", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#id)", msClass = ApiTestCaseService.class)
@SendNotice(taskType = NoticeConstants.TaskType.API_DEFINITION_TASK, event = NoticeConstants.Event.CASE_DELETE, mailTemplate = "api/CaseDelete", subject = "接口用例通知")
public void deleteToGc(@PathVariable String id) {
apiTestCaseService.deleteToGc(id);
}
@PostMapping("/removeToGc")
@MsAuditLog(module = "api_definition", type = OperLogConstants.GC, beforeEvent = "#msClass.getLogDetails(#ids)", msClass = ApiTestCaseService.class)
public void removeToGc(@RequestBody List<String> ids) {
@ -123,6 +129,7 @@ public class ApiTestCaseController {
public void editApiBathByParam(@RequestBody ApiTestBatchRequest request) {
apiTestCaseService.editApiBathByParam(request);
}
@PostMapping("/reduction")
@MsAuditLog(module = "api_definition", type = OperLogConstants.RESTORE, beforeEvent = "#msClass.getLogDetails(#request.ids)", content = "#msClass.getLogDetails(#request.ids)", msClass = ApiTestCaseService.class)
public List<String> reduction(@RequestBody ApiTestBatchRequest request) {
@ -147,6 +154,7 @@ public class ApiTestCaseController {
public void deleteToGcByParam(@RequestBody ApiTestBatchRequest request) {
apiTestCaseService.deleteToGcByParam(request);
}
@PostMapping("/checkDeleteDatas")
public DeleteCheckResult checkDeleteDatas(@RequestBody ApiTestBatchRequest request) {
return apiTestCaseService.checkDeleteDatas(request);

View File

@ -42,6 +42,8 @@ public class SaveApiDefinitionRequest {
private String userId;
private String followPeople;
private Schedule schedule;
private String triggerMode;

View File

@ -342,7 +342,7 @@ public class ApiAutomationService {
}
}
public void update(SaveApiScenarioRequest request, List<MultipartFile> bodyFiles, List<MultipartFile> scenarioFiles) {
public ApiScenario update(SaveApiScenarioRequest request, List<MultipartFile> bodyFiles, List<MultipartFile> scenarioFiles) {
checkNameExist(request);
checkScenarioNum(request);
@ -367,6 +367,7 @@ public class ApiAutomationService {
apiScenarioReferenceIdService.saveByApiScenario(scenario);
extScheduleMapper.updateNameByResourceID(request.getId(), request.getName());// 修改场景name同步到修改首页定时任务
uploadFiles(request, bodyFiles, scenarioFiles);
return scenario;
}
/**

View File

@ -368,6 +368,7 @@ public class ApiDefinitionService {
test.setResponse(JSONObject.toJSONString(request.getResponse()));
test.setEnvironmentId(request.getEnvironmentId());
test.setUserId(request.getUserId());
test.setFollowPeople(request.getFollowPeople());
if (StringUtils.isNotEmpty(request.getTags()) && !StringUtils.equals(request.getTags(), "[]")) {
test.setTags(request.getTags());
} else {
@ -404,6 +405,7 @@ public class ApiDefinitionService {
test.setStatus(APITestStatus.Underway.name());
test.setModulePath(request.getModulePath());
test.setModuleId(request.getModuleId());
test.setFollowPeople(request.getFollowPeople());
if (StringUtils.isEmpty(request.getModuleId()) || "default-module".equals(request.getModuleId())) {
ApiModuleExample example = new ApiModuleExample();
example.createCriteria().andProjectIdEqualTo(test.getProjectId()).andProtocolEqualTo(test.getProtocol()).andNameEqualTo("默认模块");

View File

@ -303,6 +303,7 @@ public class ApiTestCaseService {
test.setUpdateTime(System.currentTimeMillis());
test.setDescription(request.getDescription());
test.setVersion(request.getVersion() == null ? 0 : request.getVersion() + 1);
test.setFollowPeople(request.getFollowPeople());
if (StringUtils.equals("[]", request.getTags())) {
test.setTags("");
} else {
@ -332,6 +333,7 @@ public class ApiTestCaseService {
test.setUpdateTime(System.currentTimeMillis());
test.setDescription(request.getDescription());
test.setNum(getNextNum(request.getApiDefinitionId()));
test.setFollowPeople(request.getFollowPeople());
if (StringUtils.equals("[]", request.getTags())) {
test.setTags("");
} else {

View File

@ -51,5 +51,7 @@ public class ApiDefinition implements Serializable {
private String deleteUserId;
private String followPeople;
private static final long serialVersionUID = 1L;
}

View File

@ -1673,6 +1673,76 @@ public class ApiDefinitionExample {
addCriterion("delete_user_id not between", value1, value2, "deleteUserId");
return (Criteria) this;
}
public Criteria andFollowPeopleIsNull() {
addCriterion("follow_people is null");
return (Criteria) this;
}
public Criteria andFollowPeopleIsNotNull() {
addCriterion("follow_people is not null");
return (Criteria) this;
}
public Criteria andFollowPeopleEqualTo(String value) {
addCriterion("follow_people =", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleNotEqualTo(String value) {
addCriterion("follow_people <>", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleGreaterThan(String value) {
addCriterion("follow_people >", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleGreaterThanOrEqualTo(String value) {
addCriterion("follow_people >=", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleLessThan(String value) {
addCriterion("follow_people <", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleLessThanOrEqualTo(String value) {
addCriterion("follow_people <=", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleLike(String value) {
addCriterion("follow_people like", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleNotLike(String value) {
addCriterion("follow_people not like", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleIn(List<String> values) {
addCriterion("follow_people in", values, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleNotIn(List<String> values) {
addCriterion("follow_people not in", values, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleBetween(String value1, String value2) {
addCriterion("follow_people between", value1, value2, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleNotBetween(String value1, String value2) {
addCriterion("follow_people not between", value1, value2, "followPeople");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -39,5 +39,7 @@ public class ApiTestCase implements Serializable {
private Integer version;
private String followPeople;
private static final long serialVersionUID = 1L;
}
}

View File

@ -1243,6 +1243,76 @@ public class ApiTestCaseExample {
addCriterion("version not between", value1, value2, "version");
return (Criteria) this;
}
public Criteria andFollowPeopleIsNull() {
addCriterion("follow_people is null");
return (Criteria) this;
}
public Criteria andFollowPeopleIsNotNull() {
addCriterion("follow_people is not null");
return (Criteria) this;
}
public Criteria andFollowPeopleEqualTo(String value) {
addCriterion("follow_people =", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleNotEqualTo(String value) {
addCriterion("follow_people <>", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleGreaterThan(String value) {
addCriterion("follow_people >", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleGreaterThanOrEqualTo(String value) {
addCriterion("follow_people >=", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleLessThan(String value) {
addCriterion("follow_people <", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleLessThanOrEqualTo(String value) {
addCriterion("follow_people <=", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleLike(String value) {
addCriterion("follow_people like", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleNotLike(String value) {
addCriterion("follow_people not like", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleIn(List<String> values) {
addCriterion("follow_people in", values, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleNotIn(List<String> values) {
addCriterion("follow_people not in", values, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleBetween(String value1, String value2) {
addCriterion("follow_people between", value1, value2, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleNotBetween(String value1, String value2) {
addCriterion("follow_people not between", value1, value2, "followPeople");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
@ -1337,4 +1407,4 @@ public class ApiTestCaseExample {
this(condition, value, secondValue, null);
}
}
}
}

View File

@ -31,5 +31,7 @@ public class LoadTest implements Serializable {
private String scenarioId;
private String followPeople;
private static final long serialVersionUID = 1L;
}

View File

@ -973,6 +973,76 @@ public class LoadTestExample {
addCriterion("scenario_id not between", value1, value2, "scenarioId");
return (Criteria) this;
}
public Criteria andFollowPeopleIsNull() {
addCriterion("follow_people is null");
return (Criteria) this;
}
public Criteria andFollowPeopleIsNotNull() {
addCriterion("follow_people is not null");
return (Criteria) this;
}
public Criteria andFollowPeopleEqualTo(String value) {
addCriterion("follow_people =", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleNotEqualTo(String value) {
addCriterion("follow_people <>", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleGreaterThan(String value) {
addCriterion("follow_people >", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleGreaterThanOrEqualTo(String value) {
addCriterion("follow_people >=", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleLessThan(String value) {
addCriterion("follow_people <", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleLessThanOrEqualTo(String value) {
addCriterion("follow_people <=", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleLike(String value) {
addCriterion("follow_people like", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleNotLike(String value) {
addCriterion("follow_people not like", value, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleIn(List<String> values) {
addCriterion("follow_people in", values, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleNotIn(List<String> values) {
addCriterion("follow_people not in", values, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleBetween(String value1, String value2) {
addCriterion("follow_people between", value1, value2, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleNotBetween(String value1, String value2) {
addCriterion("follow_people not between", value1, value2, "followPeople");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -25,6 +25,7 @@
<result column="case_passing_rate" jdbcType="VARCHAR" property="casePassingRate" />
<result column="delete_time" jdbcType="BIGINT" property="deleteTime" />
<result column="delete_user_id" jdbcType="VARCHAR" property="deleteUserId" />
<result column="follow_people" jdbcType="VARCHAR" property="followPeople" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiDefinitionWithBLOBs">
<result column="description" jdbcType="LONGVARCHAR" property="description" />
@ -92,7 +93,8 @@
<sql id="Base_Column_List">
id, project_id, `name`, `method`, module_path, environment_id, schedule, `status`,
module_id, user_id, create_time, update_time, protocol, `path`, num, tags, original_state,
create_user, case_total, case_status, case_passing_rate, delete_time, delete_user_id
create_user, case_total, case_status, case_passing_rate, delete_time, delete_user_id,
follow_people
</sql>
<sql id="Blob_Column_List">
description, request, response
@ -153,8 +155,9 @@
protocol, `path`, num,
tags, original_state, create_user,
case_total, case_status, case_passing_rate,
delete_time, delete_user_id, description,
request, response)
delete_time, delete_user_id, follow_people,
description, request, response
)
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{method,jdbcType=VARCHAR}, #{modulePath,jdbcType=VARCHAR}, #{environmentId,jdbcType=VARCHAR},
#{schedule,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, #{moduleId,jdbcType=VARCHAR},
@ -162,8 +165,9 @@
#{protocol,jdbcType=VARCHAR}, #{path,jdbcType=VARCHAR}, #{num,jdbcType=INTEGER},
#{tags,jdbcType=VARCHAR}, #{originalState,jdbcType=VARCHAR}, #{createUser,jdbcType=VARCHAR},
#{caseTotal,jdbcType=VARCHAR}, #{caseStatus,jdbcType=VARCHAR}, #{casePassingRate,jdbcType=VARCHAR},
#{deleteTime,jdbcType=BIGINT}, #{deleteUserId,jdbcType=VARCHAR}, #{description,jdbcType=LONGVARCHAR},
#{request,jdbcType=LONGVARCHAR}, #{response,jdbcType=LONGVARCHAR})
#{deleteTime,jdbcType=BIGINT}, #{deleteUserId,jdbcType=VARCHAR}, #{followPeople,jdbcType=VARCHAR},
#{description,jdbcType=LONGVARCHAR}, #{request,jdbcType=LONGVARCHAR}, #{response,jdbcType=LONGVARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiDefinitionWithBLOBs">
insert into api_definition
@ -237,6 +241,9 @@
<if test="deleteUserId != null">
delete_user_id,
</if>
<if test="followPeople != null">
follow_people,
</if>
<if test="description != null">
description,
</if>
@ -317,6 +324,9 @@
<if test="deleteUserId != null">
#{deleteUserId,jdbcType=VARCHAR},
</if>
<if test="followPeople != null">
#{followPeople,jdbcType=VARCHAR},
</if>
<if test="description != null">
#{description,jdbcType=LONGVARCHAR},
</if>
@ -406,6 +416,9 @@
<if test="record.deleteUserId != null">
delete_user_id = #{record.deleteUserId,jdbcType=VARCHAR},
</if>
<if test="record.followPeople != null">
follow_people = #{record.followPeople,jdbcType=VARCHAR},
</if>
<if test="record.description != null">
description = #{record.description,jdbcType=LONGVARCHAR},
</if>
@ -445,6 +458,7 @@
case_passing_rate = #{record.casePassingRate,jdbcType=VARCHAR},
delete_time = #{record.deleteTime,jdbcType=BIGINT},
delete_user_id = #{record.deleteUserId,jdbcType=VARCHAR},
follow_people = #{record.followPeople,jdbcType=VARCHAR},
description = #{record.description,jdbcType=LONGVARCHAR},
request = #{record.request,jdbcType=LONGVARCHAR},
response = #{record.response,jdbcType=LONGVARCHAR}
@ -476,7 +490,8 @@
case_status = #{record.caseStatus,jdbcType=VARCHAR},
case_passing_rate = #{record.casePassingRate,jdbcType=VARCHAR},
delete_time = #{record.deleteTime,jdbcType=BIGINT},
delete_user_id = #{record.deleteUserId,jdbcType=VARCHAR}
delete_user_id = #{record.deleteUserId,jdbcType=VARCHAR},
follow_people = #{record.followPeople,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -550,6 +565,9 @@
<if test="deleteUserId != null">
delete_user_id = #{deleteUserId,jdbcType=VARCHAR},
</if>
<if test="followPeople != null">
follow_people = #{followPeople,jdbcType=VARCHAR},
</if>
<if test="description != null">
description = #{description,jdbcType=LONGVARCHAR},
</if>
@ -586,6 +604,7 @@
case_passing_rate = #{casePassingRate,jdbcType=VARCHAR},
delete_time = #{deleteTime,jdbcType=BIGINT},
delete_user_id = #{deleteUserId,jdbcType=VARCHAR},
follow_people = #{followPeople,jdbcType=VARCHAR},
description = #{description,jdbcType=LONGVARCHAR},
request = #{request,jdbcType=LONGVARCHAR},
response = #{response,jdbcType=LONGVARCHAR}
@ -614,7 +633,8 @@
case_status = #{caseStatus,jdbcType=VARCHAR},
case_passing_rate = #{casePassingRate,jdbcType=VARCHAR},
delete_time = #{deleteTime,jdbcType=BIGINT},
delete_user_id = #{deleteUserId,jdbcType=VARCHAR}
delete_user_id = #{deleteUserId,jdbcType=VARCHAR},
follow_people = #{followPeople,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -19,6 +19,7 @@
<result column="delete_time" jdbcType="BIGINT" property="deleteTime" />
<result column="delete_user_id" jdbcType="VARCHAR" property="deleteUserId" />
<result column="version" jdbcType="INTEGER" property="version" />
<result column="follow_people" jdbcType="VARCHAR" property="followPeople" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiTestCaseWithBLOBs">
<result column="description" jdbcType="LONGVARCHAR" property="description" />
@ -83,9 +84,9 @@
</where>
</sql>
<sql id="Base_Column_List">
id, project_id, `name`, priority, api_definition_id, create_user_id, update_user_id,
create_time, update_time, num, tags, last_result_id, `status`, original_status, delete_time,
delete_user_id, version
id, project_id, `name`, priority, api_definition_id, create_user_id, update_user_id,
create_time, update_time, num, tags, last_result_id, `status`, original_status, delete_time,
delete_user_id, version, follow_people
</sql>
<sql id="Blob_Column_List">
description, request
@ -121,7 +122,7 @@
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
select
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
@ -139,20 +140,20 @@
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.ApiTestCaseWithBLOBs">
insert into api_test_case (id, project_id, `name`,
priority, api_definition_id, create_user_id,
update_user_id, create_time, update_time,
num, tags, last_result_id,
`status`, original_status, delete_time,
delete_user_id, version, description,
request)
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{priority,jdbcType=VARCHAR}, #{apiDefinitionId,jdbcType=VARCHAR}, #{createUserId,jdbcType=VARCHAR},
#{updateUserId,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{num,jdbcType=INTEGER}, #{tags,jdbcType=VARCHAR}, #{lastResultId,jdbcType=VARCHAR},
#{status,jdbcType=VARCHAR}, #{originalStatus,jdbcType=VARCHAR}, #{deleteTime,jdbcType=BIGINT},
#{deleteUserId,jdbcType=VARCHAR}, #{version,jdbcType=INTEGER}, #{description,jdbcType=LONGVARCHAR},
#{request,jdbcType=LONGVARCHAR})
insert into api_test_case (id, project_id, `name`,
priority, api_definition_id, create_user_id,
update_user_id, create_time, update_time,
num, tags, last_result_id,
`status`, original_status, delete_time,
delete_user_id, version, follow_people,
description, request)
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{priority,jdbcType=VARCHAR}, #{apiDefinitionId,jdbcType=VARCHAR}, #{createUserId,jdbcType=VARCHAR},
#{updateUserId,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{num,jdbcType=INTEGER}, #{tags,jdbcType=VARCHAR}, #{lastResultId,jdbcType=VARCHAR},
#{status,jdbcType=VARCHAR}, #{originalStatus,jdbcType=VARCHAR}, #{deleteTime,jdbcType=BIGINT},
#{deleteUserId,jdbcType=VARCHAR}, #{version,jdbcType=INTEGER}, #{followPeople,jdbcType=VARCHAR},
#{description,jdbcType=LONGVARCHAR}, #{request,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiTestCaseWithBLOBs">
insert into api_test_case
@ -208,6 +209,9 @@
<if test="version != null">
version,
</if>
<if test="followPeople != null">
follow_people,
</if>
<if test="description != null">
description,
</if>
@ -267,6 +271,9 @@
<if test="version != null">
#{version,jdbcType=INTEGER},
</if>
<if test="followPeople != null">
#{followPeople,jdbcType=VARCHAR},
</if>
<if test="description != null">
#{description,jdbcType=LONGVARCHAR},
</if>
@ -335,6 +342,9 @@
<if test="record.version != null">
version = #{record.version,jdbcType=INTEGER},
</if>
<if test="record.followPeople != null">
follow_people = #{record.followPeople,jdbcType=VARCHAR},
</if>
<if test="record.description != null">
description = #{record.description,jdbcType=LONGVARCHAR},
</if>
@ -365,6 +375,7 @@
delete_time = #{record.deleteTime,jdbcType=BIGINT},
delete_user_id = #{record.deleteUserId,jdbcType=VARCHAR},
version = #{record.version,jdbcType=INTEGER},
follow_people = #{record.followPeople,jdbcType=VARCHAR},
description = #{record.description,jdbcType=LONGVARCHAR},
request = #{record.request,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
@ -389,7 +400,8 @@
original_status = #{record.originalStatus,jdbcType=VARCHAR},
delete_time = #{record.deleteTime,jdbcType=BIGINT},
delete_user_id = #{record.deleteUserId,jdbcType=VARCHAR},
version = #{record.version,jdbcType=INTEGER}
version = #{record.version,jdbcType=INTEGER},
follow_people = #{record.followPeople,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -445,6 +457,9 @@
<if test="version != null">
version = #{version,jdbcType=INTEGER},
</if>
<if test="followPeople != null">
follow_people = #{followPeople,jdbcType=VARCHAR},
</if>
<if test="description != null">
description = #{description,jdbcType=LONGVARCHAR},
</if>
@ -472,6 +487,7 @@
delete_time = #{deleteTime,jdbcType=BIGINT},
delete_user_id = #{deleteUserId,jdbcType=VARCHAR},
version = #{version,jdbcType=INTEGER},
follow_people = #{followPeople,jdbcType=VARCHAR},
description = #{description,jdbcType=LONGVARCHAR},
request = #{request,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
@ -493,7 +509,8 @@
original_status = #{originalStatus,jdbcType=VARCHAR},
delete_time = #{deleteTime,jdbcType=BIGINT},
delete_user_id = #{deleteUserId,jdbcType=VARCHAR},
version = #{version,jdbcType=INTEGER}
version = #{version,jdbcType=INTEGER},
follow_people = #{followPeople,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>
</mapper>

View File

@ -15,6 +15,7 @@
<result column="create_user" jdbcType="VARCHAR" property="createUser" />
<result column="scenario_version" jdbcType="INTEGER" property="scenarioVersion" />
<result column="scenario_id" jdbcType="VARCHAR" property="scenarioId" />
<result column="follow_people" jdbcType="VARCHAR" property="followPeople" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.LoadTestWithBLOBs">
<result column="load_configuration" jdbcType="LONGVARCHAR" property="loadConfiguration" />
@ -80,7 +81,7 @@
</sql>
<sql id="Base_Column_List">
id, project_id, `name`, description, create_time, update_time, `status`, test_resource_pool_id,
user_id, num, create_user, scenario_version, scenario_id
user_id, num, create_user, scenario_version, scenario_id, follow_people
</sql>
<sql id="Blob_Column_List">
load_configuration, advanced_configuration
@ -138,14 +139,14 @@
description, create_time, update_time,
`status`, test_resource_pool_id, user_id,
num, create_user, scenario_version,
scenario_id, load_configuration, advanced_configuration
)
scenario_id, follow_people, load_configuration,
advanced_configuration)
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{status,jdbcType=VARCHAR}, #{testResourcePoolId,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR},
#{num,jdbcType=INTEGER}, #{createUser,jdbcType=VARCHAR}, #{scenarioVersion,jdbcType=INTEGER},
#{scenarioId,jdbcType=VARCHAR}, #{loadConfiguration,jdbcType=LONGVARCHAR}, #{advancedConfiguration,jdbcType=LONGVARCHAR}
)
#{scenarioId,jdbcType=VARCHAR}, #{followPeople,jdbcType=VARCHAR}, #{loadConfiguration,jdbcType=LONGVARCHAR},
#{advancedConfiguration,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.LoadTestWithBLOBs">
insert into load_test
@ -189,6 +190,9 @@
<if test="scenarioId != null">
scenario_id,
</if>
<if test="followPeople != null">
follow_people,
</if>
<if test="loadConfiguration != null">
load_configuration,
</if>
@ -236,6 +240,9 @@
<if test="scenarioId != null">
#{scenarioId,jdbcType=VARCHAR},
</if>
<if test="followPeople != null">
#{followPeople,jdbcType=VARCHAR},
</if>
<if test="loadConfiguration != null">
#{loadConfiguration,jdbcType=LONGVARCHAR},
</if>
@ -292,6 +299,9 @@
<if test="record.scenarioId != null">
scenario_id = #{record.scenarioId,jdbcType=VARCHAR},
</if>
<if test="record.followPeople != null">
follow_people = #{record.followPeople,jdbcType=VARCHAR},
</if>
<if test="record.loadConfiguration != null">
load_configuration = #{record.loadConfiguration,jdbcType=LONGVARCHAR},
</if>
@ -318,6 +328,7 @@
create_user = #{record.createUser,jdbcType=VARCHAR},
scenario_version = #{record.scenarioVersion,jdbcType=INTEGER},
scenario_id = #{record.scenarioId,jdbcType=VARCHAR},
follow_people = #{record.followPeople,jdbcType=VARCHAR},
load_configuration = #{record.loadConfiguration,jdbcType=LONGVARCHAR},
advanced_configuration = #{record.advancedConfiguration,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
@ -338,7 +349,8 @@
num = #{record.num,jdbcType=INTEGER},
create_user = #{record.createUser,jdbcType=VARCHAR},
scenario_version = #{record.scenarioVersion,jdbcType=INTEGER},
scenario_id = #{record.scenarioId,jdbcType=VARCHAR}
scenario_id = #{record.scenarioId,jdbcType=VARCHAR},
follow_people = #{record.followPeople,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -382,6 +394,9 @@
<if test="scenarioId != null">
scenario_id = #{scenarioId,jdbcType=VARCHAR},
</if>
<if test="followPeople != null">
follow_people = #{followPeople,jdbcType=VARCHAR},
</if>
<if test="loadConfiguration != null">
load_configuration = #{loadConfiguration,jdbcType=LONGVARCHAR},
</if>
@ -405,6 +420,7 @@
create_user = #{createUser,jdbcType=VARCHAR},
scenario_version = #{scenarioVersion,jdbcType=INTEGER},
scenario_id = #{scenarioId,jdbcType=VARCHAR},
follow_people = #{followPeople,jdbcType=VARCHAR},
load_configuration = #{loadConfiguration,jdbcType=LONGVARCHAR},
advanced_configuration = #{advancedConfiguration,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
@ -422,7 +438,8 @@
num = #{num,jdbcType=INTEGER},
create_user = #{createUser,jdbcType=VARCHAR},
scenario_version = #{scenarioVersion,jdbcType=INTEGER},
scenario_id = #{scenarioId,jdbcType=VARCHAR}
scenario_id = #{scenarioId,jdbcType=VARCHAR},
follow_people = #{followPeople,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -212,7 +212,7 @@
</sql>
<select id="list" resultType="io.metersphere.api.dto.definition.ApiDefinitionResult">
select api_definition.id, api_definition.project_id, api_definition.num, api_definition.tags,api_definition.original_state,
select api_definition.id, api_definition.project_id, api_definition.num, api_definition.tags,api_definition.follow_people,api_definition.original_state,
api_definition.name,api_definition.protocol,api_definition.path,api_definition.module_id,api_definition.module_path,api_definition.method,
api_definition.description,api_definition.request,api_definition.response,api_definition.environment_id,
api_definition.status, api_definition.user_id, api_definition.create_time, api_definition.update_time, project.name as
@ -236,7 +236,7 @@
</select>
<select id="listByIds" resultType="io.metersphere.api.dto.definition.ApiDefinitionResult">
select api_definition.id, api_definition.project_id, api_definition.num, api_definition.tags,
select api_definition.id, api_definition.project_id, api_definition.num, api_definition.tags,api_definition.follow_people,
api_definition.name,api_definition.protocol,api_definition.path,api_definition.module_id,api_definition.module_path,api_definition.method,
api_definition.description,api_definition.request,api_definition.response,api_definition.environment_id,
api_definition.status, api_definition.user_id, api_definition.create_time, api_definition.update_time,

View File

@ -8,6 +8,15 @@ public interface NoticeConstants {
String REVIEW_TASK = "REVIEW_TASK";
String DEFECT_TASK = "DEFECT_TASK";
String SWAGGER_TASK = "SWAGGER_TASK";
String API_AUTOMATION_TASK = "API_AUTOMATION_TASK";
String API_DEFINITION_TASK = "API_DEFINITION_TASK";
String API_HOME_TASK = "API_HOME_TASK";
String API_REPORT_TASK = "API_REPORT_TASK";
String PERFORMANCE_REPORT_TASK = "PERFORMANCE_REPORT_TASK";
String PERFORMANCE_TEST_TASK = "PERFORMANCE_TEST_TASK";
String TRACK_TEST_CASE_TASK = "TRACK_TEST_CASE_TASK";
String TRACK_HOME_TASK = "TRACK_HOME_TASK";
String TRACK_REPORT_TASK = "TRACK_REPORT_TASK";
}
interface Mode {
@ -28,13 +37,21 @@ public interface NoticeConstants {
String CREATE = "CREATE";
String UPDATE = "UPDATE";
String DELETE = "DELETE";
String CASE_CREATE = "CASE_CREATE";
String CASE_UPDATE = "CASE_UPDATE";
String CASE_DELETE = "CASE_DELETE";
String COMMENT = "COMMENT";
String IMPORT = "IMPORT";
String CLOSE_SCHEDULE = "CLOSE_SCHEDULE";
}
interface RelatedUser {
String FOUNDER = "FOUNDER";//创建人
String CREATOR = "CREATOR";//创建人
String EXECUTOR = "EXECUTOR";//负责人(评审人
String MAINTAINER = "MAINTAINER";//维护人
String FOLLOW_PEOPLE = "FOLLOW_PEOPLE";//关注人
}
}

View File

@ -0,0 +1,55 @@
package io.metersphere.notice.annotation;
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SendNotice {
String taskType();
/**
* Event
*/
String event() default "";
/**
* 消息主题
*/
String subject() default "";
/**
* 获取实际值
*/
String target() default "";
/**
* 资源目标
*/
Class<?> targetClass() default Object.class;
/**
* 保存资源的 json
*/
String source() default "";
/**
* 消息内容
*/
String context() default "";
String successContext() default "";
String failedContext() default "";
/**
* html 消息模版
*/
String mailTemplate() default "";
String failedMailTemplate() default "";
String successMailTemplate() default "";
}

View File

@ -29,7 +29,7 @@ public abstract class AbstractNoticeSender implements NoticeSender {
return getContent(messageDetail.getTemplate(), noticeModel.getParamMap());
}
// 处理 userIds 中包含的特殊值
List<String> realUserIds = getRealUserIds(messageDetail.getUserIds(), noticeModel.getRelatedUsers(), messageDetail.getEvent());
List<String> realUserIds = getRealUserIds(messageDetail.getUserIds(), noticeModel, messageDetail.getEvent());
messageDetail.setUserIds(realUserIds);
// 处理 WeCom Ding context
@ -50,7 +50,7 @@ public abstract class AbstractNoticeSender implements NoticeSender {
default:
break;
}
return context;
return getContent(context, noticeModel.getParamMap());
}
protected String getHtmlContext(MessageDetail messageDetail, NoticeModel noticeModel) {
@ -59,7 +59,7 @@ public abstract class AbstractNoticeSender implements NoticeSender {
return getContent(messageDetail.getTemplate(), noticeModel.getParamMap());
}
// 处理 userIds 中包含的特殊值
List<String> realUserIds = getRealUserIds(messageDetail.getUserIds(), noticeModel.getRelatedUsers(), messageDetail.getEvent());
List<String> realUserIds = getRealUserIds(messageDetail.getUserIds(), noticeModel, messageDetail.getEvent());
messageDetail.setUserIds(realUserIds);
// 处理 mail context
@ -70,6 +70,10 @@ public abstract class AbstractNoticeSender implements NoticeSender {
case NoticeConstants.Event.UPDATE:
case NoticeConstants.Event.DELETE:
case NoticeConstants.Event.COMMENT:
case NoticeConstants.Event.CLOSE_SCHEDULE:
case NoticeConstants.Event.CASE_CREATE:
case NoticeConstants.Event.CASE_UPDATE:
case NoticeConstants.Event.CASE_DELETE:
URL resource = this.getClass().getResource("/mail/" + noticeModel.getMailTemplate() + ".html");
context = IOUtils.toString(resource, StandardCharsets.UTF_8);
break;
@ -82,6 +86,8 @@ public abstract class AbstractNoticeSender implements NoticeSender {
context = IOUtils.toString(resource2, StandardCharsets.UTF_8);
break;
default:
URL resource3 = this.getClass().getResource("/mail/" + noticeModel.getMailTemplate() + ".html");
context = IOUtils.toString(resource3, StandardCharsets.UTF_8);
break;
}
} catch (IOException e) {
@ -103,7 +109,11 @@ public abstract class AbstractNoticeSender implements NoticeSender {
return template;
}
protected List<String> getUserPhones(List<String> userIds) {
protected List<String> getUserPhones(NoticeModel noticeModel, List<String> userIds) {
// 排除自己操作的
String operator = noticeModel.getOperator();
userIds.remove(operator);
List<UserDetail> list = userService.queryTypeByIds(userIds);
List<String> phoneList = new ArrayList<>();
list.forEach(u -> phoneList.add(u.getPhone()));
@ -111,7 +121,11 @@ public abstract class AbstractNoticeSender implements NoticeSender {
return phoneList.stream().distinct().collect(Collectors.toList());
}
protected List<String> getUserEmails(List<String> userIds) {
protected List<String> getUserEmails(NoticeModel noticeModel, List<String> userIds) {
// 排除自己操作的
String operator = noticeModel.getOperator();
userIds.remove(operator);
List<UserDetail> list = userService.queryTypeByIds(userIds);
List<String> phoneList = new ArrayList<>();
list.forEach(u -> phoneList.add(u.getEmail()));
@ -119,24 +133,35 @@ public abstract class AbstractNoticeSender implements NoticeSender {
return phoneList.stream().distinct().collect(Collectors.toList());
}
private List<String> getRealUserIds(List<String> userIds, List<String> relatedUsers, String event) {
private List<String> getRealUserIds(List<String> userIds, NoticeModel noticeModel, String event) {
List<String> toUserIds = new ArrayList<>();
Map<String, Object> paramMap = noticeModel.getParamMap();
for (String userId : userIds) {
switch (userId) {
case NoticeConstants.RelatedUser.EXECUTOR:
if (StringUtils.equals(NoticeConstants.Event.CREATE, event)) {
toUserIds.addAll(relatedUsers);
toUserIds.addAll(noticeModel.getRelatedUsers());
}
break;
case NoticeConstants.RelatedUser.FOUNDER:
if (StringUtils.equals(NoticeConstants.Event.UPDATE, event)
|| StringUtils.equals(NoticeConstants.Event.DELETE, event)) {
toUserIds.addAll(relatedUsers);
case NoticeConstants.RelatedUser.CREATOR:
Object creator = paramMap.get("creator");
if (creator != null) {
toUserIds.add(creator.toString());
}
Object createUser = paramMap.get("createUser");
if (createUser != null) {
toUserIds.add(createUser.toString());
}
break;
case NoticeConstants.RelatedUser.MAINTAINER:
if (StringUtils.equals(NoticeConstants.Event.COMMENT, event)) {
toUserIds.addAll(relatedUsers);
toUserIds.addAll(noticeModel.getRelatedUsers());
}
break;
case NoticeConstants.RelatedUser.FOLLOW_PEOPLE:
Object followPeople = paramMap.get("followPeople");
if (followPeople != null) {
toUserIds.add(followPeople.toString());
}
break;
default:

View File

@ -13,6 +13,10 @@ public class NoticeModel {
* 保存 测试id
*/
private String testId;
/**
* 操作人
*/
private String operator;
/**
* 保存状态
*/

View File

@ -0,0 +1,201 @@
package io.metersphere.notice.sender;
import com.alibaba.fastjson.JSON;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.dto.BaseSystemConfigDTO;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.notice.service.NoticeSendService;
import io.metersphere.service.SystemParameterService;
import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 系统日志切面处理类
*/
@Aspect
@Component
public class SendNoticeAspect {
@Resource
private NoticeSendService noticeSendService;
@Resource
private SystemParameterService systemParameterService;
private ExpressionParser parser = new SpelExpressionParser();
private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
@Pointcut("@annotation(io.metersphere.notice.annotation.SendNotice)")
public void pointcut() {
}
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
try {
//从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//获取切入点所在的方法
Method method = signature.getMethod();
//获取参数对象数组
Object[] args = joinPoint.getArgs();
SendNotice sendNotice = method.getAnnotation(SendNotice.class);
InvocationHandler invocationHandler = Proxy.getInvocationHandler(sendNotice);
Field value = invocationHandler.getClass().getDeclaredField("memberValues");
value.setAccessible(true);
if (StringUtils.isNotEmpty(sendNotice.target())) {
// 操作内容
//获取方法参数名
String[] params = discoverer.getParameterNames(method);
//将参数纳入Spring管理
EvaluationContext context = new StandardEvaluationContext();
for (int len = 0; len < params.length; len++) {
context.setVariable(params[len], args[len]);
}
context.setVariable("targetClass", CommonBeanFactory.getBean(sendNotice.targetClass()));
String target = sendNotice.target();
Expression titleExp = parser.parseExpression(target);
Object v = titleExp.getValue(context, Object.class);
Map<String, Object> memberValues = (Map<String, Object>) value.get(invocationHandler);
memberValues.put("source", JSON.toJSONString(v));
}
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
}
}
@AfterReturning(value = "pointcut()", returning = "retValue")
public void sendNotice(JoinPoint joinPoint, Object retValue) {
try {
//从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//获取切入点所在的方法
Method method = signature.getMethod();
//获取参数对象数组
Object[] args = joinPoint.getArgs();
//获取方法参数名
String[] params = discoverer.getParameterNames(method);
//获取操作
SendNotice sendNotice = method.getAnnotation(SendNotice.class);
EvaluationContext context = new StandardEvaluationContext();
for (int len = 0; len < params.length; len++) {
context.setVariable(params[len], args[len]);
}
handleNotice(sendNotice, retValue);
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
}
}
private void handleNotice(SendNotice sendNotice, Object retValue) {
//
List<Map> resources = new ArrayList<>();
String source = sendNotice.source();
if (StringUtils.isNotBlank(source)) {
// array
if (StringUtils.startsWith(source, "[")) {
resources.addAll(JSON.parseArray(source, Map.class));
}
// map
else {
Map<?, ?> value = JSON.parseObject(source, Map.class);
resources.add(value);
}
} else {
resources.add(new BeanMap(retValue));
}
// 有批量操作发送多次
for (Map resource : resources) {
Map<String, Object> paramMap = getParamMap(resource);
String context = getContext(sendNotice, paramMap);
NoticeModel noticeModel = NoticeModel.builder()
.operator(SessionUtils.getUserId())
.context(context)
.subject(sendNotice.subject())
.mailTemplate(sendNotice.mailTemplate())
.paramMap(paramMap)
.event(sendNotice.event())
.build();
noticeSendService.send(sendNotice.taskType(), noticeModel);
}
}
private Map<String, Object> getParamMap(Map resource) {
Map<String, Object> paramMap = new HashMap<>();
BaseSystemConfigDTO baseSystemConfigDTO = systemParameterService.getBaseInfo();
paramMap.put("url", baseSystemConfigDTO.getUrl());
paramMap.put("operator", SessionUtils.getUser().getName());
paramMap.putAll(resource);
return paramMap;
}
private String getContext(SendNotice sendNotice, Map<String, Object> paramMap) {
String operation = "";
switch (sendNotice.event()) {
case NoticeConstants.Event.CREATE:
operation = "创建了";
break;
case NoticeConstants.Event.UPDATE:
operation = "更新了";
break;
case NoticeConstants.Event.DELETE:
operation = "删除了";
break;
case NoticeConstants.Event.COMMENT:
operation = "评论了";
break;
case NoticeConstants.Event.CLOSE_SCHEDULE:
operation = "关闭了定时任务";
break;
case NoticeConstants.Event.CASE_CREATE:
operation = "创建了接口用例";
break;
case NoticeConstants.Event.CASE_UPDATE:
operation = "更新了接口用例";
break;
default:
break;
}
String subject = sendNotice.subject();
String resource = StringUtils.removeEnd(subject, "通知");
String name = "";
if (paramMap.containsKey("name")) {
name = ": ${name}";
}
if (paramMap.containsKey("title")) {
name = ": ${title}";
}
return "${operator}" + operation + resource + name;
}
}

View File

@ -16,7 +16,7 @@ import java.util.List;
@Component
public class DingNoticeSender extends AbstractNoticeSender {
public void sendNailRobot(MessageDetail messageDetail, String context) {
public void sendNailRobot(MessageDetail messageDetail, NoticeModel noticeModel, String context) {
List<String> userIds = messageDetail.getUserIds();
if (CollectionUtils.isEmpty(userIds)) {
return;
@ -28,7 +28,7 @@ public class DingNoticeSender extends AbstractNoticeSender {
text.setContent(context);
request.setText(text);
OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
List<String> phoneList = super.getUserPhones(userIds);
List<String> phoneList = super.getUserPhones(noticeModel, userIds);
LogUtil.info("收件人地址: " + phoneList);
at.setAtMobiles(phoneList);
request.setAt(at);
@ -42,6 +42,6 @@ public class DingNoticeSender extends AbstractNoticeSender {
@Override
public void send(MessageDetail messageDetail, NoticeModel noticeModel) {
String context = super.getContext(messageDetail, noticeModel);
sendNailRobot(messageDetail, context);
sendNailRobot(messageDetail, noticeModel, context);
}
}

View File

@ -35,7 +35,7 @@ public class MailNoticeSender extends AbstractNoticeSender {
LogUtil.info("发件人地址" + javaMailSender.getUsername());
LogUtil.info("helper" + helper);
helper.setSubject("MeterSphere " + noticeModel.getSubject());
List<String> emails = super.getUserEmails(messageDetail.getUserIds());
List<String> emails = super.getUserEmails(noticeModel, messageDetail.getUserIds());
String[] users = emails.toArray(new String[0]);
LogUtil.info("收件人地址: " + emails);
helper.setText(context, true);

View File

@ -16,13 +16,13 @@ import java.util.List;
public class WeComNoticeSender extends AbstractNoticeSender {
public void sendWechatRobot(MessageDetail messageDetail, String context) {
public void sendWechatRobot(MessageDetail messageDetail, NoticeModel noticeModel, String context) {
List<String> userIds = messageDetail.getUserIds();
if (CollectionUtils.isEmpty(userIds)) {
return;
}
TextMessage message = new TextMessage(context);
List<String> phoneLists = super.getUserPhones(userIds);
List<String> phoneLists = super.getUserPhones(noticeModel, userIds);
message.setMentionedMobileList(phoneLists);
try {
WxChatbotClient.send(messageDetail.getWebhook(), message);
@ -34,6 +34,6 @@ public class WeComNoticeSender extends AbstractNoticeSender {
@Override
public void send(MessageDetail messageDetail, NoticeModel noticeModel) {
String context = super.getContext(messageDetail, noticeModel);
sendWechatRobot(messageDetail, context);
sendWechatRobot(messageDetail, noticeModel, context);
}
}

View File

@ -1,64 +0,0 @@
package io.metersphere.notice.service;
import io.metersphere.api.dto.APIReportResult;
import io.metersphere.base.domain.ApiTestReportDetail;
import io.metersphere.base.domain.LoadTestReportWithBLOBs;
import io.metersphere.base.domain.Schedule;
import io.metersphere.base.mapper.ApiTestReportDetailMapper;
import io.metersphere.base.mapper.LoadTestReportMapper;
import io.metersphere.base.mapper.ext.ExtApiTestReportMapper;
import io.metersphere.base.mapper.ext.ExtLoadTestMapper;
import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.dto.LoadTestDTO;
import io.metersphere.performance.request.QueryTestPlanRequest;
import io.metersphere.service.ScheduleService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.List;
@Service
@Transactional(rollbackFor = Exception.class)
public class ApiAndPerformanceHelper {
@Resource
private ExtLoadTestMapper extLoadTestMapper;
@Resource
private ExtApiTestReportMapper extApiTestReportMapper;
@Resource
private ApiTestReportDetailMapper apiTestReportDetailMapper;
@Resource
private ScheduleService scheduleService;
@Resource
private LoadTestReportMapper loadTestReportMapper;
public APIReportResult getApi(String reportId) {
APIReportResult result = extApiTestReportMapper.get(reportId);
ApiTestReportDetail detail = apiTestReportDetailMapper.selectByPrimaryKey(reportId);
if (detail != null) {
result.setContent(new String(detail.getContent(), StandardCharsets.UTF_8));
}
return result;
}
public LoadTestDTO getPerformance(String testId) {
QueryTestPlanRequest request = new QueryTestPlanRequest();
request.setId(testId);
List<LoadTestDTO> testDTOS = extLoadTestMapper.list(request);
if (!CollectionUtils.isEmpty(testDTOS)) {
LoadTestDTO loadTestDTO = testDTOS.get(0);
Schedule schedule = scheduleService.getScheduleByResource(loadTestDTO.getId(), ScheduleGroup.PERFORMANCE_TEST.name());
loadTestDTO.setSchedule(schedule);
return loadTestDTO;
}
return null;
}
public LoadTestReportWithBLOBs getLoadTestReport(String id) {
return loadTestReportMapper.selectByPrimaryKey(id);
}
}

View File

@ -4,30 +4,27 @@ import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.LoadTestReportLog;
import io.metersphere.base.domain.LoadTestReportWithBLOBs;
import io.metersphere.base.domain.UserGroup;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.dto.LogDetailDTO;
import io.metersphere.dto.ReportDTO;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.performance.base.*;
import io.metersphere.performance.controller.request.DeleteReportRequest;
import io.metersphere.performance.controller.request.RenameReportRequest;
import io.metersphere.performance.controller.request.ReportRequest;
import io.metersphere.performance.dto.LoadTestExportJmx;
import io.metersphere.performance.service.PerformanceReportService;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping(value = "performance/report")
@ -54,6 +51,8 @@ public class PerformanceReportController {
@PostMapping("/delete/{reportId}")
@RequiresPermissions(PermissionConstants.PROJECT_PERFORMANCE_REPORT_READ_DELETE)
@MsAuditLog(module = "performance_test_report", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#reportId)", msClass = PerformanceReportService.class)
@SendNotice(taskType = NoticeConstants.TaskType.PERFORMANCE_REPORT_TASK, event = NoticeConstants.Event.DELETE,
target = "#targetClass.getReport(#reportId)", targetClass = PerformanceReportService.class, mailTemplate = "performance/ReportDelete", subject = "性能测试报告通知")
public void deleteReport(@PathVariable String reportId) {
performanceReportService.deleteReport(reportId);
}

View File

@ -5,6 +5,7 @@ import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.domain.LoadTest;
import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.commons.utils.PageUtils;
@ -17,6 +18,7 @@ import io.metersphere.dto.DashboardTestDTO;
import io.metersphere.dto.LoadTestDTO;
import io.metersphere.dto.ScheduleDao;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.performance.dto.LoadTestExportJmx;
import io.metersphere.performance.request.*;
import io.metersphere.performance.service.PerformanceTestService;
@ -76,7 +78,9 @@ public class PerformanceTestController {
@MsAuditLog(module = "performance_test", type = OperLogConstants.CREATE, title = "#request.name", content = "#msClass.getLogDetails(#request.id)", msClass = PerformanceTestService.class)
@RequiresPermissions(PermissionConstants.PROJECT_PERFORMANCE_TEST_READ_CREATE)
@CacheNode // 把监控节点缓存起来
public String save(
@SendNotice(taskType = NoticeConstants.TaskType.PERFORMANCE_TEST_TASK, event = NoticeConstants.Event.CREATE,
mailTemplate = "performance/TestCreate", subject = "性能测试通知")
public LoadTest save(
@RequestPart("request") SaveTestPlanRequest request,
@RequestPart(value = "file", required = false) List<MultipartFile> files
) {
@ -95,7 +99,8 @@ public class PerformanceTestController {
@MsAuditLog(module = "performance_test", type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#request.id)", title = "#request.name", content = "#msClass.getLogDetails(#request.id)", msClass = PerformanceTestService.class)
@RequiresPermissions(PermissionConstants.PROJECT_PERFORMANCE_TEST_READ_EDIT)
@CacheNode // 把监控节点缓存起来
public String edit(
@SendNotice(taskType = NoticeConstants.TaskType.PERFORMANCE_TEST_TASK, event = NoticeConstants.Event.UPDATE, mailTemplate = "performance/TestUpdate", subject = "性能测试通知")
public LoadTest edit(
@RequestPart("request") EditTestPlanRequest request,
@RequestPart(value = "file", required = false) List<MultipartFile> files
) {
@ -145,6 +150,8 @@ public class PerformanceTestController {
@MsAuditLog(module = "performance_test", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#request.id)", msClass = PerformanceTestService.class)
@RequiresPermissions(PermissionConstants.PROJECT_PERFORMANCE_TEST_READ_DELETE)
@CacheNode // 把监控节点缓存起来
@SendNotice(taskType = NoticeConstants.TaskType.PERFORMANCE_TEST_TASK, event = NoticeConstants.Event.DELETE,
target = "#targetClass.get(#request.id)", targetClass = PerformanceTestService.class, mailTemplate = "performance/TestDelete", subject = "性能测试通知")
public void delete(@RequestBody DeleteTestPlanRequest request) {
checkPermissionService.checkPerformanceTestOwner(request.getId());
performanceTestService.delete(request);

View File

@ -30,6 +30,8 @@ public class TestPlanRequest {
private String testResourcePoolId;
private String followPeople;
private static final long serialVersionUID = 1L;
}

View File

@ -144,7 +144,7 @@ public class PerformanceTestService {
loadTestFileMapper.deleteByExample(loadTestFileExample);
}
public String save(SaveTestPlanRequest request, List<MultipartFile> files) {
public LoadTest save(SaveTestPlanRequest request, List<MultipartFile> files) {
checkQuota(request, true);
LoadTestWithBLOBs loadTest = saveLoadTest(request);
@ -156,7 +156,7 @@ public class PerformanceTestService {
this.saveUploadFiles(files, loadTest, request.getFileSorts());
//关联转化的文件
this.conversionFiles(loadTest.getId(), request.getConversionFileIdList());
return loadTest.getId();
return loadTest;
}
private void conversionFiles(String id, List<String> conversionFileIdList) {
@ -230,13 +230,14 @@ public class PerformanceTestService {
loadTest.setAdvancedConfiguration(request.getAdvancedConfiguration());
loadTest.setStatus(PerformanceTestStatus.Saved.name());
loadTest.setNum(getNextNum(request.getProjectId()));
loadTest.setFollowPeople(request.getFollowPeople());
List<ApiLoadTest> apiList = request.getApiList();
apiPerformanceService.add(apiList, loadTest.getId());
loadTestMapper.insert(loadTest);
return loadTest;
}
public String edit(EditTestPlanRequest request, List<MultipartFile> files) {
public LoadTest edit(EditTestPlanRequest request, List<MultipartFile> files) {
checkQuota(request, false);
//
String testId = request.getId();
@ -278,9 +279,10 @@ public class PerformanceTestService {
loadTest.setAdvancedConfiguration(request.getAdvancedConfiguration());
loadTest.setTestResourcePoolId(request.getTestResourcePoolId());
loadTest.setStatus(PerformanceTestStatus.Saved.name());
loadTest.setFollowPeople(request.getFollowPeople());
loadTestMapper.updateByPrimaryKeySelective(loadTest);
return testId;
return loadTest;
}
@Transactional(noRollbackFor = MSException.class)// 保存失败的信息

View File

@ -4,10 +4,12 @@ import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.Issues;
import io.metersphere.base.domain.IssuesDao;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.track.issue.domain.PlatformUser;
import io.metersphere.track.issue.domain.zentao.ZentaoBuild;
import io.metersphere.track.request.testcase.AuthUserIssueRequest;
@ -40,12 +42,16 @@ public class IssuesController {
@PostMapping("/add")
@MsAuditLog(module = "track_bug", type = OperLogConstants.CREATE, content = "#msClass.getLogDetails(#issuesRequest)", msClass = IssuesService.class)
@SendNotice(taskType = NoticeConstants.TaskType.DEFECT_TASK, target = "#issuesRequest",
event = NoticeConstants.Event.CREATE, mailTemplate = "track/IssuesCreate", subject = "缺陷通知")
public void addIssues(@RequestBody IssuesUpdateRequest issuesRequest) {
issuesService.addIssues(issuesRequest);
}
@PostMapping("/update")
@MsAuditLog(module = "track_bug", type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#issuesRequest.id)", content = "#msClass.getLogDetails(#issuesRequest.id)", msClass = IssuesService.class)
@SendNotice(taskType = NoticeConstants.TaskType.DEFECT_TASK, target = "#issuesRequest",
event = NoticeConstants.Event.UPDATE, mailTemplate = "track/IssuesUpdate", subject = "缺陷通知")
public void updateIssues(@RequestBody IssuesUpdateRequest issuesRequest) {
issuesService.updateIssues(issuesRequest);
}
@ -88,6 +94,7 @@ public class IssuesController {
@GetMapping("/delete/{id}")
@MsAuditLog(module = "track_bug", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#id)", msClass = IssuesService.class)
@SendNotice(taskType = NoticeConstants.TaskType.DEFECT_TASK, target = "#targetClass.get(#id)", targetClass = IssuesService.class, event = NoticeConstants.Event.DELETE, mailTemplate = "track/IssuesDelete", subject = "缺陷通知")
public void delete(@PathVariable String id) {
issuesService.delete(id);
}

View File

@ -1,11 +1,15 @@
package io.metersphere.track.controller;
import io.metersphere.base.domain.TestCaseComment;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.track.dto.TestCaseCommentDTO;
import io.metersphere.track.request.testreview.SaveCommentRequest;
import io.metersphere.track.service.TestCaseCommentService;
import io.metersphere.track.service.TestCaseService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*;
@ -23,9 +27,11 @@ public class TestCaseCommentController {
@PostMapping("/save")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_COMMENT)
@MsAuditLog(module = "track_test_case_review", type = OperLogConstants.CREATE, content = "#msClass.getLogDetails(#request.id)", msClass = TestCaseCommentService.class)
public void saveComment(@RequestBody SaveCommentRequest request) {
@SendNotice(taskType = NoticeConstants.TaskType.TRACK_TEST_CASE_TASK, target = "#targetClass.getTestCase(#request.caseId)", targetClass = TestCaseService.class,
event = NoticeConstants.Event.COMMENT, mailTemplate = "track/TestCaseComment", subject = "测试用例通知")
public TestCaseComment saveComment(@RequestBody SaveCommentRequest request) {
request.setId(UUID.randomUUID().toString());
testCaseCommentService.saveComment(request);
return testCaseCommentService.saveComment(request);
}
@GetMapping("/list/{caseId}")
@ -43,7 +49,9 @@ public class TestCaseCommentController {
@PostMapping("/edit")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_COMMENT)
@MsAuditLog(module = "track_test_case_review", type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#request.id)", content = "#msClass.getLogDetails(#request.id)", msClass = TestCaseCommentService.class)
public void editComment(@RequestBody SaveCommentRequest request) {
testCaseCommentService.edit(request);
// @SendNotice(taskType = NoticeConstants.TaskType.TRACK_TEST_CASE_TASK, target = "#targetClass.getTestCase(#request.caseId)", targetClass = TestCaseService.class,
// event = NoticeConstants.Event.COMMENT, mailTemplate = "track/TestCaseComment", subject = "测试用例通知")
public TestCaseComment editComment(@RequestBody SaveCommentRequest request) {
return testCaseCommentService.edit(request);
}
}

View File

@ -6,7 +6,12 @@ import io.metersphere.api.dto.automation.ApiScenarioDTO;
import io.metersphere.api.dto.automation.ApiScenarioRequest;
import io.metersphere.api.dto.definition.ApiTestCaseDTO;
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.base.domain.*;
import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.domain.Project;
import io.metersphere.base.domain.TestCase;
import io.metersphere.base.domain.TestCaseWithBLOBs;
import io.metersphere.base.mapper.TestCaseMapper;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.commons.utils.PageUtils;
@ -16,6 +21,7 @@ import io.metersphere.dto.LoadTestDTO;
import io.metersphere.dto.TestCaseTestDao;
import io.metersphere.excel.domain.ExcelResponse;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.service.CheckPermissionService;
import io.metersphere.service.FileService;
import io.metersphere.track.dto.TestCaseDTO;
@ -168,14 +174,18 @@ public class TestCaseController {
@PostMapping(value = "/add", consumes = {"multipart/form-data"})
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_CASE_READ_CREATE)
@MsAuditLog(module = "track_test_case", type = OperLogConstants.CREATE, title = "#request.name", content = "#msClass.getLogDetails(#request.id)", msClass = TestCaseService.class)
public String addTestCase(@RequestPart("request") EditTestCaseRequest request, @RequestPart(value = "file", required = false) List<MultipartFile> files) {
@SendNotice(taskType = NoticeConstants.TaskType.TRACK_TEST_CASE_TASK, targetClass = TestCaseMapper.class,
event = NoticeConstants.Event.CREATE, mailTemplate = "track/TestCaseCreate", subject = "测试用例通知")
public TestCase addTestCase(@RequestPart("request") EditTestCaseRequest request, @RequestPart(value = "file", required = false) List<MultipartFile> files) {
request.setId(UUID.randomUUID().toString());
return testCaseService.save(request, files);
}
@PostMapping(value = "/edit", consumes = {"multipart/form-data"})
@MsAuditLog(module = "track_test_case", type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#request.id)", title = "#request.name", content = "#msClass.getLogDetails(#request.id)", msClass = TestCaseService.class)
public String editTestCase(@RequestPart("request") EditTestCaseRequest request, @RequestPart(value = "file", required = false) List<MultipartFile> files) {
@SendNotice(taskType = NoticeConstants.TaskType.TRACK_TEST_CASE_TASK, target = "#targetClass.getTestCase(#request.id)", targetClass = TestCaseService.class,
event = NoticeConstants.Event.UPDATE, mailTemplate = "track/TestCaseUpdate", subject = "测试用例通知")
public TestCase editTestCase(@RequestPart("request") EditTestCaseRequest request, @RequestPart(value = "file", required = false) List<MultipartFile> files) {
return testCaseService.edit(request, files);
}
@ -194,6 +204,8 @@ public class TestCaseController {
@PostMapping("/deleteToGc/{testCaseId}")
@MsAuditLog(module = "track_test_case", type = OperLogConstants.GC, beforeEvent = "#msClass.getLogDetails(#testCaseId)", msClass = TestCaseService.class)
@SendNotice(taskType = NoticeConstants.TaskType.TRACK_TEST_CASE_TASK, event = NoticeConstants.Event.DELETE, target = "#targetClass.getTestCase(#testCaseId)", targetClass = TestCaseService.class,
mailTemplate = "track/TestCaseDelete", subject = "测试用例通知")
public int deleteToGC(@PathVariable String testCaseId) {
checkPermissionService.checkTestCaseOwner(testCaseId);
return testCaseService.deleteTestCaseToGc(testCaseId);
@ -204,26 +216,26 @@ public class TestCaseController {
@MsAuditLog(module = "track_test_case", type = OperLogConstants.IMPORT, project = "#projectId")
public ExcelResponse testCaseImport(MultipartFile file, @PathVariable String projectId, @PathVariable String userId, @PathVariable String importType, HttpServletRequest request) {
checkPermissionService.checkProjectOwner(projectId);
return testCaseService.testCaseImport(file, projectId, userId, importType,request);
return testCaseService.testCaseImport(file, projectId, userId, importType, request);
}
@PostMapping("/importIgnoreError/{projectId}/{userId}/{importType}")
@MsAuditLog(module = "track_test_case", type = OperLogConstants.IMPORT, project = "#projectId")
public ExcelResponse testCaseImportIgnoreError(MultipartFile file, @PathVariable String projectId, @PathVariable String userId, @PathVariable String importType, HttpServletRequest request) {
checkPermissionService.checkProjectOwner(projectId);
return testCaseService.testCaseImportIgnoreError(file, projectId, userId,importType, request);
return testCaseService.testCaseImportIgnoreError(file, projectId, userId, importType, request);
}
@GetMapping("/export/template/{projectId}/{importType}")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_CASE_READ_EXPORT)
public void testCaseTemplateExport(@PathVariable String projectId,@PathVariable String importType,HttpServletResponse response) {
testCaseService.testCaseTemplateExport(projectId,importType,response);
public void testCaseTemplateExport(@PathVariable String projectId, @PathVariable String importType, HttpServletResponse response) {
testCaseService.testCaseTemplateExport(projectId, importType, response);
}
@GetMapping("/export/xmindTemplate/{projectId}/{importType}")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_CASE_READ_EXPORT)
public void xmindTemplate(@PathVariable String projectId,@PathVariable String importType,HttpServletResponse response) {
testCaseService.testCaseXmindTemplateExport(projectId,importType,response);
public void xmindTemplate(@PathVariable String projectId, @PathVariable String importType, HttpServletResponse response) {
testCaseService.testCaseXmindTemplateExport(projectId, importType, response);
}
@PostMapping("/export/testcase")

View File

@ -5,12 +5,14 @@ import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.Project;
import io.metersphere.base.domain.TestCaseReview;
import io.metersphere.base.domain.User;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.service.CheckPermissionService;
import io.metersphere.track.dto.TestCaseReviewDTO;
import io.metersphere.track.dto.TestReviewDTOWithMetric;
@ -45,7 +47,8 @@ public class TestCaseReviewController {
@PostMapping("/save")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_CREATE)
@MsAuditLog(module = "track_test_case_review", type = OperLogConstants.CREATE, title = "#reviewRequest.name", content = "#msClass.getLogDetails(#reviewRequest.id)", msClass = TestCaseReviewService.class)
public String saveCaseReview(@RequestBody SaveTestCaseReviewRequest reviewRequest) {
@SendNotice(taskType = NoticeConstants.TaskType.REVIEW_TASK, event = NoticeConstants.Event.CREATE, mailTemplate = "track/ReviewInitiate", subject = "测试评审通知")
public TestCaseReview saveCaseReview(@RequestBody SaveTestCaseReviewRequest reviewRequest) {
reviewRequest.setId(UUID.randomUUID().toString());
return testCaseReviewService.saveTestCaseReview(reviewRequest);
}
@ -70,13 +73,16 @@ public class TestCaseReviewController {
@PostMapping("/edit")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_EDIT)
@MsAuditLog(module = "track_test_case_review", type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#testCaseReview.id)", title = "#testCaseReview.name", content = "#msClass.getLogDetails(#testCaseReview.id)", msClass = TestCaseReviewService.class)
public String editCaseReview(@RequestBody SaveTestCaseReviewRequest testCaseReview) {
@SendNotice(taskType = NoticeConstants.TaskType.REVIEW_TASK, event = NoticeConstants.Event.UPDATE, mailTemplate = "track/ReviewEnd", subject = "测试评审通知")
public TestCaseReview editCaseReview(@RequestBody SaveTestCaseReviewRequest testCaseReview) {
return testCaseReviewService.editCaseReview(testCaseReview);
}
@GetMapping("/delete/{reviewId}")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_DELETE)
@MsAuditLog(module = "track_test_case_review", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#reviewId)", msClass = TestCaseReviewService.class)
@SendNotice(taskType = NoticeConstants.TaskType.REVIEW_TASK, target = "#targetClass.getTestReview(#reviewId)", targetClass = TestCaseReviewService.class,
event = NoticeConstants.Event.DELETE, mailTemplate = "track/ReviewDelete", subject = "测试评审通知")
public void deleteCaseReview(@PathVariable String reviewId) {
checkPermissionService.checkTestReviewOwner(reviewId);
testCaseReviewService.deleteCaseReview(reviewId);
@ -117,6 +123,7 @@ public class TestCaseReviewController {
@PostMapping("/edit/status/{reviewId}")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_EDIT)
@SendNotice(taskType = NoticeConstants.TaskType.REVIEW_TASK, event = NoticeConstants.Event.UPDATE, mailTemplate = "track/ReviewEnd", subject = "测试评审通知")
public void editTestPlanStatus(@PathVariable String reviewId) {
checkPermissionService.checkTestReviewOwner(reviewId);
testCaseReviewService.editTestReviewStatus(reviewId);

View File

@ -3,15 +3,21 @@ package io.metersphere.track.controller;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.datacount.request.ScheduleInfoRequest;
import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.base.domain.Project;
import io.metersphere.base.domain.Schedule;
import io.metersphere.base.domain.TestPlan;
import io.metersphere.base.domain.TestPlanWithBLOBs;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.service.CheckPermissionService;
import io.metersphere.service.ScheduleService;
import io.metersphere.track.dto.*;
import io.metersphere.track.request.testcase.PlanCaseRelevanceRequest;
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
@ -40,6 +46,10 @@ public class TestPlanController {
TestPlanProjectService testPlanProjectService;
@Resource
CheckPermissionService checkPermissionService;
@Resource
private ScheduleService scheduleService;
@Resource
private ApiAutomationService apiAutomationService;
@PostMapping("/autoCheck/{testPlanId}")
public void autoCheck(@PathVariable String testPlanId) {
@ -87,17 +97,18 @@ public class TestPlanController {
@PostMapping("/add")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_PLAN_READ_CREATE)
@MsAuditLog(module = "track_test_plan", type = OperLogConstants.CREATE, title = "#testPlan.name", content = "#msClass.getLogDetails(#testPlan.id)", msClass = TestPlanService.class)
public String addTestPlan(@RequestBody AddTestPlanRequest testPlan) {
@SendNotice(taskType = NoticeConstants.TaskType.TEST_PLAN_TASK, event = NoticeConstants.Event.CREATE, mailTemplate = "track/TestPlanStart", subject = "测试计划通知")
public TestPlan addTestPlan(@RequestBody AddTestPlanRequest testPlan) {
testPlan.setId(UUID.randomUUID().toString());
return testPlanService.addTestPlan(testPlan);
}
@PostMapping("/edit")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_PLAN_READ_EDIT)
@MsAuditLog(module = "track_test_plan", type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#testPlanDTO.id)", content = "#msClass.getLogDetails(#testPlanDTO.id)", msClass = TestPlanService.class)
public String editTestPlan(@RequestBody TestPlanDTO testPlanDTO) {
return testPlanService.editTestPlan(testPlanDTO, true);
@SendNotice(taskType = NoticeConstants.TaskType.TEST_PLAN_TASK, event = NoticeConstants.Event.UPDATE, mailTemplate = "track/TestPlanEnd", subject = "测试计划通知")
public TestPlan editTestPlan(@RequestBody TestPlanDTO testPlanDTO) {
return testPlanService.editTestPlan(testPlanDTO);
}
@PostMapping("/edit/status/{planId}")
@ -111,6 +122,7 @@ public class TestPlanController {
@PostMapping("/delete/{testPlanId}")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_PLAN_READ_DELETE)
@MsAuditLog(module = "track_test_plan", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#testPlanId)", msClass = TestPlanService.class)
@SendNotice(taskType = NoticeConstants.TaskType.TEST_PLAN_TASK, event = NoticeConstants.Event.DELETE, mailTemplate = "track/TestPlanDelete", subject = "测试计划通知")
public int deleteTestPlan(@PathVariable String testPlanId) {
checkPermissionService.checkTestPlanOwner(testPlanId);
return testPlanService.deleteTestPlan(testPlanId);
@ -194,12 +206,12 @@ public class TestPlanController {
}
@GetMapping("/report/{planId}")
public TestPlanSimpleReportDTO getReport(@PathVariable String planId){
public TestPlanSimpleReportDTO getReport(@PathVariable String planId) {
return testPlanService.getReport(planId);
}
@GetMapping("/report/functional/result")
public TestCaseReportStatusResultDTO getFunctionalResultReport(@PathVariable String planId){
public TestCaseReportStatusResultDTO getFunctionalResultReport(@PathVariable String planId) {
return testPlanService.getFunctionalResultReport(planId);
}
@ -207,4 +219,13 @@ public class TestPlanController {
public void editReport(@RequestBody TestPlanWithBLOBs testPlanWithBLOBs) {
testPlanService.editReport(testPlanWithBLOBs);
}
@PostMapping(value = "/schedule/updateEnableByPrimyKey")
@SendNotice(taskType = NoticeConstants.TaskType.TRACK_HOME_TASK, event = NoticeConstants.Event.CLOSE_SCHEDULE, mailTemplate = "track/ScheduleClose", subject = "测试跟踪通知")
public Schedule updateScheduleEnableByPrimyKey(@RequestBody ScheduleInfoRequest request) {
Schedule schedule = scheduleService.getSchedule(request.getTaskID());
schedule.setEnable(request.isEnable());
apiAutomationService.updateSchedule(schedule);
return schedule;
}
}

View File

@ -3,12 +3,14 @@ package io.metersphere.track.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.TestPlanReport;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.track.dto.TestPlanReportDTO;
import io.metersphere.track.request.report.QueryTestPlanReportRequest;
import io.metersphere.track.request.report.TestPlanReportSaveRequest;
@ -30,11 +32,13 @@ public class TestPlanReportController {
@Resource
private TestPlanReportService testPlanReportService;
@PostMapping("/list/{goPage}/{pageSize}")
public Pager<List<TestPlanReportDTO>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestPlanReportRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, testPlanReportService.list(request));
}
@GetMapping("/getMetric/{planId}")
public TestPlanReportDTO getMetric(@PathVariable String planId) {
return testPlanReportService.getMetric(planId);
@ -56,6 +60,8 @@ public class TestPlanReportController {
@PostMapping("/delete")
@MsAuditLog(module = "track_report", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#testPlanReportIdList)", msClass = TestPlanReportService.class)
@SendNotice(taskType = NoticeConstants.TaskType.TRACK_REPORT_TASK, target = "#targetClass.getReports(#testPlanReportIdList)", targetClass = TestPlanReportService.class,
event = NoticeConstants.Event.DELETE, mailTemplate = "track/ReportDelete", subject = "报告通知")
public void delete(@RequestBody List<String> testPlanReportIdList) {
testPlanReportService.delete(testPlanReportIdList);
}
@ -67,20 +73,20 @@ public class TestPlanReportController {
@GetMapping("/apiExecuteFinish/{planId}/{userId}")
public void apiExecuteFinish(@PathVariable String planId,@PathVariable String userId) {
public void apiExecuteFinish(@PathVariable String planId, @PathVariable String userId) {
String reportId = UUID.randomUUID().toString();
TestPlanReportSaveRequest saveRequest = new TestPlanReportSaveRequest(reportId,planId,userId,ReportTriggerMode.API.name());
TestPlanReportSaveRequest saveRequest = new TestPlanReportSaveRequest(reportId, planId, userId, ReportTriggerMode.API.name());
TestPlanReport report = testPlanReportService.genTestPlanReport(saveRequest);
testPlanReportService.countReportByTestPlanReportId(report.getId(),null, ReportTriggerMode.API.name(),null);
testPlanReportService.countReportByTestPlanReportId(report.getId(), null, ReportTriggerMode.API.name(), null);
}
@GetMapping("/saveTestPlanReport/{planId}/{triggerMode}")
public String saveTestPlanReport(@PathVariable String planId,@PathVariable String triggerMode) {
public String saveTestPlanReport(@PathVariable String planId, @PathVariable String triggerMode) {
String userId = SessionUtils.getUser().getId();
String reportId = UUID.randomUUID().toString();
TestPlanReportSaveRequest saveRequest = new TestPlanReportSaveRequest(reportId,planId,userId,triggerMode);
TestPlanReportSaveRequest saveRequest = new TestPlanReportSaveRequest(reportId, planId, userId, triggerMode);
TestPlanReport report = testPlanReportService.genTestPlanReport(saveRequest);
testPlanReportService.countReportByTestPlanReportId(report.getId(),null, triggerMode,null);
testPlanReportService.countReportByTestPlanReportId(report.getId(), null, triggerMode, null);
return "success";
}
}

View File

@ -13,12 +13,10 @@ import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.user.SessionUser;
import io.metersphere.commons.utils.*;
import io.metersphere.controller.request.IntegrationRequest;
import io.metersphere.i18n.Translator;
import io.metersphere.log.utils.ReflexObjectUtil;
import io.metersphere.log.vo.DetailColumn;
import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.log.vo.track.TestPlanReference;
import io.metersphere.notice.sender.NoticeModel;
import io.metersphere.notice.service.NoticeSendService;
import io.metersphere.service.IntegrationService;
import io.metersphere.service.IssueTemplateService;
@ -90,7 +88,6 @@ public class IssuesService {
}
public void addIssues(IssuesUpdateRequest issuesRequest) {
List<AbstractIssuePlatform> platformList = getUpdatePlatforms(issuesRequest);
platformList.forEach(platform -> {
@ -108,27 +105,6 @@ public class IssuesService {
LogUtil.error("处理bug数量报错caseId: {}, message: {}", l, ExceptionUtils.getStackTrace(e));
}
});
noticeIssueEven(issuesRequest, "IssuesCreate");
}
public void noticeIssueEven(IssuesUpdateRequest issuesRequest, String type) {
SessionUser user = SessionUtils.getUser();
String orgId = user.getLastOrganizationId();
List<String> userIds = new ArrayList<>();
userIds.add(orgId);
String context = getIssuesContext(user, issuesRequest, NoticeConstants.Event.CREATE);
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("issuesName", issuesRequest.getTitle());
paramMap.put("creator", user.getName());
NoticeModel noticeModel = NoticeModel.builder()
.context(context)
.relatedUsers(userIds)
.subject(Translator.get("task_defect_notification"))
.mailTemplate(type)
.paramMap(paramMap)
.event(NoticeConstants.Event.CREATE)
.build();
noticeSendService.send(NoticeConstants.TaskType.DEFECT_TASK, noticeModel);
}
@ -324,6 +300,10 @@ public class IssuesService {
testCaseIssuesMapper.deleteByExample(example);
}
public IssuesWithBLOBs get(String id) {
return issuesMapper.selectByPrimaryKey(id);
}
private static String getIssuesContext(SessionUser user, IssuesUpdateRequest issuesRequest, String type) {
String context = "";
if (StringUtils.equals(NoticeConstants.Event.CREATE, type)) {
@ -476,7 +456,7 @@ public class IssuesService {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
try {
Class clazz = loader.loadClass("io.metersphere.xpack.issue.azuredevops.AzureDevopsPlatform");
Constructor cons = clazz.getDeclaredConstructor(new Class[] { IssuesRequest.class });
Constructor cons = clazz.getDeclaredConstructor(new Class[]{IssuesRequest.class});
AbstractIssuePlatform azureDevopsPlatform = (AbstractIssuePlatform) cons.newInstance(issuesRequest);
syncThirdPartyIssues(azureDevopsPlatform::syncIssues, project, azureDevopsIssues);
} catch (ClassNotFoundException e) {

View File

@ -47,7 +47,7 @@ public class TestCaseCommentService {
@Resource
private SystemParameterService systemParameterService;
public void saveComment(SaveCommentRequest request) {
public TestCaseComment saveComment(SaveCommentRequest request) {
TestCaseComment testCaseComment = new TestCaseComment();
testCaseComment.setId(request.getId());
testCaseComment.setAuthor(SessionUtils.getUser().getId());
@ -57,30 +57,31 @@ public class TestCaseCommentService {
testCaseComment.setDescription(request.getDescription());
testCaseComment.setStatus(request.getStatus());
testCaseCommentMapper.insert(testCaseComment);
TestCaseWithBLOBs testCaseWithBLOBs;
testCaseWithBLOBs = testCaseMapper.selectByPrimaryKey(request.getCaseId());
// 发送通知
User user = userMapper.selectByPrimaryKey(testCaseComment.getAuthor());
BaseSystemConfigDTO baseSystemConfigDTO = systemParameterService.getBaseInfo();
List<String> userIds = new ArrayList<>();
userIds.add(testCaseWithBLOBs.getMaintainer());//用例维护人
String context = getReviewContext(testCaseComment, testCaseWithBLOBs);
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("maintainer", user.getName());
paramMap.put("testCaseName", testCaseWithBLOBs.getName());
paramMap.put("description", request.getDescription());
paramMap.put("url", baseSystemConfigDTO.getUrl());
paramMap.put("id", request.getReviewId());
NoticeModel noticeModel = NoticeModel.builder()
.context(context)
.relatedUsers(userIds)
.subject(Translator.get("test_review_task_notice"))
.mailTemplate("ReviewComments")
.paramMap(paramMap)
.event(NoticeConstants.Event.COMMENT)
.build();
noticeSendService.send(NoticeConstants.TaskType.REVIEW_TASK, noticeModel);
// TestCaseWithBLOBs testCaseWithBLOBs;
// testCaseWithBLOBs = testCaseMapper.selectByPrimaryKey(request.getCaseId());
//
// // 发送通知
// User user = userMapper.selectByPrimaryKey(testCaseComment.getAuthor());
// BaseSystemConfigDTO baseSystemConfigDTO = systemParameterService.getBaseInfo();
// List<String> userIds = new ArrayList<>();
// userIds.add(testCaseWithBLOBs.getMaintainer());//用例维护人
// String context = getReviewContext(testCaseComment, testCaseWithBLOBs);
// Map<String, Object> paramMap = new HashMap<>();
// paramMap.put("maintainer", user.getName());
// paramMap.put("testCaseName", testCaseWithBLOBs.getName());
// paramMap.put("description", request.getDescription());
// paramMap.put("url", baseSystemConfigDTO.getUrl());
// paramMap.put("id", request.getReviewId());
// NoticeModel noticeModel = NoticeModel.builder()
// .context(context)
// .relatedUsers(userIds)
// .subject(Translator.get("test_review_task_notice"))
// .mailTemplate("ReviewComments")
// .paramMap(paramMap)
// .event(NoticeConstants.Event.COMMENT)
// .build();
// noticeSendService.send(NoticeConstants.TaskType.REVIEW_TASK, noticeModel);
return testCaseComment;
}
public List<TestCaseCommentDTO> getCaseComments(String caseId) {
@ -112,9 +113,10 @@ public class TestCaseCommentService {
testCaseCommentMapper.deleteByPrimaryKey(commentId);
}
public void edit(SaveCommentRequest request) {
public TestCaseComment edit(SaveCommentRequest request) {
checkCommentOwner(request.getId());
testCaseCommentMapper.updateByPrimaryKeySelective(request);
return testCaseCommentMapper.selectByPrimaryKey(request.getId());
}
private void checkCommentOwner(String commentId) {

View File

@ -93,7 +93,7 @@ public class TestCaseReviewService {
private ApiDefinitionMapper apiDefinitionMapper;
public String saveTestCaseReview(SaveTestCaseReviewRequest reviewRequest) {
public TestCaseReview saveTestCaseReview(SaveTestCaseReviewRequest reviewRequest) {
checkCaseReviewExist(reviewRequest);
String reviewId = reviewRequest.getId();
List<String> userIds = reviewRequest.getUserIds();//执行人
@ -115,19 +115,7 @@ public class TestCaseReviewService {
reviewRequest.setProjectId(SessionUtils.getCurrentProjectId());
}
testCaseReviewMapper.insert(reviewRequest);
// 发送通知
String context = getReviewContext(reviewRequest, NoticeConstants.Event.CREATE);
Map<String, Object> paramMap = new HashMap<>(getReviewParamMap(reviewRequest));
NoticeModel noticeModel = NoticeModel.builder()
.context(context)
.relatedUsers(userIds)
.subject(Translator.get("test_review_task_notice"))
.mailTemplate("ReviewInitiate")
.paramMap(paramMap)
.event(NoticeConstants.Event.CREATE)
.build();
noticeSendService.send(NoticeConstants.TaskType.REVIEW_TASK, noticeModel);
return reviewRequest.getId();
return reviewRequest;
}
//评审内容
@ -221,25 +209,12 @@ public class TestCaseReviewService {
return extTestCaseReviewMapper.listByWorkspaceId(currentWorkspaceId, SessionUtils.getUserId(), SessionUtils.getCurrentProjectId());
}
public String editCaseReview(SaveTestCaseReviewRequest testCaseReview) {
public TestCaseReview editCaseReview(SaveTestCaseReviewRequest testCaseReview) {
editCaseReviewer(testCaseReview);
testCaseReview.setUpdateTime(System.currentTimeMillis());
checkCaseReviewExist(testCaseReview);
testCaseReviewMapper.updateByPrimaryKeySelective(testCaseReview);
// 发送通知
List<String> userIds = new ArrayList<>(testCaseReview.getUserIds());
String context = getReviewContext(testCaseReview, NoticeConstants.Event.UPDATE);
Map<String, Object> paramMap = new HashMap<>(getReviewParamMap(testCaseReview));
NoticeModel noticeModel = NoticeModel.builder()
.context(context)
.relatedUsers(userIds)
.subject(Translator.get("test_review_task_notice"))
.mailTemplate("ReviewEnd")
.paramMap(paramMap)
.event(NoticeConstants.Event.UPDATE)
.build();
noticeSendService.send(NoticeConstants.TaskType.REVIEW_TASK, noticeModel);
return testCaseReview.getId();
return testCaseReview;
}
private void editCaseReviewer(SaveTestCaseReviewRequest testCaseReview) {
@ -284,31 +259,10 @@ public class TestCaseReviewService {
}
public void deleteCaseReview(String reviewId) {
TestCaseReview testCaseReview = getTestReview(reviewId);
deleteCaseReviewProject(reviewId);
deleteCaseReviewUsers(reviewId);
deleteCaseReviewTestCase(reviewId);
testCaseReviewMapper.deleteByPrimaryKey(reviewId);
// 发送通知
try {
List<String> userIds = new ArrayList<>();
userIds.add(testCaseReview.getCreator());
SaveTestCaseReviewRequest testCaseReviewRequest = new SaveTestCaseReviewRequest();
BeanUtils.copyProperties(testCaseReviewRequest, testCaseReview);
String context = getReviewContext(testCaseReviewRequest, NoticeConstants.Event.DELETE);
Map<String, Object> paramMap = new HashMap<>(getReviewParamMap(testCaseReviewRequest));
NoticeModel noticeModel = NoticeModel.builder()
.context(context)
.relatedUsers(userIds)
.subject(Translator.get("test_review_task_notice"))
.mailTemplate("ReviewDelete")
.paramMap(paramMap)
.event(NoticeConstants.Event.DELETE)
.build();
noticeSendService.send(NoticeConstants.TaskType.REVIEW_TASK, noticeModel);
} catch (Exception e) {
LogUtil.error(e);
}
}
private void deleteCaseReviewProject(String reviewId) {
@ -467,28 +421,6 @@ public class TestCaseReviewService {
}
testCaseReview.setStatus(TestCaseReviewStatus.Completed.name());
testCaseReviewMapper.updateByPrimaryKeySelective(testCaseReview);
SaveTestCaseReviewRequest testCaseReviewRequest = new SaveTestCaseReviewRequest();
TestCaseReview _testCaseReview = testCaseReviewMapper.selectByPrimaryKey(reviewId);
List<String> userIds = new ArrayList<>();
userIds.add(_testCaseReview.getCreator());
if (StringUtils.equals(TestCaseReviewStatus.Completed.name(), _testCaseReview.getStatus())) {
try {
BeanUtils.copyProperties(testCaseReviewRequest, _testCaseReview);
String context = getReviewContext(testCaseReviewRequest, NoticeConstants.Event.UPDATE);
Map<String, Object> paramMap = new HashMap<>(getReviewParamMap(testCaseReviewRequest));
NoticeModel noticeModel = NoticeModel.builder()
.context(context)
.relatedUsers(userIds)
.subject(Translator.get("test_review_task_notice"))
.mailTemplate("ReviewEnd")
.paramMap(paramMap)
.event(NoticeConstants.Event.UPDATE)
.build();
noticeSendService.send(NoticeConstants.TaskType.REVIEW_TASK, noticeModel);
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
}
}
}
public List<TestReviewDTOWithMetric> listRelateAll(ReviewRelateRequest relateRequest) {

View File

@ -1243,7 +1243,7 @@ public class TestCaseService {
return false;
}
public String save(EditTestCaseRequest request, List<MultipartFile> files) {
public TestCase save(EditTestCaseRequest request, List<MultipartFile> files) {
final TestCaseWithBLOBs testCaseWithBLOBs = addTestCase(request);
@ -1282,10 +1282,10 @@ public class TestCaseService {
});
}
return testCaseWithBLOBs.getId();
return testCaseWithBLOBs;
}
public String edit(EditTestCaseRequest request, List<MultipartFile> files) {
public TestCase edit(EditTestCaseRequest request, List<MultipartFile> files) {
TestCaseWithBLOBs testCaseWithBLOBs = testCaseMapper.selectByPrimaryKey(request.getId());
request.setNum(testCaseWithBLOBs.getNum());
if (testCaseWithBLOBs == null) {
@ -1339,7 +1339,7 @@ public class TestCaseService {
}
this.setNode(request);
editTestCase(request);
return request.getId();
return testCaseWithBLOBs;
}
public String editTestCase(EditTestCaseRequest request, List<MultipartFile> files) {

View File

@ -111,7 +111,7 @@ public class TestPlanReportService {
// }
private TestPlanReport updateTestPlanReportById(String id) {
return this.updateExecuteApis(id,null,null,null);
return this.updateExecuteApis(id, null, null, null);
}
public TestPlanScheduleReportInfoDTO genTestPlanReportBySchedule(String projectID, String planId, String userId, String triggerMode) {
@ -141,15 +141,15 @@ public class TestPlanReportService {
Map<String, String> apiCaseInfoMap = new HashMap<>();
for (String id : apiTestCaseIdMap.keySet()) {
apiCaseInfoMap.put(id,TestPlanApiExecuteStatus.PREPARE.name());
apiCaseInfoMap.put(id, TestPlanApiExecuteStatus.PREPARE.name());
}
Map<String, String> scenarioInfoMap = new HashMap<>();
for (String id : planScenarioIdMap.keySet()) {
scenarioInfoMap.put(id,TestPlanApiExecuteStatus.PREPARE.name());
scenarioInfoMap.put(id, TestPlanApiExecuteStatus.PREPARE.name());
}
Map<String, String> performanceInfoMap = new HashMap<>();
for (String id : performanceIdMap.values()) {
performanceInfoMap.put(id,TestPlanApiExecuteStatus.PREPARE.name());
performanceInfoMap.put(id, TestPlanApiExecuteStatus.PREPARE.name());
}
TestPlanReportSaveRequest saveRequest = new TestPlanReportSaveRequest(planReportId, planId, userId, triggerMode,
apiTestCaseIdMap.size() > 0, planScenarioIdMap.size() > 0, performanceIdMap.size() > 0,
@ -216,13 +216,13 @@ public class TestPlanReportService {
testPlanReport.setIsPerformanceExecuting(!performanceIdList.isEmpty());
for (String id : apiCaseIdList) {
apiCaseInfoMap.put(id,TestPlanApiExecuteStatus.PREPARE.name());
apiCaseInfoMap.put(id, TestPlanApiExecuteStatus.PREPARE.name());
}
for (String id : scenarioIdList) {
scenarioInfoMap.put(id,TestPlanApiExecuteStatus.PREPARE.name());
scenarioInfoMap.put(id, TestPlanApiExecuteStatus.PREPARE.name());
}
for (String id : performanceIdList) {
performanceInfoMap.put(id,TestPlanApiExecuteStatus.PREPARE.name());
performanceInfoMap.put(id, TestPlanApiExecuteStatus.PREPARE.name());
}
} else {
testPlanReport.setIsApiCaseExecuting(saveRequest.isApiCaseIsExecuting());
@ -235,8 +235,8 @@ public class TestPlanReportService {
}
List<TestPlanReportResource> resourceList = new ArrayList<>();
if(MapUtils.isNotEmpty(apiCaseInfoMap)){
for (Map.Entry<String, String> entry : apiCaseInfoMap.entrySet()){
if (MapUtils.isNotEmpty(apiCaseInfoMap)) {
for (Map.Entry<String, String> entry : apiCaseInfoMap.entrySet()) {
String id = entry.getKey();
String status = entry.getValue();
String type = TestPlanResourceType.API_CASE.name();
@ -250,8 +250,8 @@ public class TestPlanReportService {
resourceList.add(apiCaseResource);
}
}
if(MapUtils.isNotEmpty(scenarioInfoMap)){
for (Map.Entry<String, String> entry : scenarioInfoMap.entrySet()){
if (MapUtils.isNotEmpty(scenarioInfoMap)) {
for (Map.Entry<String, String> entry : scenarioInfoMap.entrySet()) {
String id = entry.getKey();
String status = entry.getValue();
String type = TestPlanResourceType.SCENARIO_CASE.name();
@ -265,8 +265,8 @@ public class TestPlanReportService {
resourceList.add(scenarioResource);
}
}
if(MapUtils.isNotEmpty(performanceInfoMap)){
for (Map.Entry<String, String> entry : performanceInfoMap.entrySet()){
if (MapUtils.isNotEmpty(performanceInfoMap)) {
for (Map.Entry<String, String> entry : performanceInfoMap.entrySet()) {
String id = entry.getKey();
String status = entry.getValue();
String type = TestPlanResourceType.PERFORMANCE_CASE.name();
@ -310,8 +310,8 @@ public class TestPlanReportService {
TestPlanReportDTO returnDTO = new TestPlanReportDTO();
TestPlanReport report = testPlanReportMapper.selectByPrimaryKey(reportId);
if (report != null) {
if(StringUtils.equalsIgnoreCase(report.getStatus(),TestPlanApiExecuteStatus.RUNNING.name())){
report = this.updateExecuteApis(reportId,null,null,null);
if (StringUtils.equalsIgnoreCase(report.getStatus(), TestPlanApiExecuteStatus.RUNNING.name())) {
report = this.updateExecuteApis(reportId, null, null, null);
}
TestPlanReportDataExample example = new TestPlanReportDataExample();
example.createCriteria().andTestPlanReportIdEqualTo(reportId);
@ -364,15 +364,15 @@ public class TestPlanReportService {
}
}
public TestCaseReportMetricDTO countReportData(TestPlanDTO testPlan, Map<String,Map<String, String>> executeResult) {
public TestCaseReportMetricDTO countReportData(TestPlanDTO testPlan, Map<String, Map<String, String>> executeResult) {
TestCaseReportMetricDTO returnDTO = new TestCaseReportMetricDTO();
ReportResultComponent reportResultComponent = new ReportResultComponent(testPlan);
reportResultComponent.afterBuild(returnDTO);
TestCaseReportAdvanceStatusResultDTO statusDTO = new TestCaseReportAdvanceStatusResultDTO();
Map<String,String> apiCaseExecuteMap = executeResult.get(TestPlanResourceType.API_CASE.name());
Map<String,String> scenarioExecuteMap = executeResult.get(TestPlanResourceType.SCENARIO_CASE.name());
Map<String,String> performanceCaseExecuteMap = executeResult.get(TestPlanResourceType.PERFORMANCE_CASE.name());
Map<String, String> apiCaseExecuteMap = executeResult.get(TestPlanResourceType.API_CASE.name());
Map<String, String> scenarioExecuteMap = executeResult.get(TestPlanResourceType.SCENARIO_CASE.name());
Map<String, String> performanceCaseExecuteMap = executeResult.get(TestPlanResourceType.PERFORMANCE_CASE.name());
List<TestCaseReportStatusResultDTO> apiResult = new ArrayList<>();
List<TestCaseReportStatusResultDTO> scenarioResult = new ArrayList<>();
@ -382,9 +382,9 @@ public class TestPlanReportService {
List<String> faliureScenarioCaseIdList = new ArrayList<>();
List<String> faliureLoadCaseIdList = new ArrayList<>();
if(MapUtils.isNotEmpty(apiCaseExecuteMap)){
if (MapUtils.isNotEmpty(apiCaseExecuteMap)) {
Map<String, Integer> countMap = new HashMap<>();
for (Map.Entry<String, String> executeEntry: apiCaseExecuteMap.entrySet()){
for (Map.Entry<String, String> executeEntry : apiCaseExecuteMap.entrySet()) {
String caseResult = executeEntry.getValue();
String id = executeEntry.getKey();
if (StringUtils.equalsAnyIgnoreCase(caseResult, TestPlanApiExecuteStatus.SUCCESS.name())) {
@ -425,9 +425,9 @@ public class TestPlanReportService {
}
}
if(MapUtils.isNotEmpty(scenarioExecuteMap)){
if (MapUtils.isNotEmpty(scenarioExecuteMap)) {
Map<String, Integer> countMap = new HashMap<>();
for (Map.Entry<String, String> executeEntry: scenarioExecuteMap.entrySet()){
for (Map.Entry<String, String> executeEntry : scenarioExecuteMap.entrySet()) {
String caseResult = executeEntry.getValue();
String id = executeEntry.getKey();
if (StringUtils.equalsAnyIgnoreCase(caseResult, TestPlanApiExecuteStatus.SUCCESS.name())) {
@ -468,9 +468,9 @@ public class TestPlanReportService {
}
}
if(MapUtils.isNotEmpty(performanceCaseExecuteMap)){
if (MapUtils.isNotEmpty(performanceCaseExecuteMap)) {
Map<String, Integer> countMap = new HashMap<>();
for (Map.Entry<String, String> executeEntry: performanceCaseExecuteMap.entrySet()){
for (Map.Entry<String, String> executeEntry : performanceCaseExecuteMap.entrySet()) {
String caseResult = executeEntry.getValue();
String id = executeEntry.getKey();
if (StringUtils.equalsAnyIgnoreCase(caseResult, TestPlanApiExecuteStatus.SUCCESS.name())) {
@ -662,13 +662,13 @@ public class TestPlanReportService {
return returnDTO;
}
public TestPlanReport updateReport(TestPlanReportDataWithBLOBs testPlanReportData, boolean apiCaseIsOk, boolean scenarioIsOk, boolean performanceIsOk,boolean updateTime) {
public TestPlanReport updateReport(TestPlanReportDataWithBLOBs testPlanReportData, boolean apiCaseIsOk, boolean scenarioIsOk, boolean performanceIsOk, boolean updateTime) {
TestPlanReport testPlanReport = testPlanReportMapper.selectByPrimaryKey(testPlanReportData.getTestPlanReportId());
if (testPlanReport == null) {
return null;
}
if(updateTime){
if (updateTime) {
testPlanReport.setEndTime(System.currentTimeMillis());
testPlanReport.setUpdateTime(System.currentTimeMillis());
}
@ -699,9 +699,9 @@ public class TestPlanReportService {
testPlanService.buildScenarioCaseReport(testPlanReport.getTestPlanId(), components);
testPlanService.buildLoadCaseReport(testPlanReport.getTestPlanId(), components);
Map<String,Map<String, String>> testPlanExecuteResult = testPlanReportResourceService.selectExecuteResultByTestPlanReportId(testPlanReportData.getTestPlanReportId());
Map<String, Map<String, String>> testPlanExecuteResult = testPlanReportResourceService.selectExecuteResultByTestPlanReportId(testPlanReportData.getTestPlanReportId());
testPlanLog.info("ReportId["+testPlanReportData.getTestPlanReportId()+"] COUNT OVER. COUNT RESULT :"+JSONObject.toJSONString(testPlanExecuteResult));
testPlanLog.info("ReportId[" + testPlanReportData.getTestPlanReportId() + "] COUNT OVER. COUNT RESULT :" + JSONObject.toJSONString(testPlanExecuteResult));
TestCaseReportMetricDTO testCaseReportMetricDTO = this.countReportData(testPlan, testPlanExecuteResult);
@ -897,7 +897,7 @@ public class TestPlanReportService {
}
}
if (failurCaseObject.containsKey("scenarioTestCases") && failurCaseObject.getJSONArray("scenarioTestCases").size() >= 0) {
JSONArray array = failurCaseObject.getJSONArray("scenarioTestCases");
JSONArray array = failurCaseObject.getJSONArray("scenarioTestCases");
if (array.size() > 0) {
status = TestPlanReportStatus.FAILED.name();
return status;
@ -1004,7 +1004,7 @@ public class TestPlanReportService {
*
* @param testPlanReport
*/
public void updatePerformanceInfo(TestPlanReport testPlanReport, Map<String,String> performaneReportIDMap, String triggerMode) {
public void updatePerformanceInfo(TestPlanReport testPlanReport, Map<String, String> performaneReportIDMap, String triggerMode) {
/**
* 虽然kafka已经设置了topic推送但是当执行机器性能不够时会影响到报告状态当修改
@ -1017,17 +1017,17 @@ public class TestPlanReportService {
List<String> performaneReportIDList = new ArrayList<>(performaneReportIDMap.keySet());
while (performaneReportIDList.size() > 0) {
List<String> selectList = new ArrayList<>(performaneReportIDList);
testPlanLog.info("TestPlanReportId["+testPlanReport.getId()+"] SELECT performance BATCH START:"+JSONArray.toJSONString(selectList));
testPlanLog.info("TestPlanReportId[" + testPlanReport.getId() + "] SELECT performance BATCH START:" + JSONArray.toJSONString(selectList));
for (String loadTestReportId : selectList) {
try{
try {
LoadTestReportWithBLOBs loadTestReportFromDatabase = loadTestReportMapper.selectByPrimaryKey(loadTestReportId);
if (loadTestReportFromDatabase == null) {
testPlanLog.info("TestPlanReportId["+testPlanReport.getId()+"] SELECT performance ID:"+loadTestReportId+",RESULT IS NULL");
testPlanLog.info("TestPlanReportId[" + testPlanReport.getId() + "] SELECT performance ID:" + loadTestReportId + ",RESULT IS NULL");
//检查错误数据
if (errorDataCheckMap.containsKey(loadTestReportId)) {
if (errorDataCheckMap.get(loadTestReportId) > 10) {
performaneReportIDList.remove(loadTestReportId);
if(performaneReportIDMap.containsKey(loadTestReportId)){
if (performaneReportIDMap.containsKey(loadTestReportId)) {
finishLoadTestId.put(performaneReportIDMap.get(loadTestReportId), TestPlanApiExecuteStatus.FAILD.name());
}
} else {
@ -1036,23 +1036,23 @@ public class TestPlanReportService {
} else {
errorDataCheckMap.put(loadTestReportId, 1);
}
} else{
testPlanLog.info("TestPlanReportId["+testPlanReport.getId()+"] SELECT performance ID:"+loadTestReportId+",RESULT :"+loadTestReportFromDatabase.getStatus());
} else {
testPlanLog.info("TestPlanReportId[" + testPlanReport.getId() + "] SELECT performance ID:" + loadTestReportId + ",RESULT :" + loadTestReportFromDatabase.getStatus());
if (StringUtils.equalsAny(loadTestReportFromDatabase.getStatus(),
PerformanceTestStatus.Completed.name(), PerformanceTestStatus.Error.name())) {
finishLoadTestId.put(loadTestReportFromDatabase.getTestId(), TestPlanApiExecuteStatus.SUCCESS.name());
performaneReportIDList.remove(loadTestReportId);
}
}
}catch (Exception e){
} catch (Exception e) {
performaneReportIDList.remove(loadTestReportId);
finishLoadTestId.put(performaneReportIDMap.get(loadTestReportId), TestPlanApiExecuteStatus.FAILD.name());
testPlanLog.error(e.getMessage());
}
}
testPlanLog.info("TestPlanReportId["+testPlanReport.getId()+"] SELECT performance BATCH OVER:"+JSONArray.toJSONString(selectList));
testPlanLog.info("TestPlanReportId[" + testPlanReport.getId() + "] SELECT performance BATCH OVER:" + JSONArray.toJSONString(selectList));
if (performaneReportIDList.isEmpty()) {
testPlanLog.info("TestPlanReportId["+testPlanReport.getId()+"] performance EXECUTE OVER. TRIGGER_MODE:"+triggerMode+",REsult:"+JSONObject.toJSONString(finishLoadTestId));
testPlanLog.info("TestPlanReportId[" + testPlanReport.getId() + "] performance EXECUTE OVER. TRIGGER_MODE:" + triggerMode + ",REsult:" + JSONObject.toJSONString(finishLoadTestId));
if (StringUtils.equals(triggerMode, ReportTriggerMode.API.name())) {
for (String string : finishLoadTestId.keySet()) {
TestPlanLoadCaseEventDTO eventDTO = new TestPlanLoadCaseEventDTO();
@ -1096,12 +1096,18 @@ public class TestPlanReportService {
}
}
public List<TestPlanReport> getReports(List<String> ids) {
TestPlanReportExample example = new TestPlanReportExample();
example.createCriteria().andIdIn(ids);
return testPlanReportMapper.selectByExample(example);
}
public void delete(QueryTestPlanReportRequest request) {
List<String> deleteReportIds = request.getDataIds();
if (request.isSelectAllDate()) {
deleteReportIds = this.getAllApiIdsByFontedSelect(request.getFilters(), request.getName(), request.getProjectId(), request.getUnSelectIds());
}
if(CollectionUtils.isNotEmpty(deleteReportIds)){
if (CollectionUtils.isNotEmpty(deleteReportIds)) {
TestPlanReportExample deleteReportExample = new TestPlanReportExample();
deleteReportExample.createCriteria().andIdIn(deleteReportIds);
testPlanReportMapper.deleteByExample(deleteReportExample);
@ -1147,71 +1153,72 @@ public class TestPlanReportService {
public synchronized TestPlanReport updateExecuteApis(String planReportId, Map<String, String> executeApiCaseIdMap, Map<String, String> executeScenarioCaseIdMap, Map<String, String> executePerformanceIdMap) {
TestPlanReportDataExample example = new TestPlanReportDataExample();
// List<String> resourceIdList = new ArrayList<>();
if(executeApiCaseIdMap == null){
if (executeApiCaseIdMap == null) {
executeApiCaseIdMap = new HashMap<>();
}
if(executeScenarioCaseIdMap == null){
if (executeScenarioCaseIdMap == null) {
executeScenarioCaseIdMap = new HashMap<>();
}
if(executePerformanceIdMap == null){
if (executePerformanceIdMap == null) {
executePerformanceIdMap = new HashMap<>();
}
boolean updateTime = MapUtils.isNotEmpty(executeApiCaseIdMap)||MapUtils.isNotEmpty(executeScenarioCaseIdMap)||MapUtils.isNotEmpty(executePerformanceIdMap);
boolean updateTime = MapUtils.isNotEmpty(executeApiCaseIdMap) || MapUtils.isNotEmpty(executeScenarioCaseIdMap) || MapUtils.isNotEmpty(executePerformanceIdMap);
testPlanLog.info("ReportId["+planReportId+"] Executed. api :"+JSONObject.toJSONString(executeApiCaseIdMap)+"; scenario:"+JSONObject.toJSONString(executeScenarioCaseIdMap)+"; performance:"+JSONObject.toJSONString(executePerformanceIdMap));
testPlanLog.info("ReportId[" + planReportId + "] Executed. api :" + JSONObject.toJSONString(executeApiCaseIdMap) + "; scenario:" + JSONObject.toJSONString(executeScenarioCaseIdMap) + "; performance:" + JSONObject.toJSONString(executePerformanceIdMap));
example.createCriteria().andTestPlanReportIdEqualTo(planReportId);
List<TestPlanReportDataWithBLOBs> reportDataList = testPlanReportDataMapper.selectByExampleWithBLOBs(example);
TestPlanReport report = null;
if (!reportDataList.isEmpty()) {
Map<String,List<String>> batchUpdateMap = new HashMap<>();
for (Map.Entry<String, String> entry:executeApiCaseIdMap.entrySet()){
Map<String, List<String>> batchUpdateMap = new HashMap<>();
for (Map.Entry<String, String> entry : executeApiCaseIdMap.entrySet()) {
String id = entry.getKey();
String result = entry.getValue();
if(batchUpdateMap.containsKey(result)){
if (batchUpdateMap.containsKey(result)) {
batchUpdateMap.get(result).add(id);
}else {
} else {
List<String> idList = new ArrayList<>();
idList.add(id);
batchUpdateMap.put(result,idList);
batchUpdateMap.put(result, idList);
}
}
for (Map.Entry<String, String> entry:executeScenarioCaseIdMap.entrySet()){
for (Map.Entry<String, String> entry : executeScenarioCaseIdMap.entrySet()) {
String id = entry.getKey();
String result = entry.getValue();
if(batchUpdateMap.containsKey(result)){
if (batchUpdateMap.containsKey(result)) {
batchUpdateMap.get(result).add(id);
}else {
} else {
List<String> idList = new ArrayList<>();
idList.add(id);
batchUpdateMap.put(result,idList);
batchUpdateMap.put(result, idList);
}
}
for (Map.Entry<String, String> entry:executePerformanceIdMap.entrySet()){
for (Map.Entry<String, String> entry : executePerformanceIdMap.entrySet()) {
String id = entry.getKey();
String result = entry.getValue();
if(batchUpdateMap.containsKey(result)){
if (batchUpdateMap.containsKey(result)) {
batchUpdateMap.get(result).add(id);
}else {
} else {
List<String> idList = new ArrayList<>();
idList.add(id);
batchUpdateMap.put(result,idList);
batchUpdateMap.put(result, idList);
}
}
for(Map.Entry<String,List<String>> entry : batchUpdateMap.entrySet()){
for (Map.Entry<String, List<String>> entry : batchUpdateMap.entrySet()) {
String status = entry.getKey();
List<String> ids = entry.getValue();
if(CollectionUtils.isEmpty(ids)){
if (CollectionUtils.isEmpty(ids)) {
continue;
}
int updateCount = this.testPlanReportResourceService.updateExecuteResultByReportIdAndResourceIds(status,planReportId,ids);
testPlanLog.info("ReportId["+planReportId+"] Update Execute Result. Update datas count is :["+updateCount+"]; Update Status:["+status+"],Update ids :["+JSONArray.toJSONString(ids)+"] ");
int updateCount = this.testPlanReportResourceService.updateExecuteResultByReportIdAndResourceIds(status, planReportId, ids);
testPlanLog.info("ReportId[" + planReportId + "] Update Execute Result. Update datas count is :[" + updateCount + "]; Update Status:[" + status + "],Update ids :[" + JSONArray.toJSONString(ids) + "] ");
}
boolean apiCaseExecuteOk = testPlanReportResourceService.countByReportIdAndResourceTypeAndExecuteResultEquals(planReportId,TestPlanResourceType.API_CASE.name(),TestPlanApiExecuteStatus.RUNNING.name()) == 0;
boolean scenarioExecuteOk = testPlanReportResourceService.countByReportIdAndResourceTypeAndExecuteResultEquals(planReportId,TestPlanResourceType.SCENARIO_CASE.name(),TestPlanApiExecuteStatus.RUNNING.name()) == 0;
boolean performanceExecuteOk = testPlanReportResourceService.countByReportIdAndResourceTypeAndExecuteResultEquals(planReportId,TestPlanResourceType.PERFORMANCE_CASE.name(),TestPlanApiExecuteStatus.RUNNING.name()) == 0;;
boolean apiCaseExecuteOk = testPlanReportResourceService.countByReportIdAndResourceTypeAndExecuteResultEquals(planReportId, TestPlanResourceType.API_CASE.name(), TestPlanApiExecuteStatus.RUNNING.name()) == 0;
boolean scenarioExecuteOk = testPlanReportResourceService.countByReportIdAndResourceTypeAndExecuteResultEquals(planReportId, TestPlanResourceType.SCENARIO_CASE.name(), TestPlanApiExecuteStatus.RUNNING.name()) == 0;
boolean performanceExecuteOk = testPlanReportResourceService.countByReportIdAndResourceTypeAndExecuteResultEquals(planReportId, TestPlanResourceType.PERFORMANCE_CASE.name(), TestPlanApiExecuteStatus.RUNNING.name()) == 0;
;
testPlanLog.info("ReportId["+planReportId+"] count over. Testplan Execute Result: Api is over ->"+apiCaseExecuteOk+"; scenario is over ->"+scenarioExecuteOk+"; performance is over ->"+performanceExecuteOk);
testPlanLog.info("ReportId[" + planReportId + "] count over. Testplan Execute Result: Api is over ->" + apiCaseExecuteOk + "; scenario is over ->" + scenarioExecuteOk + "; performance is over ->" + performanceExecuteOk);
TestPlanReportDataWithBLOBs reportData = reportDataList.get(0);
@ -1223,9 +1230,9 @@ public class TestPlanReportService {
// sqlSession.flushStatements();
report = this.updateReport(reportData, apiCaseExecuteOk, scenarioExecuteOk, performanceExecuteOk,updateTime);
}else {
testPlanLog.info("ReportId["+planReportId+"] CANNOT FIND REPORT! Execited result. api :"+JSONObject.toJSONString(executeApiCaseIdMap)+"; scenario:"+JSONObject.toJSONString(executeScenarioCaseIdMap)+"; performance:"+JSONObject.toJSONString(executePerformanceIdMap));
report = this.updateReport(reportData, apiCaseExecuteOk, scenarioExecuteOk, performanceExecuteOk, updateTime);
} else {
testPlanLog.info("ReportId[" + planReportId + "] CANNOT FIND REPORT! Execited result. api :" + JSONObject.toJSONString(executeApiCaseIdMap) + "; scenario:" + JSONObject.toJSONString(executeScenarioCaseIdMap) + "; performance:" + JSONObject.toJSONString(executePerformanceIdMap));
}
return report;

View File

@ -162,7 +162,7 @@ public class TestPlanService {
@Resource
private IssueTemplateService issueTemplateService;
public synchronized String addTestPlan(AddTestPlanRequest testPlan) {
public synchronized TestPlan addTestPlan(AddTestPlanRequest testPlan) {
if (getTestPlanByName(testPlan.getName()).size() > 0) {
MSException.throwException(Translator.get("plan_name_already_exists"));
}
@ -175,22 +175,7 @@ public class TestPlanService {
}
testPlanMapper.insert(testPlan);
List<String> userIds = new ArrayList<>();
userIds.add(testPlan.getPrincipal());
String context = getTestPlanContext(testPlan, NoticeConstants.Event.CREATE);
User user = userMapper.selectByPrimaryKey(testPlan.getCreator());
Map<String, Object> paramMap = getTestPlanParamMap(testPlan);
paramMap.put("creator", user.getName());
NoticeModel noticeModel = NoticeModel.builder()
.context(context)
.relatedUsers(userIds)
.subject(Translator.get("test_plan_notification"))
.mailTemplate("TestPlanStart")
.paramMap(paramMap)
.event(NoticeConstants.Event.CREATE)
.build();
noticeSendService.send(NoticeConstants.TaskType.TEST_PLAN_TASK, noticeModel);
return testPlan.getId();
return testPlan;
}
public List<TestPlan> getTestPlanByName(String name) {
@ -205,7 +190,7 @@ public class TestPlanService {
return Optional.ofNullable(testPlanMapper.selectByPrimaryKey(testPlanId)).orElse(new TestPlanWithBLOBs());
}
public String editTestPlan(TestPlanDTO testPlan, Boolean isSendMessage) {
public TestPlan editTestPlan(TestPlanDTO testPlan) {
checkTestPlanExist(testPlan);
TestPlan res = testPlanMapper.selectByPrimaryKey(testPlan.getId()); // 先查一次库
testPlan.setUpdateTime(System.currentTimeMillis());
@ -232,9 +217,7 @@ public class TestPlanService {
} // 非已结束->已结束更新结束时间
}
List<String> userIds = new ArrayList<>();
userIds.add(testPlan.getPrincipal());
AddTestPlanRequest testPlans = new AddTestPlanRequest();
int i;
if (testPlan.getName() == null) {// 若是点击该测试计划则仅更新了updateTime其它字段全为null使用updateByPrimaryKeySelective
i = testPlanMapper.updateByPrimaryKeySelective(testPlan);
@ -242,23 +225,8 @@ public class TestPlanService {
extScheduleMapper.updateNameByResourceID(testPlan.getId(), testPlan.getName());// 同步更新该测试的定时任务的name
i = testPlanMapper.updateByPrimaryKeyWithBLOBs(testPlan); // 更新
}
if (!StringUtils.isBlank(testPlan.getStatus()) && isSendMessage) {
BeanUtils.copyBean(testPlans, getTestPlan(testPlan.getId()));
String context = getTestPlanContext(testPlans, NoticeConstants.Event.UPDATE);
User user = userMapper.selectByPrimaryKey(testPlans.getCreator());
Map<String, Object> paramMap = getTestPlanParamMap(testPlans);
paramMap.put("creator", user.getName());
NoticeModel noticeModel = NoticeModel.builder()
.context(context)
.relatedUsers(userIds)
.subject(Translator.get("test_plan_notification"))
.mailTemplate("TestPlanEnd")
.paramMap(paramMap)
.event(NoticeConstants.Event.UPDATE)
.build();
noticeSendService.send(NoticeConstants.TaskType.TEST_PLAN_TASK, noticeModel);
}
return testPlan.getId();
return testPlan;
}
//计划内容
@ -313,7 +281,6 @@ public class TestPlanService {
}
public int deleteTestPlan(String planId) {
TestPlan testPlan = getTestPlan(planId);
deleteTestCaseByPlanId(planId);
testPlanApiCaseService.deleteByPlanId(planId);
testPlanScenarioCaseService.deleteByPlanId(planId);
@ -322,29 +289,7 @@ public class TestPlanService {
//删除定时任务
scheduleService.deleteByResourceId(planId, ScheduleGroup.TEST_PLAN_TEST.name());
int num = testPlanMapper.deleteByPrimaryKey(planId);
List<String> relatedUsers = new ArrayList<>();
AddTestPlanRequest testPlans = new AddTestPlanRequest();
relatedUsers.add(testPlan.getCreator());
try {
BeanUtils.copyBean(testPlans, testPlan);
String context = getTestPlanContext(testPlans, NoticeConstants.Event.DELETE);
User user = userMapper.selectByPrimaryKey(testPlan.getCreator());
Map<String, Object> paramMap = getTestPlanParamMap(testPlan);
paramMap.put("creator", user.getName());
NoticeModel noticeModel = NoticeModel.builder()
.context(context)
.relatedUsers(relatedUsers)
.subject(Translator.get("test_plan_notification"))
.mailTemplate("TestPlanDelete")
.paramMap(paramMap)
.event(NoticeConstants.Event.DELETE)
.build();
noticeSendService.send(NoticeConstants.TaskType.TEST_PLAN_TASK, noticeModel);
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
}
return num;
return testPlanMapper.deleteByPrimaryKey(planId);
}
public void deleteTestCaseByPlanId(String testPlanId) {
@ -432,7 +377,7 @@ public class TestPlanService {
testPlanDTO.setId(testPlanId);
if (statusList.size() == 0) { // 原先status不是prepare, 但删除所有关联用例的情况
testPlanDTO.setStatus(TestPlanStatus.Prepare.name());
editTestPlan(testPlanDTO, false);
editTestPlan(testPlanDTO);
return;
}
int passNum = 0, prepareNum = 0, failNum = 0;
@ -449,13 +394,13 @@ public class TestPlanService {
}
if (passNum == statusList.size()) { // 全部通过
testPlanDTO.setStatus(TestPlanStatus.Completed.name());
this.editTestPlan(testPlanDTO, false);
this.editTestPlan(testPlanDTO);
} else if (prepareNum == 0 && passNum + failNum == statusList.size()) { // 已结束
testPlanDTO.setStatus(TestPlanStatus.Finished.name());
editTestPlan(testPlanDTO, false);
editTestPlan(testPlanDTO);
} else if (prepareNum != 0) { // 进行中
testPlanDTO.setStatus(TestPlanStatus.Underway.name());
editTestPlan(testPlanDTO, false);
editTestPlan(testPlanDTO);
}
}
@ -669,12 +614,12 @@ public class TestPlanService {
String context = getTestPlanContext(_testPlans, NoticeConstants.Event.UPDATE);
User user = userMapper.selectByPrimaryKey(_testPlans.getCreator());
Map<String, Object> paramMap = getTestPlanParamMap(_testPlans);
paramMap.put("creator", user.getName());
paramMap.put("operator", user.getName());
NoticeModel noticeModel = NoticeModel.builder()
.context(context)
.relatedUsers(userIds)
.subject(Translator.get("test_plan_notification"))
.mailTemplate("TestPlanEnd")
.mailTemplate("track/TestPlanEnd")
.paramMap(paramMap)
.event(NoticeConstants.Event.UPDATE)
.build();

View File

@ -40,4 +40,13 @@ CREATE TABLE `load_test_report_result_realtime`
DEFAULT CHARSET = utf8mb4
COLLATE utf8mb4_general_ci;
ALTER TABLE api_definition
ADD follow_people VARCHAR(100) NULL;
ALTER TABLE load_test
ADD follow_people VARCHAR(100) NULL;
ALTER TABLE api_test_case
ADD follow_people VARCHAR(100) NULL;
ALTER TABLE test_plan ADD report_summary TEXT NULL COMMENT '测试计划报告总结';

View File

@ -78,7 +78,7 @@
<table tableName="test_plan"/>
<table tableName="test_case_test"/>-->
<!-- <table tableName="api_test_environment"></table>-->
<table tableName="load_test_report_result_realtime"/>
<table tableName="api_test_case"/>
<!-- <table tableName="custom_field"></table>-->
<!-- <table tableName="test_case"></table>-->
<!-- <table tableName="test_case"></table>-->

View File

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p style="text-align: left">${creator} 发起的用例评审:<br>
${reviewName}<br>
计划开始时间是:${start}<br>
计划结束时间为:${end}<br>
已删除<br>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}创建了接口自动化: ${name}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}删除了接口自动化: ${name}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}更新了接口自动化: ${name}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}创建了接口用例: ${name}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}删除了接口用例: ${name}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}更新了接口用例: ${name}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}创建了接口定义: ${name}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}删除了接口定义: ${name}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}更新了接口定义: ${name}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}更新了接口定义: ${name}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}关闭了定时任务: ${name}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}删除了性能测试报告: ${name}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}创建了性能测试: ${name}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}删除了性能测试: ${name}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}更新了性能测试: ${name}</p>
</div>
</body>
</html>

View File

@ -6,7 +6,7 @@
</head>
<body>
<div>
<p>${creator}发起了一个缺陷:${issuesName},请跟进</p>
<p>${operator}创建了缺陷: ${title}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}删除了缺陷: ${title}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}更新了缺陷: ${title}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}删除了报告: ${name}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p style="text-align: left">${operator}删除了用例评审:${name}</p>
</div>
</body>
</html>

View File

@ -6,11 +6,7 @@
</head>
<body>
<div>
<p style="text-align: left">${creator} 发起的:<br>
${reviewName}<br>
计划开始时间是:${start}<br>
计划结束时间为:${end}<br>
${status}<br>
<p style="text-align: left">${operator}更新了测试评审: ${name} <br>
点击下面链接进入用例评审页面</p>
<a href="${url}/#/track/review/view">${url}/#/track/review/view</a>
</div>

View File

@ -6,11 +6,7 @@
</head>
<body>
<div>
<p style="text-align: left">${creator} 发起的:<br>
${reviewName}待开始<br>
计划开始时间是:${start}<br>
计划结束时间为:${end}<br>
请跟进<br>
<p style="text-align: left">${operator}发起了测试评审:${name}<br>
点击下面链接进入评审页面进行审核</p>
<a href="${url}/#/track/review/view/${id}">${url}/#/track/review/view/${id}</a>
</div>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}关闭了定时任务: ${name}</p>
</div>
</body>
</html>

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p style="text-align: left">
${operator}评论了测试用例: ${name}
</p>
点击下面链接进入测试用例
<a href="${url}/#/track/case/all">${url}/#/track/case/all</a>
</div>
</body>
</html>

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p style="text-align: left">
${operator}创建了测试用例: ${name}
</p>
点击下面链接进入测试用例
<a href="${url}/#/track/case/all">${url}/#/track/case/all</a>
</div>
</body>
</html>

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p style="text-align: left">
${operator}删除了测试用例: ${name}
</p>
点击下面链接进入测试用例
<a href="${url}/#/track/case/all">${url}/#/track/case/all</a>
</div>
</body>
</html>

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p style="text-align: left">
${operator}修改了测试用例: ${name}
</p>
点击下面链接进入测试用例
<a href="${url}/#/track/case/all">${url}/#/track/case/all</a>
</div>
</body>
</html>

View File

@ -6,8 +6,8 @@
</head>
<body>
<div>
<p style="text-align: left">${creator} 创建的:<br>
${testPlanName}<br>
<p style="text-align: left">${creator}创建的:<br>
${name}<br>
计划开始时间是:${start}<br>
计划结束时间为:${end}<br>
已删除!

View File

@ -6,11 +6,7 @@
</head>
<body>
<div>
<p style="text-align: left">${creator} 创建的:<br>
${testPlanName}<br>
计划开始时间是:${start}<br>
计划结束时间为:${end}<br>
${status}<br>
<p style="text-align: left">${operator}更新了测试计划: ${name}<br>
点击下面链接进入测试计划页面</p>
<a href="${url}/#/track/plan/view/${id}">${url}/#/track/plan/view</a>
</div>

View File

@ -6,11 +6,7 @@
</head>
<body>
<div>
<p style="text-align: left">${creator} 创建的:<br>
${testPlanName}<br>
计划开始时间是:${start}<br>
计划结束时间为:${end}<br>
请跟进!<br>
<p style="text-align: left">${operator}创建了测试计划${name}<br>
点击下面链接进入测试计划页面</p>
<a href="${url}/#/track/plan/all">${url}/#/track/plan/all</a>
</div>

View File

@ -61,6 +61,7 @@
<el-col :span="7">
<el-form-item :label="$t('api_test.automation.follow_people')" prop="followPeople">
<el-select v-model="currentScenario.followPeople"
clearable
:placeholder="$t('api_test.automation.follow_people')" filterable size="small"
class="ms-scenario-input">
<el-option

View File

@ -20,7 +20,7 @@
</el-col>
</el-row>
</el-col>
<el-col :span="api.protocol==='HTTP'?6:10" v-loading="loading && !(apiCase.active||type==='detail')">
<el-col :span="api.protocol==='HTTP'?4:8" v-loading="loading && !(apiCase.active||type==='detail')">
<span @click.stop>
<i class="icon el-icon-arrow-right" :class="{'is-active': apiCase.active}" @click="active(apiCase)"/>
<el-input v-if="!apiCase.id || isShowInput" size="small" v-model="apiCase.name" :name="index" :key="index"
@ -61,6 +61,22 @@
</div>
</el-col>
<el-col :span="3">
<div class="tag-item" @click.stop>
<el-select v-model="apiCase.followPeople"
clearable
:placeholder="$t('api_test.automation.follow_people')" filterable size="small"
@change="saveTestCase(apiCase)">
<el-option
v-for="item in maintainerOptions"
:key="item.id"
:label="item.id + ' (' + item.name + ')'"
:value="item.id">
</el-option>
</el-select>
</div>
</el-col>
<el-col :span="3">
<span @click.stop>
<ms-tip-button @click="singleRun(apiCase)" :tip="$t('api_test.run')" icon="el-icon-video-play"
@ -80,7 +96,7 @@
</span>
</el-col>
<el-col :span="3">
<el-col :span="2">
<el-link @click.stop type="danger" v-if="apiCase.execResult && apiCase.execResult==='error'" @click="showExecResult(apiCase)">
{{ getResult(apiCase.execResult) }}
</el-link>
@ -204,6 +220,7 @@ export default {
{name: this.$t('test_track.case.batch_edit_case'), handleClick: this.handleEditBatch}
],
methodColorMap: new Map(API_METHOD_COLOUR),
maintainerOptions: [],
}
},
props: {
@ -241,6 +258,7 @@ export default {
if (requireComponent != null && JSON.stringify(esbDefinition) != '{}' && JSON.stringify(esbDefinitionResponse) != '{}') {
this.showXpackCompnent = true;
}
this.getMaintainerOptions();
},
watch: {
'apiCase.selected'() {
@ -248,6 +266,11 @@ export default {
}
},
methods: {
getMaintainerOptions() {
this.$post('/user/project/member/tester/list', {projectId: getCurrentProjectID()}, response => {
this.maintainerOptions = response.data;
});
},
openHis(row) {
this.$refs.changeHistory.open(row.id);
},

View File

@ -40,12 +40,27 @@
</el-row>
<el-row>
<el-col :span="12">
<el-col :span="8">
<el-form-item :label="$t('commons.tag')" prop="tag">
<ms-input-tag :currentScenario="basicForm" ref="tag"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-col :span="8">
<el-form-item :label="$t('api_test.automation.follow_people')" prop="followPeople">
<el-select v-model="basicForm.followPeople"
clearable
:placeholder="$t('api_test.automation.follow_people')" filterable size="small"
class="ms-http-textarea">
<el-option
v-for="item in maintainerOptions"
:key="item.id"
:label="item.id + ' (' + item.name + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea"
v-model="basicForm.description"
@ -136,4 +151,7 @@
</script>
<style scoped>
.ms-http-textarea {
width: 100%;
}
</style>

View File

@ -68,7 +68,22 @@
<ms-input-tag :currentScenario="httpForm" ref="tag"/>
</el-form-item>
</el-col>
<el-col :span="16">
<el-col :span="7">
<el-form-item :label="$t('api_test.automation.follow_people')" prop="followPeople">
<el-select v-model="httpForm.followPeople"
clearable
:placeholder="$t('api_test.automation.follow_people')" filterable size="small"
class="ms-http-textarea">
<el-option
v-for="item in maintainerOptions"
:key="item.id"
:label="item.id + ' (' + item.name + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea"
v-model="httpForm.description"

View File

@ -47,12 +47,27 @@
</el-row>
<el-row>
<el-col :span="12">
<el-col :span="8">
<el-form-item :label="$t('commons.tag')" prop="tag">
<ms-input-tag :currentScenario="basicForm" ref="tag"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-col :span="8">
<el-form-item :label="$t('api_test.automation.follow_people')" prop="followPeople">
<el-select v-model="basicForm.followPeople"
clearable
:placeholder="$t('api_test.automation.follow_people')" filterable size="small"
class="ms-http-textarea">
<el-option
v-for="item in maintainerOptions"
:key="item.id"
:label="item.id + ' (' + item.name + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea"
v-model="basicForm.description"
@ -151,4 +166,7 @@
</script>
<style scoped>
.ms-http-textarea {
width: 100%;
}
</style>

View File

@ -168,7 +168,7 @@ export default {
this.search();
},
handleStatus(scope) {
console.log(scope.row.userId)
// console.log(scope.row.userId)
}
}
</script>

View File

@ -3,16 +3,34 @@
<ms-main-container>
<el-card v-loading="result.loading">
<el-row>
<el-col :span="10">
<el-input :disabled="isReadOnly" :placeholder="$t('load_test.input_name')" v-model="test.name"
class="input-with-select"
size="small"
maxlength="30" show-word-limit
>
<template slot="prepend">{{ $t('load_test.name') }}</template>
</el-input>
<el-col :span="6">
<el-form :inline="true">
<el-form-item :label="$t('load_test.name') ">
<el-input :disabled="isReadOnly" :placeholder="$t('load_test.input_name')" v-model="test.name"
class="input-with-select"
size="small"
maxlength="30" show-word-limit/>
</el-form-item>
</el-form>
</el-col>
<el-col :span="12" :offset="2">
<el-col :span="6">
<el-form>
<el-form-item :label="$t('api_test.automation.follow_people')">
<el-select v-model="test.followPeople"
clearable
:placeholder="$t('api_test.automation.follow_people')" filterable size="small">
<el-option
v-for="item in maintainerOptions"
:key="item.id"
:label="item.id + ' (' + item.name + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-form>
</el-col>
<el-col :span="12">
<el-link type="primary" size="small" style="margin-right: 20px" @click="openHis" v-if="test.id">
{{ $t('operating_log.change_history') }}
</el-link>
@ -43,8 +61,7 @@
</el-col>
</el-row>
<el-tabs class="testplan-config" v-model="active" @tab-click="clickTab">
<el-tabs v-model="active" @tab-click="clickTab">
<el-tab-pane :label="$t('load_test.basic_config')" class="advanced-config">
<performance-basic-config :is-read-only="isReadOnly" :test="test" ref="basicConfig"
@tgTypeChange="tgTypeChange"
@ -118,7 +135,8 @@ export default {
title: this.$t('load_test.advanced_config'),
id: '2',
component: 'PerformanceAdvancedConfig'
}]
}],
maintainerOptions: [],
};
},
watch: {
@ -144,8 +162,14 @@ export default {
},
mounted() {
this.importAPITest();
this.getMaintainerOptions();
},
methods: {
getMaintainerOptions() {
this.$post('/user/project/member/tester/list', {projectId: getCurrentProjectID()}, response => {
this.maintainerOptions = response.data;
});
},
openHis() {
this.$refs.changeHistory.open(this.test.id);
},
@ -158,7 +182,7 @@ export default {
this.$refs.basicConfig.handleUpload();
let relateApiList = [];
relateApiList.push({
apiId : apiTest.jmx.scenarioId,
apiId: apiTest.jmx.scenarioId,
apiVersion: apiTest.jmx.version,
type: 'SCENARIO'
});
@ -168,7 +192,7 @@ export default {
this.$refs.basicConfig.importCase(apiTest.jmx);
let relateApiList = [];
relateApiList.push({
apiId : apiTest.jmx.caseId,
apiId: apiTest.jmx.caseId,
apiVersion: apiTest.jmx.version,
envId: apiTest.jmx.envId,
type: 'API_CASE'
@ -197,7 +221,7 @@ export default {
this.$refs.basicConfig.importScenario(item.scenarioId);
this.$refs.basicConfig.handleUpload();
relateApiList.push({
apiId : item.scenarioId,
apiId: item.scenarioId,
apiVersion: item.version,
type: 'SCENARIO'
});
@ -440,9 +464,6 @@ export default {
<style scoped>
.testplan-config {
margin-top: 5px;
}
.el-select {
min-width: 130px;

View File

@ -1,38 +1,110 @@
<template>
<div>
<el-alert
title="Notice:"
type="info"
show-icon>
<div v-loading="result.loading">
<el-alert :closable="false"
type="info">
<template v-slot:default>
{{ $t('organization.message.notes') }}
<span v-html="$t('organization.message.notes')"></span>
</template>
</el-alert>
<jenkins-notification :jenkins-receiver-options="jenkinsReceiverOptions"/>
<test-plan-task-notification :test-plan-receiver-options="testPlanReceiverOptions"/>
<test-review-notification :review-receiver-options="reviewReceiverOptions"/>
<defect-task-notification :defect-receiver-options="defectReceiverOptions"/>
<div style="padding-top: 10px;"></div>
<el-collapse accordion class="task-notification">
<el-collapse-item name="2">
<template v-slot:title>
<span style="width: 200px">
测试跟踪任务通知
</span>
<span>通知数: <span style="color: #783887;">{{ trackNoticeSize }}</span></span>
</template>
<track-home-notification @noticeSize="getNoticeSize" :receiver-options="reviewReceiverOptions"/>
<test-case-notification @noticeSize="getNoticeSize" :receiver-options="reviewReceiverOptions"/>
<test-review-notification @noticeSize="getNoticeSize" :review-receiver-options="reviewReceiverOptions"/>
<test-plan-task-notification @noticeSize="getNoticeSize" :test-plan-receiver-options="testPlanReceiverOptions"/>
<defect-task-notification @noticeSize="getNoticeSize" :defect-receiver-options="defectReceiverOptions"/>
<track-report-notification @noticeSize="getNoticeSize" :receiver-options="reviewReceiverOptions"/>
</el-collapse-item>
<el-collapse-item name="3">
<template v-slot:title>
<span style="width: 200px">
接口测试任务通知
</span>
<span>通知数: <span style="color: #783887;">{{ apiNoticeSize }}</span></span>
</template>
<api-home-notification @noticeSize="getNoticeSize" :receiver-options="reviewReceiverOptions"/>
<api-definition-notification @noticeSize="getNoticeSize" :receiver-options="reviewReceiverOptions"/>
<api-automation-notification @noticeSize="getNoticeSize" :receiver-options="reviewReceiverOptions"/>
<api-report-notification @noticeSize="getNoticeSize" :receiver-options="reviewReceiverOptions"/>
</el-collapse-item>
<el-collapse-item name="4">
<template v-slot:title>
<span style="width: 200px">
性能测试任务通知
</span>
<span>通知数: <span style="color: #783887;">{{ performanceNoticeSize }}</span></span>
</template>
<performance-test-notification @noticeSize="getNoticeSize" :receiver-options="reviewReceiverOptions"/>
<performance-report-notification @noticeSize="getNoticeSize" :receiver-options="reviewReceiverOptions"/>
</el-collapse-item>
<el-collapse-item name="1">
<template v-slot:title>
<span style="width: 200px">{{ $t('organization.message.jenkins_task_notification') }}</span>
<span>通知数: <span style="color: #783887;">{{ jenkinsNoticeSize }}</span></span>
</template>
<jenkins-notification @noticeSize="getNoticeSize" :jenkins-receiver-options="jenkinsReceiverOptions"/>
</el-collapse-item>
</el-collapse>
</div>
</template>
<script>
import {getCurrentOrganizationId, getCurrentUser} from "@/common/js/utils";
import JenkinsNotification from "@/business/components/settings/organization/components/JenkinsNotification";
import TestPlanTaskNotification from "@/business/components/settings/organization/components/TestPlanTaskNotification";
import TestReviewNotification from "@/business/components/settings/organization/components/TestReviewNotification";
import DefectTaskNotification from "@/business/components/settings/organization/components/DefectTaskNotification";
import JenkinsNotification from "@/business/components/settings/organization/components/jenkins/JenkinsNotification";
import TestPlanTaskNotification
from "@/business/components/settings/organization/components/track/TestPlanTaskNotification";
import TestReviewNotification
from "@/business/components/settings/organization/components/track/TestReviewNotification";
import DefectTaskNotification
from "@/business/components/settings/organization/components/track/DefectTaskNotification";
import MsContainer from "@/business/components/common/components/MsContainer";
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
import HomeNotification from "@/business/components/settings/organization/components/track/TrackHomeNotification";
import TrackHomeNotification from "@/business/components/settings/organization/components/track/TrackHomeNotification";
import TestCaseNotification from "@/business/components/settings/organization/components/track/TestCaseNotification";
import TrackReportNotification
from "@/business/components/settings/organization/components/track/TrackReportNotification";
import ApiDefinitionNotification
from "@/business/components/settings/organization/components/api/ApiDefinitionNotification";
import ApiAutomationNotification
from "@/business/components/settings/organization/components/api/ApiAutomationNotification";
import ApiReportNotification from "@/business/components/settings/organization/components/api/ApiReportNotification";
import PerformanceTestNotification
from "@/business/components/settings/organization/components/performance/PerformanceTestNotification";
import PerformanceReportNotification
from "@/business/components/settings/organization/components/performance/PerformanceReportNotification";
import ApiHomeNotification from "@/business/components/settings/organization/components/api/ApiHomeNotification";
export default {
name: "TaskNotification",
components: {
ApiHomeNotification,
PerformanceReportNotification,
PerformanceTestNotification,
ApiReportNotification,
ApiAutomationNotification,
ApiDefinitionNotification,
TrackReportNotification,
TestCaseNotification,
TrackHomeNotification,
HomeNotification,
DefectTaskNotification, TestReviewNotification, TestPlanTaskNotification, JenkinsNotification, MsContainer,
MsMainContainer,
},
data() {
return {
jenkinsNoticeSize: 0,
apiNoticeSize: 0,
performanceNoticeSize: 0,
trackNoticeSize: 0,
jenkinsReceiverOptions: [],
//
testPlanReceiverOptions: [],
@ -40,7 +112,8 @@ export default {
reviewReceiverOptions: [],
//
defectReceiverOptions: [],
}
result: {}
};
},
activated() {
@ -50,7 +123,7 @@ export default {
handleEdit(index, data) {
data.isReadOnly = true;
if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly
data.isReadOnly = !data.isReadOnly;
}
},
currentUser: () => {
@ -63,16 +136,38 @@ export default {
organizationId: getCurrentOrganizationId()
};
this.result = this.$post('user/org/member/list/all', param, response => {
this.jenkinsReceiverOptions = response.data
this.reviewReceiverOptions = response.data
this.defectReceiverOptions = response.data
this.testPlanReceiverOptions = response.data
this.jenkinsReceiverOptions = response.data;
this.reviewReceiverOptions = response.data;
this.defectReceiverOptions = response.data;
this.testPlanReceiverOptions = response.data;
});
},
getNoticeSize(config) {
switch (config.taskType) {
case 'jenkins':
this.jenkinsNoticeSize += config.size;
break;
case 'performance':
this.performanceNoticeSize += config.size;
break;
case 'api':
this.apiNoticeSize += config.size;
break;
case 'track':
this.trackNoticeSize += config.size;
break;
default:
break;
}
return 0;
}
}
}
};
</script>
<style scoped>
.task-notification {
height: calc(100vh - 200px);
overflow: auto;
}
</style>

View File

@ -2,8 +2,9 @@
<div>
<el-row>
<el-col :span="10">
<h3>{{ $t('organization.message.test_review_task_notice') }}</h3>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel" v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
<h5>接口自动化</h5>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
{{ $t('organization.message.create_new_notification') }}
</el-button>
<el-popover
@ -19,8 +20,9 @@
<el-popover
placement="right-end"
title="示例"
width="600"
trigger="click">
width="400"
trigger="click"
:content="robotTitle">
<ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }}
@ -31,7 +33,7 @@
<el-row>
<el-col :span="24">
<el-table
:data="reviewTask"
:data="defectTask"
class="tb-edit"
border
:cell-style="rowClass"
@ -40,10 +42,10 @@
<el-table-column :label="$t('schedule.event')" min-width="15%" prop="events">
<template slot-scope="scope">
<el-select v-model="scope.row.event" :placeholder="$t('organization.message.select_events')" size="mini"
@change="handleReviewReceivers(scope.row)"
@change="handleReceivers(scope.row)"
prop="event" :disabled="!scope.row.isSet">
<el-option
v-for="item in reviewTaskEventOptions"
v-for="item in eventOptions"
:key="item.value"
:label="item.label"
:value="item.value">
@ -57,7 +59,7 @@
:placeholder="$t('commons.please_select')"
style="width: 100%;" :disabled="!row.isSet">
<el-option
v-for="item in row.reviewReceiverOptions"
v-for="item in row.receiverOptions"
:key="item.id"
:label="item.name"
:value="item.id">
@ -87,43 +89,49 @@
</el-table-column>
<el-table-column :label="$t('commons.operating')" min-width="25%" prop="result">
<template v-slot:default="scope">
<el-button
<ms-tip-button
circle
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
:tip="$t('organization.message.template')"
icon="el-icon-tickets"/>
<ms-tip-button
circle
type="primary"
size="mini"
v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)"
>{{ $t('commons.add') }}
</el-button>
<el-button
:tip="$t('commons.add')"
icon="el-icon-check"/>
<ms-tip-button
circle
size="mini"
v-show="scope.row.isSet"
@click.native.prevent="removeRowTask(scope.$index,reviewTask)"
>{{ $t('commons.cancel') }}
</el-button>
<el-button
@click="removeRowTask(scope.$index,defectTask)"
:tip="$t('commons.cancel')"
icon="el-icon-refresh-left"/>
<ms-tip-button
el-button
circle
type="primary"
size="mini"
icon="el-icon-edit"
v-show="!scope.row.isSet"
:tip="$t('commons.edit')"
@click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"
>{{ $t('commons.edit') }}
</el-button>
<el-button
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
<ms-tip-button
circle
type="danger"
icon="el-icon-delete"
size="mini"
v-show="!scope.row.isSet"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"
@click.native.prevent="deleteRowTask(scope.$index,scope.row)"
></el-button>
@click="deleteRowTask(scope.$index,scope.row)"
:tip="$t('commons.delete')"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</template>
</el-table-column>
</el-table>
@ -136,19 +144,21 @@
<script>
import {hasLicense} from "@/common/js/utils";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import MsTipButton from "@/business/components/common/components/MsTipButton";
const TASK_TYPE = 'REVIEW_TASK';
const TASK_TYPE = 'API_AUTOMATION_TASK';
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
export default {
name: "TestReviewNotification",
name: "ApiAutomationNotification",
components: {
MsTipButton,
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default
},
props: {
reviewReceiverOptions: {
receiverOptions: {
type: Array
}
},
@ -163,20 +173,13 @@ export default {
"</head>\n" +
"<body>\n" +
"<div>\n" +
" <p style=\"text-align: left\">${creator} 创建的:<br>\n" +
" ${reviewName}待开始<br>\n" +
" 计划开始时间是:${start}<br>\n" +
" 计划结束时间为:${end}<br>\n" +
" 请跟进!/${status}<br>\n" +
" 点击下面链接进入评审页面进行审核</p>\n" +
" <a href=\"${url}/#/track/review/view/${id}\">${url}/#/track/review/view/${id}</a>\n" +
" <p>${creator}创建了测试用例</p>\n" +
"</div>\n" +
"</body>\n" +
"</html>",
robotTitle: "【任务通知】:${creator} 创建的:${reviewName}待开始,计划开始时间是:${start}," +
"计划结束时间是:${end}请跟进!/ ${status}!点击下面链接进入测试评审页面${url}/#/track/review/view/${id}",
reviewTask: [{
taskType: "reviewTask",
robotTitle: "【任务通知】:${creator}创建了测试用例",
defectTask: [{
taskType: "defectTask",
event: "",
userIds: [],
type: [],
@ -185,29 +188,29 @@ export default {
identification: "",
isReadOnly: false,
}],
reviewTaskEventOptions: [
eventOptions: [
{value: 'CREATE', label: this.$t('commons.create')},
{value: 'UPDATE', label: this.$t('commons.update')},
{value: 'DELETE', label: this.$t('commons.delete')},
{value: 'COMMENT', label: this.$t('commons.comment')}
],
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')},
{value: 'LARK', label: this.$t('organization.message.lark')}
],
};
},
methods: {
initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.reviewTask = response.data;
this.reviewTask.forEach(planTask => {
this.handleReviewReceivers(planTask);
this.defectTask = response.data;
//
this.$emit("noticeSize", {taskType: 'api', size: this.defectTask.length});
this.defectTask.forEach(planTask => {
this.handleReceivers(planTask);
});
})
});
},
handleEdit(index, data) {
data.isReadOnly = true;
@ -226,15 +229,16 @@ export default {
}
},
handleAddTaskModel() {
let Task = {};
Task.event = [];
Task.userIds = [];
Task.type = '';
Task.webhook = '';
Task.isSet = true;
Task.identification = '';
Task.taskType = TASK_TYPE
this.reviewTask.push(Task)
let task = {};
task.receiverOptions = this.receiverOptions;
task.event = [];
task.userIds = [];
task.type = '';
task.webhook = '';
task.isSet = true;
task.identification = '';
task.taskType = TASK_TYPE;
this.defectTask.push(task);
},
handleAddTask(index, data) {
@ -258,11 +262,11 @@ export default {
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)
data.splice(index, 1);
} else {
data[index].isSet = false;
}
@ -270,50 +274,59 @@ export default {
deleteRowTask(index, data) { //
this.result = this.$get("/notice/delete/message/" + data.identification, response => {
this.$success(this.$t('commons.delete_success'));
this.initForm()
})
this.initForm();
});
},
rowClass() {
return "text-align:center"
return "text-align:center";
},
headClass() {
return "text-align:center;background:'#ededed'"
},
handleReviewReceivers(row) {
let reviewReceiverOptions = JSON.parse(JSON.stringify(this.reviewReceiverOptions));
switch (row.event) {
case "CREATE":
reviewReceiverOptions.unshift({id: 'EXECUTOR', name: this.$t('test_track.review.reviewer')})
break;
case "UPDATE":
reviewReceiverOptions.unshift({id: 'FOUNDER', name: this.$t('test_track.review.review_creator')})
break;
case "DELETE":
reviewReceiverOptions.unshift({id: 'FOUNDER', name: this.$t('test_track.review.review_creator')})
break;
case "COMMENT":
reviewReceiverOptions.unshift({id: 'MAINTAINER', name: this.$t('test_track.case.maintainer')})
break;
default:
break;
}
row.reviewReceiverOptions = reviewReceiverOptions;
return "text-align:center;background:'#ededed'";
},
handleTemplate(index, row) {
if (hasLicense()) {
this.$refs.noticeTemplate.open(row);
}
},
handleReceivers(row) {
let receiverOptions = JSON.parse(JSON.stringify(this.receiverOptions));
let i = row.userIds.indexOf('FOLLOW_PEOPLE');
switch (row.event) {
case "UPDATE":
receiverOptions.unshift({id: 'FOLLOW_PEOPLE', name: this.$t('api_test.automation.follow_people')});
receiverOptions.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
if (row.userIds.indexOf('FOLLOW_PEOPLE') < 0) {
row.userIds.unshift('FOLLOW_PEOPLE');
}
break;
case "DELETE":
receiverOptions.unshift({id: 'FOLLOW_PEOPLE', name: this.$t('api_test.automation.follow_people')});
receiverOptions.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
if (i > -1) {
row.userIds.splice(i, 1);
}
break;
default:
break;
}
row.receiverOptions = receiverOptions;
}
},
watch: {
reviewReceiverOptions(value) {
receiverOptions(value) {
if (value && value.length > 0) {
this.initForm();
}
}
}
}
};
</script>
<style scoped>
@ -322,20 +335,6 @@ export default {
}
.el-button {
margin-left: 10px;
}
/deep/ .el-select .el-input.is-disabled .el-input__inner {
background-color: #F5F7FA;
border-color: #E4E7ED;
color: #0a0a0a;
cursor: not-allowed;
}
/deep/ .el-input.is-disabled .el-input__inner {
background-color: #F5F7FA;
border-color: #E4E7ED;
color: #0a0a0a;
cursor: not-allowed;
margin-right: 10px;
}
</style>

View File

@ -0,0 +1,344 @@
<template>
<div>
<el-row>
<el-col :span="10">
<h5>接口定义</h5>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
{{ $t('organization.message.create_new_notification') }}
</el-button>
<el-popover
placement="right-end"
title="示例"
width="600"
trigger="click">
<ms-code-edit :read-only="true" height="400px" :data.sync="title" :modes="modes" :mode="'html'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.mail_template_example') }}
</el-button>
</el-popover>
<el-popover
placement="right-end"
title="示例"
width="400"
trigger="click"
:content="robotTitle">
<ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }}
</el-button>
</el-popover>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-table
:data="defectTask"
class="tb-edit"
border
:cell-style="rowClass"
:header-cell-style="headClass"
>
<el-table-column :label="$t('schedule.event')" min-width="15%" prop="events">
<template slot-scope="scope">
<el-select v-model="scope.row.event" :placeholder="$t('organization.message.select_events')" size="mini"
@change="handleReceivers(scope.row)"
prop="event" :disabled="!scope.row.isSet">
<el-option
v-for="item in eventOptions"
: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="receiver" min-width="20%">
<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 row.receiverOptions"
: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')" min-width="20%" prop="type">
<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')" min-width="25%" prop="result">
<template v-slot:default="scope">
<ms-tip-button
circle
type="success"
size="mini"
v-if="scope.row.isSet"
v-xpack
@click="handleTemplate(scope.$index,scope.row)"
:tip="$t('organization.message.template')"
icon="el-icon-tickets"/>
<ms-tip-button
circle
type="primary"
size="mini"
v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)"
:tip="$t('commons.add')"
icon="el-icon-check"/>
<ms-tip-button
circle
size="mini"
v-show="scope.row.isSet"
@click="removeRowTask(scope.$index,defectTask)"
:tip="$t('commons.cancel')"
icon="el-icon-refresh-left"/>
<ms-tip-button
el-button
circle
type="primary"
size="mini"
icon="el-icon-edit"
v-show="!scope.row.isSet"
:tip="$t('commons.edit')"
@click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
<ms-tip-button
circle
type="danger"
icon="el-icon-delete"
size="mini"
v-show="!scope.row.isSet"
@click="deleteRowTask(scope.$index,scope.row)"
:tip="$t('commons.delete')"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</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";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import MsTipButton from "@/business/components/common/components/MsTipButton";
const TASK_TYPE = 'API_DEFINITION_TASK';
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
export default {
name: "ApiDefinitionNotification",
components: {
MsTipButton,
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default
},
props: {
receiverOptions: {
type: Array
}
},
data() {
return {
modes: ['text', 'html'],
title: "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>MeterSphere</title>\n" +
"</head>\n" +
"<body>\n" +
"<div>\n" +
" <p>${creator}创建了测试用例</p>\n" +
"</div>\n" +
"</body>\n" +
"</html>",
robotTitle: "【任务通知】:${creator}创建了测试用例",
defectTask: [{
taskType: "defectTask",
event: "",
userIds: [],
type: [],
webhook: "",
isSet: true,
identification: "",
isReadOnly: false,
}],
eventOptions: [
{value: 'CREATE', label: 'API ' + this.$t('commons.create')},
{value: 'UPDATE', label: 'API ' + this.$t('commons.update')},
{value: 'DELETE', label: 'API ' + this.$t('commons.delete')},
{value: 'CASE_CREATE', label: 'CASE ' + this.$t('commons.create')},
{value: 'CASE_UPDATE', label: 'CASE ' + this.$t('commons.update')},
{value: 'CASE_DELETE', label: 'CASE ' + this.$t('commons.delete')},
],
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')},
{value: 'LARK', label: this.$t('organization.message.lark')}
],
};
},
methods: {
initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.defectTask = response.data;
//
this.$emit("noticeSize", {taskType: 'api', size: this.defectTask.length});
this.defectTask.forEach(planTask => {
this.handleReceivers(planTask);
});
});
},
handleEdit(index, data) {
data.isReadOnly = true;
if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly;
data.webhook = '';
}
},
handleEditTask(index, data) {
data.isSet = true;
if (data.type === 'EMAIL') {
data.isReadOnly = false;
data.webhook = '';
} else {
data.isReadOnly = true;
}
},
handleAddTaskModel() {
let task = {};
task.receiverOptions = this.receiverOptions;
task.event = [];
task.userIds = [];
task.type = '';
task.webhook = '';
task.isSet = true;
task.identification = '';
task.taskType = TASK_TYPE;
this.defectTask.push(task);
},
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' || data.type === 'LARK') {
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) {
data.isSet = false;
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);
}
},
handleReceivers(row) {
let receiverOptions = JSON.parse(JSON.stringify(this.receiverOptions));
let i = row.userIds.indexOf('FOLLOW_PEOPLE');
switch (row.event) {
case "UPDATE":
case "CASE_UPDATE":
receiverOptions.unshift({id: 'FOLLOW_PEOPLE', name: this.$t('api_test.automation.follow_people')});
receiverOptions.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
if (row.userIds.indexOf('FOLLOW_PEOPLE') < 0) {
row.userIds.unshift('FOLLOW_PEOPLE');
}
break;
case "DELETE":
case "CASE_DELETE":
receiverOptions.unshift({id: 'FOLLOW_PEOPLE', name: this.$t('api_test.automation.follow_people')});
receiverOptions.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
if (i > -1) {
row.userIds.splice(i, 1);
}
break;
default:
break;
}
row.receiverOptions = receiverOptions;
}
},
watch: {
receiverOptions(value) {
if (value && value.length > 0) {
this.initForm();
}
}
}
};
</script>
<style scoped>
.el-row {
margin-bottom: 10px;
}
.el-button {
margin-right: 10px;
}
</style>

View File

@ -0,0 +1,324 @@
<template>
<div>
<el-row>
<el-col :span="10">
<h5>首页</h5>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
{{ $t('organization.message.create_new_notification') }}
</el-button>
<el-popover
placement="right-end"
title="示例"
width="600"
trigger="click">
<ms-code-edit :read-only="true" height="400px" :data.sync="title" :modes="modes" :mode="'html'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.mail_template_example') }}
</el-button>
</el-popover>
<el-popover
placement="right-end"
title="示例"
width="400"
trigger="click"
:content="robotTitle">
<ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }}
</el-button>
</el-popover>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-table
:data="defectTask"
class="tb-edit"
border
:cell-style="rowClass"
:header-cell-style="headClass"
>
<el-table-column :label="$t('schedule.event')" min-width="15%" prop="events">
<template slot-scope="scope">
<el-select v-model="scope.row.event" :placeholder="$t('organization.message.select_events')" size="mini"
@change="handleReceivers(scope.row)"
prop="event" :disabled="!scope.row.isSet">
<el-option
v-for="item in eventOptions"
: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="receiver" min-width="20%">
<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 row.receiverOptions"
: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')" min-width="20%" prop="type">
<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')" min-width="25%" prop="result">
<template v-slot:default="scope">
<ms-tip-button
circle
type="success"
size="mini"
v-if="scope.row.isSet"
v-xpack
@click="handleTemplate(scope.$index,scope.row)"
:tip="$t('organization.message.template')"
icon="el-icon-tickets"/>
<ms-tip-button
circle
type="primary"
size="mini"
v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)"
:tip="$t('commons.add')"
icon="el-icon-check"/>
<ms-tip-button
circle
size="mini"
v-show="scope.row.isSet"
@click="removeRowTask(scope.$index,defectTask)"
:tip="$t('commons.cancel')"
icon="el-icon-refresh-left"/>
<ms-tip-button
el-button
circle
type="primary"
size="mini"
icon="el-icon-edit"
v-show="!scope.row.isSet"
:tip="$t('commons.edit')"
@click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
<ms-tip-button
circle
type="danger"
icon="el-icon-delete"
size="mini"
v-show="!scope.row.isSet"
@click="deleteRowTask(scope.$index,scope.row)"
:tip="$t('commons.delete')"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</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";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import MsTipButton from "@/business/components/common/components/MsTipButton";
const TASK_TYPE = 'API_HOME_TASK';
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
export default {
name: "ApiHomeNotification",
components: {
MsTipButton,
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default
},
props: {
receiverOptions: {
type: Array
}
},
data() {
return {
modes: ['text', 'html'],
title: "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>MeterSphere</title>\n" +
"</head>\n" +
"<body>\n" +
"<div>\n" +
" <p>${creator}关闭了定时任务</p>\n" +
"</div>\n" +
"</body>\n" +
"</html>",
robotTitle: "【任务通知】:${creator}发起了一个缺陷:${issuesName},请跟进",
defectTask: [{
taskType: "defectTask",
event: "",
userIds: [],
type: [],
webhook: "",
isSet: true,
identification: "",
isReadOnly: false,
}],
eventOptions: [
{value: 'CLOSE_SCHEDULE', label: '关闭定时任务'},
],
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')},
{value: 'LARK', label: this.$t('organization.message.lark')}
],
};
},
activated() {
this.initForm();
},
methods: {
initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.defectTask = response.data;
//
this.$emit("noticeSize", {taskType: 'api', size: this.defectTask.length});
this.defectTask.forEach(task => {
this.handleReceivers(task);
});
});
},
handleEdit(index, data) {
data.isReadOnly = true;
if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly;
data.webhook = '';
}
},
handleEditTask(index, data) {
data.isSet = true;
if (data.type === 'EMAIL') {
data.isReadOnly = false;
data.webhook = '';
} else {
data.isReadOnly = true;
}
},
handleAddTaskModel() {
let task = {};
task.event = [];
task.userIds = [];
task.type = '';
task.webhook = '';
task.isSet = true;
task.identification = '';
task.taskType = TASK_TYPE;
this.defectTask.push(task);
},
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' || data.type === 'LARK') {
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) {
data.isSet = false;
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);
}
},
handleReceivers(row) {
let receiverOptions = JSON.parse(JSON.stringify(this.receiverOptions));
switch (row.event) {
case "CLOSE_SCHEDULE":
receiverOptions.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
break;
default:
break;
}
row.receiverOptions = receiverOptions;
}
},
watch: {
receiverOptions() {
this.initForm();
}
}
};
</script>
<style scoped>
.el-row {
margin-bottom: 10px;
}
.el-button {
margin-right: 10px;
}
</style>

View File

@ -0,0 +1,322 @@
<template>
<div>
<el-row>
<el-col :span="10">
<h5>测试报告</h5>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
{{ $t('organization.message.create_new_notification') }}
</el-button>
<el-popover
placement="right-end"
title="示例"
width="600"
trigger="click">
<ms-code-edit :read-only="true" height="400px" :data.sync="title" :modes="modes" :mode="'html'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.mail_template_example') }}
</el-button>
</el-popover>
<el-popover
placement="right-end"
title="示例"
width="400"
trigger="click"
:content="robotTitle">
<ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }}
</el-button>
</el-popover>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-table
:data="defectTask"
class="tb-edit"
border
:cell-style="rowClass"
:header-cell-style="headClass"
>
<el-table-column :label="$t('schedule.event')" min-width="15%" prop="events">
<template slot-scope="scope">
<el-select v-model="scope.row.event" :placeholder="$t('organization.message.select_events')" size="mini"
@change="handleReceivers(scope.row)"
prop="event" :disabled="!scope.row.isSet">
<el-option
v-for="item in eventOptions"
: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="receiver" min-width="20%">
<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 row.receiverOptions"
: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')" min-width="20%" prop="type">
<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')" min-width="25%" prop="result">
<template v-slot:default="scope">
<ms-tip-button
circle
type="success"
size="mini"
v-if="scope.row.isSet"
v-xpack
@click="handleTemplate(scope.$index,scope.row)"
:tip="$t('organization.message.template')"
icon="el-icon-tickets"/>
<ms-tip-button
circle
type="primary"
size="mini"
v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)"
:tip="$t('commons.add')"
icon="el-icon-check"/>
<ms-tip-button
circle
size="mini"
v-show="scope.row.isSet"
@click="removeRowTask(scope.$index,defectTask)"
:tip="$t('commons.cancel')"
icon="el-icon-refresh-left"/>
<ms-tip-button
el-button
circle
type="primary"
size="mini"
icon="el-icon-edit"
v-show="!scope.row.isSet"
:tip="$t('commons.edit')"
@click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
<ms-tip-button
circle
type="danger"
icon="el-icon-delete"
size="mini"
v-show="!scope.row.isSet"
@click="deleteRowTask(scope.$index,scope.row)"
:tip="$t('commons.delete')"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</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";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import MsTipButton from "@/business/components/common/components/MsTipButton";
const TASK_TYPE = 'API_REPORT_TASK';
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
export default {
name: "ApiReportNotification",
components: {
MsTipButton,
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default
},
props: {
receiverOptions: {
type: Array
}
},
data() {
return {
modes: ['text', 'html'],
title: "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>MeterSphere</title>\n" +
"</head>\n" +
"<body>\n" +
"<div>\n" +
" <p>${creator}创建了测试用例</p>\n" +
"</div>\n" +
"</body>\n" +
"</html>",
robotTitle: "【任务通知】:${creator}创建了测试用例",
defectTask: [{
taskType: "defectTask",
event: "",
userIds: [],
type: [],
webhook: "",
isSet: true,
identification: "",
isReadOnly: false,
}],
eventOptions: [
{value: 'DELETE', label: this.$t('commons.delete')},
],
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')},
{value: 'LARK', label: this.$t('organization.message.lark')}
],
};
},
methods: {
initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.defectTask = response.data;
//
this.$emit("noticeSize", {taskType: 'api', size: this.defectTask.length});
this.defectTask.forEach(planTask => {
this.handleReceivers(planTask);
});
});
},
handleEdit(index, data) {
data.isReadOnly = true;
if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly;
data.webhook = '';
}
},
handleEditTask(index, data) {
data.isSet = true;
if (data.type === 'EMAIL') {
data.isReadOnly = false;
data.webhook = '';
} else {
data.isReadOnly = true;
}
},
handleAddTaskModel() {
let task = {};
task.receiverOptions = this.receiverOptions;
task.event = [];
task.userIds = [];
task.type = '';
task.webhook = '';
task.isSet = true;
task.identification = '';
task.taskType = TASK_TYPE;
this.defectTask.push(task);
},
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' || data.type === 'LARK') {
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) {
data.isSet = false;
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);
}
},
handleReceivers(row) {
let receiverOptions = JSON.parse(JSON.stringify(this.receiverOptions));
switch (row.event) {
case "DELETE":
receiverOptions.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
break;
default:
break;
}
row.receiverOptions = receiverOptions;
}
},
watch: {
receiverOptions(value) {
if (value && value.length > 0) {
this.initForm();
}
}
}
};
</script>
<style scoped>
.el-row {
margin-bottom: 10px;
}
.el-button {
margin-right: 10px;
}
</style>

View File

@ -3,7 +3,8 @@
<el-row>
<el-col :span="10">
<h3>{{ $t('organization.message.jenkins_task_notification') }}</h3>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel" v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
{{ $t('organization.message.create_new_notification') }}
</el-button>
<el-popover
@ -90,43 +91,49 @@
</el-table-column>
<el-table-column :label="$t('commons.operating')" min-width="25%" prop="result">
<template v-slot:default="scope">
<el-button
<ms-tip-button
circle
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
:tip="$t('organization.message.template')"
icon="el-icon-tickets"/>
<ms-tip-button
circle
type="primary"
size="mini"
v-if="scope.row.isSet"
v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)"
>{{ $t('commons.add') }}
</el-button>
<el-button
:tip="$t('commons.add')"
icon="el-icon-check"/>
<ms-tip-button
circle
size="mini"
v-if="scope.row.isSet"
@click.native.prevent="removeRowTask(scope.$index,jenkinsTask)"
>{{ $t('commons.cancel') }}
</el-button>
<el-button
v-show="scope.row.isSet"
@click="removeRowTask(scope.$index,jenkinsTask)"
:tip="$t('commons.cancel')"
icon="el-icon-refresh-left"/>
<ms-tip-button
el-button
circle
type="primary"
size="mini"
v-if="!scope.row.isSet"
icon="el-icon-edit"
v-show="!scope.row.isSet"
:tip="$t('commons.edit')"
@click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"
>{{ $t('commons.edit') }}
</el-button>
<el-button
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
<ms-tip-button
circle
type="danger"
icon="el-icon-delete"
size="mini"
v-show="!scope.row.isSet"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"
@click.native.prevent="deleteRowTask(scope.$index,scope.row)"
></el-button>
@click="deleteRowTask(scope.$index,scope.row)"
:tip="$t('commons.delete')"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</template>
</el-table-column>
</el-table>
@ -139,6 +146,7 @@
<script>
import {hasLicense} from "@/common/js/utils";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import MsTipButton from "@/business/components/common/components/MsTipButton";
const TASK_TYPE = 'JENKINS_TASK';
@ -148,6 +156,7 @@ const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./
export default {
name: "JenkinsNotification",
components: {
MsTipButton,
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default
},
@ -213,7 +222,7 @@ export default {
{value: 'WECHAT_ROBOT', label: this.$t('organization.message.enterprise_wechat_robot')},
{value: 'LARK', label: this.$t('organization.message.lark')}
],
}
};
},
activated() {
this.initForm();
@ -222,7 +231,9 @@ export default {
initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.jenkinsTask = response.data;
})
//
this.$emit("noticeSize", {taskType: 'jenkins', size: this.jenkinsTask.length});
});
},
handleEdit(index, data) {
data.isReadOnly = true;
@ -239,8 +250,8 @@ export default {
Task.webhook = '';
Task.isSet = true;
Task.identification = '';
Task.taskType = TASK_TYPE
this.jenkinsTask.push(Task)
Task.taskType = TASK_TYPE;
this.jenkinsTask.push(Task);
},
handleAddTask(index, data) {
if (data.event && data.userIds.length > 0 && data.type) {
@ -259,7 +270,7 @@ export default {
}
},
handleEditTask(index, data) {
data.isSet = true
data.isSet = true;
if (data.type === 'EMAIL') {
data.isReadOnly = false;
data.webhook = '';
@ -271,11 +282,11 @@ export default {
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)
data.splice(index, 1);
} else {
data[parseInt(index)].isSet = false;
}
@ -284,14 +295,14 @@ export default {
deleteRowTask(index, data) { //
this.result = this.$get("/notice/delete/message/" + data.identification, response => {
this.$success(this.$t('commons.delete_success'));
this.initForm()
})
this.initForm();
});
},
rowClass() {
return "text-align:center"
return "text-align:center";
},
headClass() {
return "text-align:center;background:'#ededed'"
return "text-align:center;background:'#ededed'";
},
handleTemplate(index, row) {
if (hasLicense()) {
@ -299,7 +310,7 @@ export default {
}
}
}
}
};
</script>
<style scoped>
@ -308,7 +319,7 @@ export default {
}
.el-button {
margin-left: 10px;
margin-right: 10px;
}
/deep/ .el-select .el-input.is-disabled .el-input__inner {

View File

@ -0,0 +1,322 @@
<template>
<div>
<el-row>
<el-col :span="10">
<h5>报告</h5>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
{{ $t('organization.message.create_new_notification') }}
</el-button>
<el-popover
placement="right-end"
title="示例"
width="600"
trigger="click">
<ms-code-edit :read-only="true" height="400px" :data.sync="title" :modes="modes" :mode="'html'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.mail_template_example') }}
</el-button>
</el-popover>
<el-popover
placement="right-end"
title="示例"
width="400"
trigger="click"
:content="robotTitle">
<ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }}
</el-button>
</el-popover>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-table
:data="defectTask"
class="tb-edit"
border
:cell-style="rowClass"
:header-cell-style="headClass"
>
<el-table-column :label="$t('schedule.event')" min-width="15%" prop="events">
<template slot-scope="scope">
<el-select v-model="scope.row.event" :placeholder="$t('organization.message.select_events')" size="mini"
@change="handleReceivers(scope.row)"
prop="event" :disabled="!scope.row.isSet">
<el-option
v-for="item in eventOptions"
: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="receiver" min-width="20%">
<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 row.receiverOptions"
: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')" min-width="20%" prop="type">
<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')" min-width="25%" prop="result">
<template v-slot:default="scope">
<ms-tip-button
circle
type="success"
size="mini"
v-if="scope.row.isSet"
v-xpack
@click="handleTemplate(scope.$index,scope.row)"
:tip="$t('organization.message.template')"
icon="el-icon-tickets"/>
<ms-tip-button
circle
type="primary"
size="mini"
v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)"
:tip="$t('commons.add')"
icon="el-icon-check"/>
<ms-tip-button
circle
size="mini"
v-show="scope.row.isSet"
@click="removeRowTask(scope.$index,defectTask)"
:tip="$t('commons.cancel')"
icon="el-icon-refresh-left"/>
<ms-tip-button
el-button
circle
type="primary"
size="mini"
icon="el-icon-edit"
v-show="!scope.row.isSet"
:tip="$t('commons.edit')"
@click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
<ms-tip-button
circle
type="danger"
icon="el-icon-delete"
size="mini"
v-show="!scope.row.isSet"
@click="deleteRowTask(scope.$index,scope.row)"
:tip="$t('commons.delete')"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</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";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import MsTipButton from "@/business/components/common/components/MsTipButton";
const TASK_TYPE = 'PERFORMANCE_REPORT_TASK';
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
export default {
name: "PerformanceReportNotification",
components: {
MsTipButton,
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default
},
props: {
receiverOptions: {
type: Array
}
},
data() {
return {
modes: ['text', 'html'],
title: "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>MeterSphere</title>\n" +
"</head>\n" +
"<body>\n" +
"<div>\n" +
" <p>${creator}创建了测试用例</p>\n" +
"</div>\n" +
"</body>\n" +
"</html>",
robotTitle: "【任务通知】:${creator}创建了测试用例",
defectTask: [{
taskType: "defectTask",
event: "",
userIds: [],
type: [],
webhook: "",
isSet: true,
identification: "",
isReadOnly: false,
}],
eventOptions: [
{value: 'DELETE', label: this.$t('commons.delete')},
],
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')},
{value: 'LARK', label: this.$t('organization.message.lark')}
],
};
},
methods: {
initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.defectTask = response.data;
//
this.$emit("noticeSize", {taskType: 'performance', size: this.defectTask.length});
this.defectTask.forEach(planTask => {
this.handleReceivers(planTask);
});
});
},
handleEdit(index, data) {
data.isReadOnly = true;
if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly;
data.webhook = '';
}
},
handleEditTask(index, data) {
data.isSet = true;
if (data.type === 'EMAIL') {
data.isReadOnly = false;
data.webhook = '';
} else {
data.isReadOnly = true;
}
},
handleAddTaskModel() {
let task = {};
task.receiverOptions = this.receiverOptions;
task.event = [];
task.userIds = [];
task.type = '';
task.webhook = '';
task.isSet = true;
task.identification = '';
task.taskType = TASK_TYPE;
this.defectTask.push(task);
},
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' || data.type === 'LARK') {
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) {
data.isSet = false;
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);
}
},
handleReceivers(row) {
let receiverOptions = JSON.parse(JSON.stringify(this.receiverOptions));
switch (row.event) {
case "DELETE":
receiverOptions.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
break;
default:
break;
}
row.receiverOptions = receiverOptions;
}
},
watch: {
receiverOptions(value) {
if (value && value.length > 0) {
this.initForm();
}
}
}
};
</script>
<style scoped>
.el-row {
margin-bottom: 10px;
}
.el-button {
margin-right: 10px;
}
</style>

View File

@ -0,0 +1,340 @@
<template>
<div>
<el-row>
<el-col :span="10">
<h5>测试</h5>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
{{ $t('organization.message.create_new_notification') }}
</el-button>
<el-popover
placement="right-end"
title="示例"
width="600"
trigger="click">
<ms-code-edit :read-only="true" height="400px" :data.sync="title" :modes="modes" :mode="'html'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.mail_template_example') }}
</el-button>
</el-popover>
<el-popover
placement="right-end"
title="示例"
width="400"
trigger="click"
:content="robotTitle">
<ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }}
</el-button>
</el-popover>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-table
:data="defectTask"
class="tb-edit"
border
:cell-style="rowClass"
:header-cell-style="headClass"
>
<el-table-column :label="$t('schedule.event')" min-width="15%" prop="events">
<template slot-scope="scope">
<el-select v-model="scope.row.event" :placeholder="$t('organization.message.select_events')" size="mini"
@change="handleReceivers(scope.row)"
prop="event" :disabled="!scope.row.isSet">
<el-option
v-for="item in eventOptions"
: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="receiver" min-width="20%">
<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 row.receiverOptions"
: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')" min-width="20%" prop="type">
<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')" min-width="25%" prop="result">
<template v-slot:default="scope">
<ms-tip-button
circle
type="success"
size="mini"
v-if="scope.row.isSet"
v-xpack
@click="handleTemplate(scope.$index,scope.row)"
:tip="$t('organization.message.template')"
icon="el-icon-tickets"/>
<ms-tip-button
circle
type="primary"
size="mini"
v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)"
:tip="$t('commons.add')"
icon="el-icon-check"/>
<ms-tip-button
circle
size="mini"
v-show="scope.row.isSet"
@click="removeRowTask(scope.$index,defectTask)"
:tip="$t('commons.cancel')"
icon="el-icon-refresh-left"/>
<ms-tip-button
el-button
circle
type="primary"
size="mini"
icon="el-icon-edit"
v-show="!scope.row.isSet"
:tip="$t('commons.edit')"
@click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
<ms-tip-button
circle
type="danger"
icon="el-icon-delete"
size="mini"
v-show="!scope.row.isSet"
@click="deleteRowTask(scope.$index,scope.row)"
:tip="$t('commons.delete')"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</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";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import MsTipButton from "@/business/components/common/components/MsTipButton";
const TASK_TYPE = 'PERFORMANCE_TEST_TASK';
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
export default {
name: "PerformanceTestNotification",
components: {
MsTipButton,
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default
},
props: {
receiverOptions: {
type: Array
}
},
data() {
return {
modes: ['text', 'html'],
title: "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>MeterSphere</title>\n" +
"</head>\n" +
"<body>\n" +
"<div>\n" +
" <p>${creator}创建了测试用例</p>\n" +
"</div>\n" +
"</body>\n" +
"</html>",
robotTitle: "【任务通知】:${creator}创建了测试用例",
defectTask: [{
taskType: "defectTask",
event: "",
userIds: [],
type: [],
webhook: "",
isSet: true,
identification: "",
isReadOnly: false,
}],
eventOptions: [
{value: 'CREATE', label: this.$t('commons.create')},
{value: 'UPDATE', label: this.$t('commons.update')},
{value: 'DELETE', label: this.$t('commons.delete')},
],
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')},
{value: 'LARK', label: this.$t('organization.message.lark')}
],
};
},
methods: {
initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.defectTask = response.data;
//
this.$emit("noticeSize", {taskType: 'performance', size: this.defectTask.length});
this.defectTask.forEach(planTask => {
this.handleReceivers(planTask);
});
});
},
handleEdit(index, data) {
data.isReadOnly = true;
if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly;
data.webhook = '';
}
},
handleEditTask(index, data) {
data.isSet = true;
if (data.type === 'EMAIL') {
data.isReadOnly = false;
data.webhook = '';
} else {
data.isReadOnly = true;
}
},
handleAddTaskModel() {
let task = {};
task.receiverOptions = this.receiverOptions;
task.event = [];
task.userIds = [];
task.type = '';
task.webhook = '';
task.isSet = true;
task.identification = '';
task.taskType = TASK_TYPE;
this.defectTask.push(task);
},
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' || data.type === 'LARK') {
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) {
data.isSet = false;
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);
}
},
handleReceivers(row) {
let receiverOptions = JSON.parse(JSON.stringify(this.receiverOptions));
let i = row.userIds.indexOf('FOLLOW_PEOPLE');
switch (row.event) {
case "UPDATE":
receiverOptions.unshift({id: 'FOLLOW_PEOPLE', name: this.$t('api_test.automation.follow_people')});
receiverOptions.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
if (row.userIds.indexOf('FOLLOW_PEOPLE') < 0) {
row.userIds.unshift('FOLLOW_PEOPLE');
}
break;
case "DELETE":
receiverOptions.unshift({id: 'FOLLOW_PEOPLE', name: this.$t('api_test.automation.follow_people')});
receiverOptions.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
if (i > -1) {
row.userIds.splice(i, 1);
}
break;
default:
break;
}
row.receiverOptions = receiverOptions;
}
},
watch: {
receiverOptions(value) {
if (value && value.length > 0) {
this.initForm();
}
}
}
};
</script>
<style scoped>
.el-row {
margin-bottom: 10px;
}
.el-button {
margin-right: 10px;
}
</style>

View File

@ -0,0 +1,351 @@
<template>
<div>
<el-row>
<el-col :span="10">
<h5>{{ $t('test_track.issue.issue') }}</h5>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
{{ $t('organization.message.create_new_notification') }}
</el-button>
<el-popover
placement="right-end"
title="示例"
width="600"
trigger="click">
<ms-code-edit :read-only="true" height="400px" :data.sync="title" :modes="modes" :mode="'html'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.mail_template_example') }}
</el-button>
</el-popover>
<el-popover
placement="right-end"
title="示例"
width="400"
trigger="click"
:content="robotTitle">
<ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }}
</el-button>
</el-popover>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-table
:data="defectTask"
class="tb-edit"
border
:cell-style="rowClass"
:header-cell-style="headClass"
>
<el-table-column :label="$t('schedule.event')" min-width="15%" prop="events">
<template slot-scope="scope">
<el-select v-model="scope.row.event" :placeholder="$t('organization.message.select_events')" size="mini"
@change="handleReceivers(scope.row)"
prop="event" :disabled="!scope.row.isSet">
<el-option
v-for="item in defectEventOptions"
: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="receiver" min-width="20%">
<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 row.defectReceiverOptions"
: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')" min-width="20%" prop="type">
<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')" min-width="25%" prop="result">
<template v-slot:default="scope">
<ms-tip-button
circle
type="success"
size="mini"
v-if="scope.row.isSet"
v-xpack
@click="handleTemplate(scope.$index,scope.row)"
:tip="$t('organization.message.template')"
icon="el-icon-tickets"/>
<ms-tip-button
circle
type="primary"
size="mini"
v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)"
:tip="$t('commons.add')"
icon="el-icon-check"/>
<ms-tip-button
circle
size="mini"
v-show="scope.row.isSet"
@click="removeRowTask(scope.$index,defectTask)"
:tip="$t('commons.cancel')"
icon="el-icon-refresh-left"/>
<ms-tip-button
el-button
circle
type="primary"
size="mini"
icon="el-icon-edit"
v-show="!scope.row.isSet"
:tip="$t('commons.edit')"
@click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
<ms-tip-button
circle
type="danger"
icon="el-icon-delete"
size="mini"
v-show="!scope.row.isSet"
@click="deleteRowTask(scope.$index,scope.row)"
:tip="$t('commons.delete')"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</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";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import MsTipButton from "@/business/components/common/components/MsTipButton";
const TASK_TYPE = 'DEFECT_TASK';
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
export default {
name: "DefectTaskNotification",
components: {
MsTipButton,
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default
},
props: {
defectReceiverOptions: {
type: Array
}
},
data() {
return {
modes: ['text', 'html'],
title: "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>MeterSphere</title>\n" +
"</head>\n" +
"<body>\n" +
"<div>\n" +
" <p>${creator}发起了一个缺陷:${issuesName},请跟进</p>\n" +
"</div>\n" +
"</body>\n" +
"</html>",
robotTitle: "【任务通知】:${creator}发起了一个缺陷:${issuesName},请跟进",
defectTask: [{
taskType: "defectTask",
event: "",
userIds: [],
type: [],
webhook: "",
isSet: true,
identification: "",
isReadOnly: false,
}],
defectEventOptions: [
{value: 'CREATE', label: this.$t('commons.create')},
{value: 'UPDATE', label: this.$t('commons.update')},
{value: 'DELETE', label: this.$t('commons.delete')},
{value: 'STATUS_CHANGE', label: '状态变更'},
],
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')},
{value: 'LARK', label: this.$t('organization.message.lark')}
],
};
},
methods: {
initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.defectTask = response.data;
//
this.$emit("noticeSize", {taskType: 'track', size: this.defectTask.length});
this.defectTask.forEach(planTask => {
this.handleReceivers(planTask);
});
});
},
handleEdit(index, data) {
data.isReadOnly = true;
if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly;
data.webhook = '';
}
},
handleEditTask(index, data) {
data.isSet = true;
if (data.type === 'EMAIL') {
data.isReadOnly = false;
data.webhook = '';
} else {
data.isReadOnly = true;
}
},
handleAddTaskModel() {
let Task = {};
Task.event = [];
Task.userIds = [];
Task.type = '';
Task.webhook = '';
Task.isSet = true;
Task.identification = '';
Task.taskType = TASK_TYPE;
this.defectTask.push(Task);
},
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' || data.type === 'LARK') {
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) {
data.isSet = false;
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);
}
},
handleReceivers(row) {
let testPlanReceivers = JSON.parse(JSON.stringify(this.defectReceiverOptions));
switch (row.event) {
case "UPDATE":
case "STATUS_CHANGE":
testPlanReceivers.unshift({id: 'PROCESSOR', name: '处理人'});
testPlanReceivers.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
if (row.userIds.indexOf('PROCESSOR') < 0) {
row.userIds.unshift('PROCESSOR');
}
break;
case "DELETE":
testPlanReceivers.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
break;
default:
break;
}
row.defectReceiverOptions = testPlanReceivers;
},
},
watch: {
defectReceiverOptions(value) {
if (value && value.length > 0) {
this.initForm();
}
}
}
};
</script>
<style scoped>
.el-row {
margin-bottom: 10px;
}
.el-button {
margin-right: 10px;
}
/deep/ .el-select .el-input.is-disabled .el-input__inner {
background-color: #F5F7FA;
border-color: #E4E7ED;
color: #0a0a0a;
cursor: not-allowed;
}
/deep/ .el-input.is-disabled .el-input__inner {
background-color: #F5F7FA;
border-color: #E4E7ED;
color: #0a0a0a;
cursor: not-allowed;
}
</style>

View File

@ -0,0 +1,342 @@
<template>
<div>
<el-row>
<el-col :span="10">
<h5>测试用例</h5>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
{{ $t('organization.message.create_new_notification') }}
</el-button>
<el-popover
placement="right-end"
title="示例"
width="600"
trigger="click">
<ms-code-edit :read-only="true" height="400px" :data.sync="title" :modes="modes" :mode="'html'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.mail_template_example') }}
</el-button>
</el-popover>
<el-popover
placement="right-end"
title="示例"
width="400"
trigger="click"
:content="robotTitle">
<ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }}
</el-button>
</el-popover>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-table
:data="defectTask"
class="tb-edit"
border
:cell-style="rowClass"
:header-cell-style="headClass"
>
<el-table-column :label="$t('schedule.event')" min-width="15%" prop="events">
<template slot-scope="scope">
<el-select v-model="scope.row.event" :placeholder="$t('organization.message.select_events')" size="mini"
@change="handleReceivers(scope.row)"
prop="event" :disabled="!scope.row.isSet">
<el-option
v-for="item in eventOptions"
: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="receiver" min-width="20%">
<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 row.receiverOptions"
: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')" min-width="20%" prop="type">
<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')" min-width="25%" prop="result">
<template v-slot:default="scope">
<ms-tip-button
circle
type="success"
size="mini"
v-if="scope.row.isSet"
v-xpack
@click="handleTemplate(scope.$index,scope.row)"
:tip="$t('organization.message.template')"
icon="el-icon-tickets"/>
<ms-tip-button
circle
type="primary"
size="mini"
v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)"
:tip="$t('commons.add')"
icon="el-icon-check"/>
<ms-tip-button
circle
size="mini"
v-show="scope.row.isSet"
@click="removeRowTask(scope.$index,defectTask)"
:tip="$t('commons.cancel')"
icon="el-icon-refresh-left"/>
<ms-tip-button
el-button
circle
type="primary"
size="mini"
icon="el-icon-edit"
v-show="!scope.row.isSet"
:tip="$t('commons.edit')"
@click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
<ms-tip-button
circle
type="danger"
icon="el-icon-delete"
size="mini"
v-show="!scope.row.isSet"
@click="deleteRowTask(scope.$index,scope.row)"
:tip="$t('commons.delete')"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</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";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import MsTipButton from "@/business/components/common/components/MsTipButton";
const TASK_TYPE = 'TRACK_TEST_CASE_TASK';
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
export default {
name: "TestCaseNotification",
components: {
MsTipButton,
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default
},
props: {
receiverOptions: {
type: Array
}
},
data() {
return {
modes: ['text', 'html'],
title: "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>MeterSphere</title>\n" +
"</head>\n" +
"<body>\n" +
"<div>\n" +
" <p>${creator}创建了测试用例</p>\n" +
"</div>\n" +
"</body>\n" +
"</html>",
robotTitle: "【任务通知】:${creator}创建了测试用例",
defectTask: [{
taskType: "defectTask",
event: "",
userIds: [],
type: [],
webhook: "",
isSet: true,
identification: "",
isReadOnly: false,
}],
eventOptions: [
{value: 'CREATE', label: this.$t('commons.create')},
{value: 'UPDATE', label: this.$t('commons.update')},
{value: 'DELETE', label: this.$t('commons.delete')},
{value: 'COMMENT', label: this.$t('commons.comment')}
],
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')},
{value: 'LARK', label: this.$t('organization.message.lark')}
],
};
},
methods: {
initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.defectTask = response.data;
//
this.$emit("noticeSize", {taskType: 'track', size: this.defectTask.length});
this.defectTask.forEach(planTask => {
this.handleReceivers(planTask);
});
});
},
handleEdit(index, data) {
data.isReadOnly = true;
if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly;
data.webhook = '';
}
},
handleEditTask(index, data) {
data.isSet = true;
if (data.type === 'EMAIL') {
data.isReadOnly = false;
data.webhook = '';
} else {
data.isReadOnly = true;
}
},
handleAddTaskModel() {
let task = {};
task.receiverOptions = this.receiverOptions;
task.event = [];
task.userIds = [];
task.type = '';
task.webhook = '';
task.isSet = true;
task.identification = '';
task.taskType = TASK_TYPE;
this.defectTask.push(task);
},
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' || data.type === 'LARK') {
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) {
data.isSet = false;
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);
}
},
handleReceivers(row) {
let receiverOptions = JSON.parse(JSON.stringify(this.receiverOptions));
let i = row.userIds.indexOf('FOLLOW_PEOPLE');
switch (row.event) {
case "UPDATE":
case "DELETE":
receiverOptions.unshift({id: 'FOLLOW_PEOPLE', name: this.$t('api_test.automation.follow_people')});
receiverOptions.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
if (i < 0) {
row.userIds.unshift('FOLLOW_PEOPLE');
}
break;
case "COMMENT":
receiverOptions.unshift({id: 'FOLLOW_PEOPLE', name: this.$t('api_test.automation.follow_people')});
receiverOptions.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
if (i > -1) {
row.userIds.splice(i, 1);
}
break;
default:
break;
}
row.receiverOptions = receiverOptions;
}
},
watch: {
receiverOptions(value) {
if (value && value.length > 0) {
this.initForm();
}
}
}
};
</script>
<style scoped>
.el-row {
margin-bottom: 10px;
}
.el-button {
margin-right: 10px;
}
</style>

View File

@ -2,8 +2,9 @@
<div>
<el-row>
<el-col :span="10">
<h3>{{ $t('organization.message.test_plan_task_notification') }}</h3>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel" v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
<h5>{{ $t('test_track.plan.test_plan') }}</h5>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
{{ $t('organization.message.create_new_notification') }}
</el-button>
<el-popover
@ -86,43 +87,49 @@
</el-table-column>
<el-table-column :label="$t('commons.operating')" min-width="25%" prop="result">
<template v-slot:default="scope">
<el-button
<ms-tip-button
circle
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
:tip="$t('organization.message.template')"
icon="el-icon-tickets"/>
<ms-tip-button
circle
type="primary"
size="mini"
v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)"
>{{ $t('commons.add') }}
</el-button>
<el-button
:tip="$t('commons.add')"
icon="el-icon-check"/>
<ms-tip-button
circle
size="mini"
v-show="scope.row.isSet"
@click.native.prevent="removeRowTask(scope.$index,testCasePlanTask)"
>{{ $t('commons.cancel') }}
</el-button>
<el-button
@click="removeRowTask(scope.$index,testCasePlanTask)"
:tip="$t('commons.cancel')"
icon="el-icon-refresh-left"/>
<ms-tip-button
el-button
circle
type="primary"
size="mini"
icon="el-icon-edit"
v-show="!scope.row.isSet"
:tip="$t('commons.edit')"
@click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"
>{{ $t('commons.edit') }}
</el-button>
<el-button
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
<ms-tip-button
circle
type="danger"
icon="el-icon-delete"
size="mini"
v-show="!scope.row.isSet"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"
@click.native.prevent="deleteRowTask(scope.$index,scope.row)"
></el-button>
@click="deleteRowTask(scope.$index,scope.row)"
:tip="$t('commons.delete')"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</template>
</el-table-column>
</el-table>
@ -136,6 +143,7 @@
<script>
import {hasLicense} from "@/common/js/utils";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import MsTipButton from "@/business/components/common/components/MsTipButton";
const TASK_TYPE = 'TEST_PLAN_TASK';
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
@ -144,6 +152,7 @@ const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./
export default {
name: "TestPlanTaskNotification",
components: {
MsTipButton,
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default
},
@ -189,7 +198,10 @@ export default {
otherEventOptions: [
{value: 'CREATE', label: this.$t('commons.create')},
{value: 'UPDATE', label: this.$t('commons.update')},
{value: 'DELETE', label: this.$t('commons.delete')}
{value: 'DELETE', label: this.$t('commons.delete')},
{value: 'COMPLETE', label: '执行完成'},
// {value: 'SUCCESS_ONE_BY_ONE', label: ''},
// {value: 'FAIL_ONE_BY_ONE', label: ''},
],
receiveTypeOptions: [
{value: 'EMAIL', label: this.$t('organization.message.mail')},
@ -203,20 +215,22 @@ export default {
initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.testCasePlanTask = response.data;
//
this.$emit("noticeSize", {taskType: 'track', size: this.testCasePlanTask.length});
this.testCasePlanTask.forEach(planTask => {
this.handleTestPlanReceivers(planTask);
});
})
});
},
handleEdit(index, data) {
data.isReadOnly = true;
if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly
data.isReadOnly = !data.isReadOnly;
data.webhook = '';
}
},
handleEditTask(index, data) {
data.isSet = true
data.isSet = true;
if (data.type === 'EMAIL') {
data.isReadOnly = false;
data.webhook = '';
@ -232,8 +246,8 @@ export default {
Task.webhook = '';
Task.isSet = true;
Task.identification = '';
Task.taskType = TASK_TYPE
this.testCasePlanTask.push(Task)
Task.taskType = TASK_TYPE;
this.testCasePlanTask.push(Task);
},
handleAddTask(index, data) {
@ -253,41 +267,45 @@ export default {
}
},
addTask(data) {
data.isSet = false
data.isSet = false;
this.result = this.$post("/notice/save/message/task", data, () => {
this.initForm()
this.initForm();
this.$success(this.$t('commons.save_success'));
})
});
},
removeRowTask(index, data) { //
if (!data[index].identification) {
data.splice(index, 1)
data.splice(index, 1);
} else {
data[index].isSet = false
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()
})
this.initForm();
});
},
rowClass() {
return "text-align:center"
return "text-align:center";
},
headClass() {
return "text-align:center;background:'#ededed'"
return "text-align:center;background:'#ededed'";
},
handleTestPlanReceivers(row) {
let testPlanReceivers = JSON.parse(JSON.stringify(this.testPlanReceiverOptions));
switch (row.event) {
case "CREATE":
testPlanReceivers.unshift({id: 'EXECUTOR', name: this.$t('test_track.plan_view.executor')})
testPlanReceivers.unshift({id: 'EXECUTOR', name: this.$t('test_track.plan_view.executor')});
break;
case "UPDATE":
case "DELETE":
case "COMMENT":
testPlanReceivers.unshift({id: 'FOUNDER', name: this.$t('api_test.creator')});
case "COMPLETE":
testPlanReceivers.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
break;
default:
break;
@ -307,7 +325,7 @@ export default {
}
}
}
}
};
</script>
<style scoped>
@ -316,7 +334,7 @@ export default {
}
.el-button {
margin-left: 10px;
margin-right: 10px;
}
/deep/ .el-select .el-input.is-disabled .el-input__inner {

View File

@ -0,0 +1,365 @@
<template>
<div>
<el-row>
<el-col :span="10">
<h5>{{ $t('test_track.review.test_review') }}</h5>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
{{ $t('organization.message.create_new_notification') }}
</el-button>
<el-popover
placement="right-end"
title="示例"
width="600"
trigger="click">
<ms-code-edit :read-only="true" height="400px" :data.sync="title" :modes="modes" :mode="'html'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.mail_template_example') }}
</el-button>
</el-popover>
<el-popover
placement="right-end"
title="示例"
width="600"
trigger="click">
<ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }}
</el-button>
</el-popover>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-table
:data="reviewTask"
class="tb-edit"
border
:cell-style="rowClass"
:header-cell-style="headClass"
>
<el-table-column :label="$t('schedule.event')" min-width="15%" prop="events">
<template slot-scope="scope">
<el-select v-model="scope.row.event" :placeholder="$t('organization.message.select_events')" size="mini"
@change="handleReviewReceivers(scope.row)"
prop="event" :disabled="!scope.row.isSet">
<el-option
v-for="item in reviewTaskEventOptions"
: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="receiver" min-width="20%">
<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 row.reviewReceiverOptions"
: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')" min-width="20%" prop="type">
<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')" min-width="25%" prop="result">
<template v-slot:default="scope">
<ms-tip-button
circle
type="success"
size="mini"
v-if="scope.row.isSet"
v-xpack
@click="handleTemplate(scope.$index,scope.row)"
:tip="$t('organization.message.template')"
icon="el-icon-tickets"/>
<ms-tip-button
circle
type="primary"
size="mini"
v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)"
:tip="$t('commons.add')"
icon="el-icon-check"/>
<ms-tip-button
circle
size="mini"
v-show="scope.row.isSet"
@click="removeRowTask(scope.$index,reviewTask)"
:tip="$t('commons.cancel')"
icon="el-icon-refresh-left"/>
<ms-tip-button
el-button
circle
type="primary"
size="mini"
icon="el-icon-edit"
v-show="!scope.row.isSet"
:tip="$t('commons.edit')"
@click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
<ms-tip-button
circle
type="danger"
icon="el-icon-delete"
size="mini"
v-show="!scope.row.isSet"
@click="deleteRowTask(scope.$index,scope.row)"
:tip="$t('commons.delete')"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</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";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import MsTipButton from "@/business/components/common/components/MsTipButton";
const TASK_TYPE = 'REVIEW_TASK';
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
export default {
name: "TestReviewNotification",
components: {
MsTipButton,
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default
},
props: {
reviewReceiverOptions: {
type: Array
}
},
data() {
return {
modes: ['text', 'html'],
title: "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>MeterSphere</title>\n" +
"</head>\n" +
"<body>\n" +
"<div>\n" +
" <p style=\"text-align: left\">${creator} 创建的:<br>\n" +
" ${reviewName}待开始<br>\n" +
" 计划开始时间是:${start}<br>\n" +
" 计划结束时间为:${end}<br>\n" +
" 请跟进!/${status}<br>\n" +
" 点击下面链接进入评审页面进行审核</p>\n" +
" <a href=\"${url}/#/track/review/view/${id}\">${url}/#/track/review/view/${id}</a>\n" +
"</div>\n" +
"</body>\n" +
"</html>",
robotTitle: "【任务通知】:${creator} 创建的:${reviewName}待开始,计划开始时间是:${start}," +
"计划结束时间是:${end}请跟进!/ ${status}!点击下面链接进入测试评审页面${url}/#/track/review/view/${id}",
reviewTask: [{
taskType: "reviewTask",
event: "",
userIds: [],
type: [],
webhook: "",
isSet: true,
identification: "",
isReadOnly: false,
}],
reviewTaskEventOptions: [
{value: 'CREATE', label: this.$t('commons.create')},
{value: 'UPDATE', label: this.$t('commons.update')},
{value: 'DELETE', label: this.$t('commons.delete')},
{value: 'COMMENT', label: this.$t('commons.comment')},
{value: 'COMPLETE', label: '评审完成'}
],
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')},
{value: 'LARK', label: this.$t('organization.message.lark')}
],
};
},
methods: {
initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.reviewTask = response.data;
//
this.$emit("noticeSize", {taskType: 'track', size: this.reviewTask.length});
this.reviewTask.forEach(planTask => {
this.handleReviewReceivers(planTask);
});
});
},
handleEdit(index, data) {
data.isReadOnly = true;
if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly;
data.webhook = '';
}
},
handleEditTask(index, data) {
data.isSet = true;
if (data.type === 'EMAIL') {
data.isReadOnly = false;
data.webhook = '';
} else {
data.isReadOnly = true;
}
},
handleAddTaskModel() {
let Task = {};
Task.event = [];
Task.userIds = [];
Task.type = '';
Task.webhook = '';
Task.isSet = true;
Task.identification = '';
Task.taskType = TASK_TYPE;
this.reviewTask.push(Task);
},
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' || data.type === 'LARK') {
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) {
data.isSet = false;
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'";
},
handleReviewReceivers(row) {
let reviewReceiverOptions = JSON.parse(JSON.stringify(this.reviewReceiverOptions));
switch (row.event) {
case "CREATE":
reviewReceiverOptions.unshift({id: 'EXECUTOR', name: this.$t('test_track.review.reviewer')});
break;
case "UPDATE":
reviewReceiverOptions.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
break;
case "DELETE":
reviewReceiverOptions.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
break;
case "COMMENT":
reviewReceiverOptions.unshift({id: 'MAINTAINER', name: this.$t('test_track.case.maintainer')});
break;
case "COMPLETE":
reviewReceiverOptions.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
break;
default:
break;
}
row.reviewReceiverOptions = reviewReceiverOptions;
},
handleTemplate(index, row) {
if (hasLicense()) {
this.$refs.noticeTemplate.open(row);
}
}
},
watch: {
reviewReceiverOptions(value) {
if (value && value.length > 0) {
this.initForm();
}
}
}
};
</script>
<style scoped>
.el-row {
margin-bottom: 10px;
}
.el-button {
margin-right: 10px;
}
/deep/ .el-select .el-input.is-disabled .el-input__inner {
background-color: #F5F7FA;
border-color: #E4E7ED;
color: #0a0a0a;
cursor: not-allowed;
}
/deep/ .el-input.is-disabled .el-input__inner {
background-color: #F5F7FA;
border-color: #E4E7ED;
color: #0a0a0a;
cursor: not-allowed;
}
</style>

View File

@ -0,0 +1,324 @@
<template>
<div>
<el-row>
<el-col :span="10">
<h5>首页</h5>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
{{ $t('organization.message.create_new_notification') }}
</el-button>
<el-popover
placement="right-end"
title="示例"
width="600"
trigger="click">
<ms-code-edit :read-only="true" height="400px" :data.sync="title" :modes="modes" :mode="'html'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.mail_template_example') }}
</el-button>
</el-popover>
<el-popover
placement="right-end"
title="示例"
width="400"
trigger="click"
:content="robotTitle">
<ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }}
</el-button>
</el-popover>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-table
:data="defectTask"
class="tb-edit"
border
:cell-style="rowClass"
:header-cell-style="headClass"
>
<el-table-column :label="$t('schedule.event')" min-width="15%" prop="events">
<template slot-scope="scope">
<el-select v-model="scope.row.event" :placeholder="$t('organization.message.select_events')" size="mini"
@change="handleReceivers(scope.row)"
prop="event" :disabled="!scope.row.isSet">
<el-option
v-for="item in eventOptions"
: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="receiver" min-width="20%">
<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 row.receiverOptions"
: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')" min-width="20%" prop="type">
<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')" min-width="25%" prop="result">
<template v-slot:default="scope">
<ms-tip-button
circle
type="success"
size="mini"
v-if="scope.row.isSet"
v-xpack
@click="handleTemplate(scope.$index,scope.row)"
:tip="$t('organization.message.template')"
icon="el-icon-tickets"/>
<ms-tip-button
circle
type="primary"
size="mini"
v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)"
:tip="$t('commons.add')"
icon="el-icon-check"/>
<ms-tip-button
circle
size="mini"
v-show="scope.row.isSet"
@click="removeRowTask(scope.$index,defectTask)"
:tip="$t('commons.cancel')"
icon="el-icon-refresh-left"/>
<ms-tip-button
el-button
circle
type="primary"
size="mini"
icon="el-icon-edit"
v-show="!scope.row.isSet"
:tip="$t('commons.edit')"
@click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
<ms-tip-button
circle
type="danger"
icon="el-icon-delete"
size="mini"
v-show="!scope.row.isSet"
@click="deleteRowTask(scope.$index,scope.row)"
:tip="$t('commons.delete')"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</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";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import MsTipButton from "@/business/components/common/components/MsTipButton";
const TASK_TYPE = 'TRACK_HOME_TASK';
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
export default {
name: "TrackHomeNotification",
components: {
MsTipButton,
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default
},
props: {
receiverOptions: {
type: Array
}
},
data() {
return {
modes: ['text', 'html'],
title: "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>MeterSphere</title>\n" +
"</head>\n" +
"<body>\n" +
"<div>\n" +
" <p>${operator}关闭了定时任务</p>\n" +
"</div>\n" +
"</body>\n" +
"</html>",
robotTitle: "【任务通知】:${operator}发起了一个缺陷:${name},请跟进",
defectTask: [{
taskType: "defectTask",
event: "",
userIds: [],
type: [],
webhook: "",
isSet: true,
identification: "",
isReadOnly: false,
}],
eventOptions: [
{value: 'CLOSE_SCHEDULE', label: '关闭定时任务'},
],
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')},
{value: 'LARK', label: this.$t('organization.message.lark')}
],
};
},
activated() {
this.initForm();
},
methods: {
initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.defectTask = response.data;
//
this.$emit("noticeSize", {taskType: 'track', size: this.defectTask.length});
this.defectTask.forEach(task => {
this.handleReceivers(task);
});
});
},
handleEdit(index, data) {
data.isReadOnly = true;
if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly;
data.webhook = '';
}
},
handleEditTask(index, data) {
data.isSet = true;
if (data.type === 'EMAIL') {
data.isReadOnly = false;
data.webhook = '';
} else {
data.isReadOnly = true;
}
},
handleAddTaskModel() {
let task = {};
task.event = [];
task.userIds = [];
task.type = '';
task.webhook = '';
task.isSet = true;
task.identification = '';
task.taskType = TASK_TYPE;
this.defectTask.push(task);
},
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' || data.type === 'LARK') {
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) {
data.isSet = false;
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);
}
},
handleReceivers(row) {
let receiverOptions = JSON.parse(JSON.stringify(this.receiverOptions));
switch (row.event) {
case "CLOSE_SCHEDULE":
receiverOptions.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
break;
default:
break;
}
row.receiverOptions = receiverOptions;
}
},
watch: {
receiverOptions() {
this.initForm();
}
}
};
</script>
<style scoped>
.el-row {
margin-bottom: 10px;
}
.el-button {
margin-right: 10px;
}
</style>

View File

@ -2,8 +2,9 @@
<div>
<el-row>
<el-col :span="10">
<h3>{{ $t('organization.message.defect_task_notification') }}</h3>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel" v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
<h5>报告</h5>
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']">
{{ $t('organization.message.create_new_notification') }}
</el-button>
<el-popover
@ -41,9 +42,10 @@
<el-table-column :label="$t('schedule.event')" min-width="15%" prop="events">
<template slot-scope="scope">
<el-select v-model="scope.row.event" :placeholder="$t('organization.message.select_events')" size="mini"
@change="handleReceivers(scope.row)"
prop="event" :disabled="!scope.row.isSet">
<el-option
v-for="item in defectEventOptions"
v-for="item in eventOptions"
:key="item.value"
:label="item.label"
:value="item.value">
@ -57,7 +59,7 @@
:placeholder="$t('commons.please_select')"
style="width: 100%;" :disabled="!row.isSet">
<el-option
v-for="item in defectReceiverOptions"
v-for="item in row.receiverOptions"
:key="item.id"
:label="item.name"
:value="item.id">
@ -87,43 +89,49 @@
</el-table-column>
<el-table-column :label="$t('commons.operating')" min-width="25%" prop="result">
<template v-slot:default="scope">
<el-button
<ms-tip-button
circle
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
:tip="$t('organization.message.template')"
icon="el-icon-tickets"/>
<ms-tip-button
circle
type="primary"
size="mini"
v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)"
>{{ $t('commons.add') }}
</el-button>
<el-button
:tip="$t('commons.add')"
icon="el-icon-check"/>
<ms-tip-button
circle
size="mini"
v-show="scope.row.isSet"
@click.native.prevent="removeRowTask(scope.$index,defectTask)"
>{{ $t('commons.cancel') }}
</el-button>
<el-button
@click="removeRowTask(scope.$index,defectTask)"
:tip="$t('commons.cancel')"
icon="el-icon-refresh-left"/>
<ms-tip-button
el-button
circle
type="primary"
size="mini"
icon="el-icon-edit"
v-show="!scope.row.isSet"
:tip="$t('commons.edit')"
@click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"
>{{ $t('commons.edit') }}
</el-button>
<el-button
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
<ms-tip-button
circle
type="danger"
icon="el-icon-delete"
size="mini"
v-show="!scope.row.isSet"
@click="deleteRowTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"
></el-button>
:tip="$t('commons.delete')"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</template>
</el-table-column>
</el-table>
@ -136,19 +144,21 @@
<script>
import {hasLicense} from "@/common/js/utils";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import MsTipButton from "@/business/components/common/components/MsTipButton";
const TASK_TYPE = 'DEFECT_TASK';
const TASK_TYPE = 'TRACK_REPORT_TASK';
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
export default {
name: "DefectTaskNotification",
name: "TrackReportNotification",
components: {
MsTipButton,
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default
},
props: {
defectReceiverOptions: {
receiverOptions: {
type: Array
}
},
@ -163,7 +173,7 @@ export default {
"</head>\n" +
"<body>\n" +
"<div>\n" +
" <p>${creator}发起了一个缺陷:${issuesName},请跟进</p>\n" +
" <p>${creator}关闭了定时任务</p>\n" +
"</div>\n" +
"</body>\n" +
"</html>",
@ -178,36 +188,38 @@ export default {
identification: "",
isReadOnly: false,
}],
defectEventOptions: [
{value: 'CREATE', label: this.$t('commons.create')},
eventOptions: [
{value: 'DELETE', label: this.$t('commons.delete')},
],
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')},
{value: 'LARK', label: this.$t('organization.message.lark')}
],
};
},
activated() {
this.initForm()
},
methods: {
initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.defectTask = response.data;
})
//
this.$emit("noticeSize", {taskType: 'track', size: this.defectTask.length});
this.defectTask.forEach(planTask => {
this.handleReceivers(planTask);
});
});
},
handleEdit(index, data) {
data.isReadOnly = true;
if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly
data.isReadOnly = !data.isReadOnly;
data.webhook = '';
}
},
handleEditTask(index, data) {
data.isSet = true
data.isSet = true;
if (data.type === 'EMAIL') {
data.isReadOnly = false;
data.webhook = '';
@ -223,8 +235,8 @@ export default {
Task.webhook = '';
Task.isSet = true;
Task.identification = '';
Task.taskType = TASK_TYPE
this.defectTask.push(Task)
Task.taskType = TASK_TYPE;
this.defectTask.push(Task);
},
handleAddTask(index, data) {
@ -244,61 +256,67 @@ export default {
}
},
addTask(data) {
data.isSet = false
data.isSet = false;
this.result = this.$post("/notice/save/message/task", data, () => {
this.initForm()
this.initForm();
this.$success(this.$t('commons.save_success'));
})
});
},
removeRowTask(index, data) { //
if (!data[index].identification) {
data.splice(index, 1)
data.splice(index, 1);
} else {
data[index].isSet = false
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()
})
this.initForm();
});
},
rowClass() {
return "text-align:center"
return "text-align:center";
},
headClass() {
return "text-align:center;background:'#ededed'"
return "text-align:center;background:'#ededed'";
},
handleTemplate(index, row) {
if (hasLicense()) {
this.$refs.noticeTemplate.open(row);
}
},
handleReceivers(row) {
let receiverOptions = JSON.parse(JSON.stringify(this.receiverOptions));
switch (row.event) {
case "DELETE":
receiverOptions.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.userIds.indexOf('CREATOR') < 0) {
row.userIds.unshift('CREATOR');
}
break;
default:
break;
}
row.receiverOptions = receiverOptions;
}
},
watch: {
receiverOptions(value) {
if (value && value.length > 0) {
this.initForm();
}
}
}
}
};
</script>
<style scoped>
.el-row {
margin-bottom: 10px;
}
.el-button {
margin-left: 10px;
}
/deep/ .el-select .el-input.is-disabled .el-input__inner {
background-color: #F5F7FA;
border-color: #E4E7ED;
color: #0a0a0a;
cursor: not-allowed;
}
/deep/ .el-input.is-disabled .el-input__inner {
background-color: #F5F7FA;
border-color: #E4E7ED;
color: #0a0a0a;
cursor: not-allowed;
margin-right: 10px;
}
</style>

View File

@ -25,7 +25,7 @@
<el-form :model="form" :rules="rules" ref="caseFrom" v-loading="result.loading" class="case-form">
<ms-form-divider :title="$t('test_track.plan_view.base_info')"/>
<el-row>
<el-col :span="7">
<el-col :span="6">
<el-form-item
:placeholder="$t('test_track.case.input_name')"
:label="$t('test_track.case.name')"
@ -35,18 +35,34 @@
</el-form-item>
</el-col>
<el-col :span="7">
<el-col :span="6">
<el-form-item :label="$t('test_track.case.module')" :label-width="formLabelWidth" prop="module">
<ms-select-tree :disabled="readOnly" :data="treeNodes" :defaultKey="form.module" :obj="moduleObj"
@getValue="setModule" clearable checkStrictly size="small"/>
</el-form-item>
</el-col>
<el-col :span="7">
<el-col :span="6">
<el-form-item :label="$t('commons.tag')" :label-width="formLabelWidth" prop="tag">
<ms-input-tag :read-only="readOnly" :currentScenario="form" v-if="showInputTag" ref="tag" class="ms-case-input"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('api_test.automation.follow_people')" :label-width="formLabelWidth"
prop="followPeople">
<el-select v-model="form.followPeople"
clearable
:placeholder="$t('api_test.automation.follow_people')" filterable size="small">
<el-option
v-for="item in maintainerOptions"
:key="item.id"
:label="item.id + ' (' + item.name + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- 自定义字段 -->
@ -212,7 +228,8 @@
stepDescription: '',
expectedResult: '',
stepModel: 'STEP',
customNum: ''
customNum: '',
followPeople: '',
},
maintainerOptions: [],
// testOptions: [],
@ -605,14 +622,13 @@
this.$success(this.$t('commons.save_success'));
this.path = "/test/case/edit";
// this.operationType = "edit"
this.form.id = response.id;
this.$emit("refreshTestCase",);
//this.tableType = 'edit';
this.$emit("refresh", this.form);
this.form.id = response.data;
this.form.id = response.data.id;
if (this.type === 'add' || this.type === 'copy') {
param.id = response.data;
param.id = response.data.id;
this.$emit("caseCreate", param);
this.close();
} else {

Some files were not shown because too many files have changed in this diff Show More