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

View File

@ -10,10 +10,12 @@ import io.metersphere.api.dto.automation.ExecuteType;
import io.metersphere.api.jmeter.TestResult; import io.metersphere.api.jmeter.TestResult;
import io.metersphere.api.service.ApiScenarioReportService; import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.api.service.MsResultService; import io.metersphere.api.service.MsResultService;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants; import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.Pager;
import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -47,6 +49,8 @@ public class APIScenarioReportController {
@PostMapping("/delete") @PostMapping("/delete")
@MsAuditLog(module = "api_automation_report", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#request.id)", msClass = ApiScenarioReportService.class) @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) { public void delete(@RequestBody DeleteAPIReportRequest request) {
apiReportService.delete(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.dto.scenario.request.dubbo.RegistryCenter;
import io.metersphere.api.service.*; import io.metersphere.api.service.*;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.utils.CronUtils; import io.metersphere.commons.utils.CronUtils;
import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager; 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.QueryScheduleRequest;
import io.metersphere.controller.request.ScheduleRequest; import io.metersphere.controller.request.ScheduleRequest;
import io.metersphere.dto.ScheduleDao; import io.metersphere.dto.ScheduleDao;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.service.CheckPermissionService; import io.metersphere.service.CheckPermissionService;
import io.metersphere.service.ScheduleService; import io.metersphere.service.ScheduleService;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
@ -359,10 +361,12 @@ public class APITestController {
} }
@PostMapping(value = "/schedule/updateEnableByPrimyKey") @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 schedule = scheduleService.getSchedule(request.getTaskID());
schedule.setEnable(request.isEnable()); schedule.setEnable(request.isEnable());
apiAutomationService.updateSchedule(schedule); apiAutomationService.updateSchedule(schedule);
return schedule;
} }
@PostMapping(value = "/historicalDataUpgrade") @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.ApiScenario;
import io.metersphere.base.domain.ApiScenarioWithBLOBs; import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.base.domain.Schedule; import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.ApiRunMode; import io.metersphere.commons.constants.*;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.commons.constants.TriggerMode;
import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.Pager;
import io.metersphere.controller.request.ScheduleRequest; import io.metersphere.controller.request.ScheduleRequest;
import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest; import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
import io.metersphere.track.request.testplan.FileOperationRequest; import io.metersphere.track.request.testplan.FileOperationRequest;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -89,6 +87,7 @@ public class ApiAutomationController {
@PostMapping(value = "/create") @PostMapping(value = "/create")
@MsAuditLog(module = "api_automation", type = OperLogConstants.CREATE, title = "#request.name", content = "#msClass.getLogDetails(#request.id)", msClass = ApiAutomationService.class) @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) @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, public ApiScenario create(@RequestPart("request") SaveApiScenarioRequest request, @RequestPart(value = "bodyFiles", required = false) List<MultipartFile> bodyFiles,
@RequestPart(value = "scenarioFiles", required = false) List<MultipartFile> scenarioFiles) { @RequestPart(value = "scenarioFiles", required = false) List<MultipartFile> scenarioFiles) {
return apiAutomationService.create(request, bodyFiles, scenarioFiles); return apiAutomationService.create(request, bodyFiles, scenarioFiles);
@ -97,9 +96,10 @@ public class ApiAutomationController {
@PostMapping(value = "/update") @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) @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) @RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_READ_EDIT)
public void update(@RequestPart("request") SaveApiScenarioRequest request, @RequestPart(value = "bodyFiles", required = false) List<MultipartFile> bodyFiles, @SendNotice(taskType = NoticeConstants.TaskType.API_AUTOMATION_TASK, event = NoticeConstants.Event.UPDATE, mailTemplate = "api/AutomationUpdate", subject = "接口自动化通知")
@RequestPart(value = "scenarioFiles", required = false) List<MultipartFile> scenarioFiles) { public ApiScenario update(@RequestPart("request") SaveApiScenarioRequest request, @RequestPart(value = "bodyFiles", required = false) List<MultipartFile> bodyFiles,
apiAutomationService.update(request, bodyFiles, scenarioFiles); @RequestPart(value = "scenarioFiles", required = false) List<MultipartFile> scenarioFiles) {
return apiAutomationService.update(request, bodyFiles, scenarioFiles);
} }
@GetMapping("/delete/{id}") @GetMapping("/delete/{id}")
@ -123,12 +123,16 @@ public class ApiAutomationController {
@PostMapping("/removeToGc") @PostMapping("/removeToGc")
@MsAuditLog(module = "api_automation", type = OperLogConstants.GC, beforeEvent = "#msClass.getLogDetails(#ids)", msClass = ApiAutomationService.class) @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) { public void removeToGc(@RequestBody List<String> ids) {
apiAutomationService.removeToGc(ids); apiAutomationService.removeToGc(ids);
} }
@PostMapping("/removeToGcByBatch") @PostMapping("/removeToGcByBatch")
@MsAuditLog(module = "api_automation", type = OperLogConstants.BATCH_GC, beforeEvent = "#msClass.getLogDetails(#request.ids)", msClass = ApiAutomationService.class) @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) { public void removeToGcByBatch(@RequestBody ApiScenarioBatchRequest request) {
apiAutomationService.removeToGcByBatch(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.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs; import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import io.metersphere.base.domain.Schedule; import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants; import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants; import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.commons.json.JSONSchemaGenerator; 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.commons.utils.Pager;
import io.metersphere.controller.request.ScheduleRequest; import io.metersphere.controller.request.ScheduleRequest;
import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.service.CheckPermissionService; import io.metersphere.service.CheckPermissionService;
import io.metersphere.service.ScheduleService; import io.metersphere.service.ScheduleService;
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest; import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
@ -89,6 +91,7 @@ public class ApiDefinitionController {
@PostMapping(value = "/create", consumes = {"multipart/form-data"}) @PostMapping(value = "/create", consumes = {"multipart/form-data"})
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ_CREATE_API) @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) @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) { public ApiDefinitionWithBLOBs create(@RequestPart("request") SaveApiDefinitionRequest request, @RequestPart(value = "files", required = false) List<MultipartFile> bodyFiles) {
checkPermissionService.checkProjectOwner(request.getProjectId()); checkPermissionService.checkProjectOwner(request.getProjectId());
return apiDefinitionService.create(request, bodyFiles); return apiDefinitionService.create(request, bodyFiles);
@ -97,6 +100,7 @@ public class ApiDefinitionController {
@PostMapping(value = "/update", consumes = {"multipart/form-data"}) @PostMapping(value = "/update", consumes = {"multipart/form-data"})
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ_EDIT_API) @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) @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) { public ApiDefinitionWithBLOBs update(@RequestPart("request") SaveApiDefinitionRequest request, @RequestPart(value = "files", required = false) List<MultipartFile> bodyFiles) {
checkPermissionService.checkProjectOwner(request.getProjectId()); checkPermissionService.checkProjectOwner(request.getProjectId());
return apiDefinitionService.update(request, bodyFiles); return apiDefinitionService.update(request, bodyFiles);
@ -134,6 +138,8 @@ public class ApiDefinitionController {
@PostMapping("/removeToGc") @PostMapping("/removeToGc")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ_DELETE_API) @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ_DELETE_API)
@MsAuditLog(module = "api_definition", type = OperLogConstants.GC, beforeEvent = "#msClass.getLogDetails(#ids)", msClass = ApiDefinitionService.class) @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) { public void removeToGc(@RequestBody List<String> ids) {
apiDefinitionService.removeToGc(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.api.service.ApiTestCaseService;
import io.metersphere.base.domain.ApiTestCase; import io.metersphere.base.domain.ApiTestCase;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs; import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants; import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.Pager;
import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest; import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
import io.metersphere.track.service.TestPlanApiCaseService; import io.metersphere.track.service.TestPlanApiCaseService;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -81,12 +83,14 @@ public class ApiTestCaseController {
@PostMapping(value = "/create", consumes = {"multipart/form-data"}) @PostMapping(value = "/create", consumes = {"multipart/form-data"})
@MsAuditLog(module = "api_definition", type = OperLogConstants.CREATE, title = "#request.name", content = "#msClass.getLogDetails(#request)", msClass = ApiTestCaseService.class) @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) { public ApiTestCase create(@RequestPart("request") SaveApiTestCaseRequest request, @RequestPart(value = "files", required = false) List<MultipartFile> bodyFiles) {
return apiTestCaseService.create(request, bodyFiles); return apiTestCaseService.create(request, bodyFiles);
} }
@PostMapping(value = "/update", consumes = {"multipart/form-data"}) @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) @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) { public ApiTestCase update(@RequestPart("request") SaveApiTestCaseRequest request, @RequestPart(value = "files", required = false) List<MultipartFile> bodyFiles) {
return apiTestCaseService.update(request, bodyFiles); return apiTestCaseService.update(request, bodyFiles);
} }
@ -99,9 +103,11 @@ public class ApiTestCaseController {
@GetMapping("/deleteToGc/{id}") @GetMapping("/deleteToGc/{id}")
@MsAuditLog(module = "api_definition", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#id)", msClass = ApiTestCaseService.class) @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) { public void deleteToGc(@PathVariable String id) {
apiTestCaseService.deleteToGc(id); apiTestCaseService.deleteToGc(id);
} }
@PostMapping("/removeToGc") @PostMapping("/removeToGc")
@MsAuditLog(module = "api_definition", type = OperLogConstants.GC, beforeEvent = "#msClass.getLogDetails(#ids)", msClass = ApiTestCaseService.class) @MsAuditLog(module = "api_definition", type = OperLogConstants.GC, beforeEvent = "#msClass.getLogDetails(#ids)", msClass = ApiTestCaseService.class)
public void removeToGc(@RequestBody List<String> ids) { public void removeToGc(@RequestBody List<String> ids) {
@ -123,6 +129,7 @@ public class ApiTestCaseController {
public void editApiBathByParam(@RequestBody ApiTestBatchRequest request) { public void editApiBathByParam(@RequestBody ApiTestBatchRequest request) {
apiTestCaseService.editApiBathByParam(request); apiTestCaseService.editApiBathByParam(request);
} }
@PostMapping("/reduction") @PostMapping("/reduction")
@MsAuditLog(module = "api_definition", type = OperLogConstants.RESTORE, beforeEvent = "#msClass.getLogDetails(#request.ids)", content = "#msClass.getLogDetails(#request.ids)", msClass = ApiTestCaseService.class) @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) { public List<String> reduction(@RequestBody ApiTestBatchRequest request) {
@ -147,6 +154,7 @@ public class ApiTestCaseController {
public void deleteToGcByParam(@RequestBody ApiTestBatchRequest request) { public void deleteToGcByParam(@RequestBody ApiTestBatchRequest request) {
apiTestCaseService.deleteToGcByParam(request); apiTestCaseService.deleteToGcByParam(request);
} }
@PostMapping("/checkDeleteDatas") @PostMapping("/checkDeleteDatas")
public DeleteCheckResult checkDeleteDatas(@RequestBody ApiTestBatchRequest request) { public DeleteCheckResult checkDeleteDatas(@RequestBody ApiTestBatchRequest request) {
return apiTestCaseService.checkDeleteDatas(request); return apiTestCaseService.checkDeleteDatas(request);

View File

@ -42,6 +42,8 @@ public class SaveApiDefinitionRequest {
private String userId; private String userId;
private String followPeople;
private Schedule schedule; private Schedule schedule;
private String triggerMode; 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); checkNameExist(request);
checkScenarioNum(request); checkScenarioNum(request);
@ -367,6 +367,7 @@ public class ApiAutomationService {
apiScenarioReferenceIdService.saveByApiScenario(scenario); apiScenarioReferenceIdService.saveByApiScenario(scenario);
extScheduleMapper.updateNameByResourceID(request.getId(), request.getName());// 修改场景name同步到修改首页定时任务 extScheduleMapper.updateNameByResourceID(request.getId(), request.getName());// 修改场景name同步到修改首页定时任务
uploadFiles(request, bodyFiles, scenarioFiles); uploadFiles(request, bodyFiles, scenarioFiles);
return scenario;
} }
/** /**

View File

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

View File

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

View File

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

View File

@ -1673,6 +1673,76 @@ public class ApiDefinitionExample {
addCriterion("delete_user_id not between", value1, value2, "deleteUserId"); addCriterion("delete_user_id not between", value1, value2, "deleteUserId");
return (Criteria) this; 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 { public static class Criteria extends GeneratedCriteria {

View File

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

View File

@ -1243,6 +1243,76 @@ public class ApiTestCaseExample {
addCriterion("version not between", value1, value2, "version"); addCriterion("version not between", value1, value2, "version");
return (Criteria) this; 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 { public static class Criteria extends GeneratedCriteria {
@ -1337,4 +1407,4 @@ public class ApiTestCaseExample {
this(condition, value, secondValue, null); this(condition, value, secondValue, null);
} }
} }
} }

View File

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

View File

@ -973,6 +973,76 @@ public class LoadTestExample {
addCriterion("scenario_id not between", value1, value2, "scenarioId"); addCriterion("scenario_id not between", value1, value2, "scenarioId");
return (Criteria) this; 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 { public static class Criteria extends GeneratedCriteria {

View File

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

View File

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

View File

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

View File

@ -212,7 +212,7 @@
</sql> </sql>
<select id="list" resultType="io.metersphere.api.dto.definition.ApiDefinitionResult"> <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.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.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 api_definition.status, api_definition.user_id, api_definition.create_time, api_definition.update_time, project.name as
@ -236,7 +236,7 @@
</select> </select>
<select id="listByIds" resultType="io.metersphere.api.dto.definition.ApiDefinitionResult"> <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.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.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, 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 REVIEW_TASK = "REVIEW_TASK";
String DEFECT_TASK = "DEFECT_TASK"; String DEFECT_TASK = "DEFECT_TASK";
String SWAGGER_TASK = "SWAGGER_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 { interface Mode {
@ -28,13 +37,21 @@ public interface NoticeConstants {
String CREATE = "CREATE"; String CREATE = "CREATE";
String UPDATE = "UPDATE"; String UPDATE = "UPDATE";
String DELETE = "DELETE"; String DELETE = "DELETE";
String CASE_CREATE = "CASE_CREATE";
String CASE_UPDATE = "CASE_UPDATE";
String CASE_DELETE = "CASE_DELETE";
String COMMENT = "COMMENT"; String COMMENT = "COMMENT";
String IMPORT = "IMPORT"; String IMPORT = "IMPORT";
String CLOSE_SCHEDULE = "CLOSE_SCHEDULE";
} }
interface RelatedUser { interface RelatedUser {
String FOUNDER = "FOUNDER";//创建人 String CREATOR = "CREATOR";//创建人
String EXECUTOR = "EXECUTOR";//负责人(评审人 String EXECUTOR = "EXECUTOR";//负责人(评审人
String MAINTAINER = "MAINTAINER";//维护人 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()); return getContent(messageDetail.getTemplate(), noticeModel.getParamMap());
} }
// 处理 userIds 中包含的特殊值 // 处理 userIds 中包含的特殊值
List<String> realUserIds = getRealUserIds(messageDetail.getUserIds(), noticeModel.getRelatedUsers(), messageDetail.getEvent()); List<String> realUserIds = getRealUserIds(messageDetail.getUserIds(), noticeModel, messageDetail.getEvent());
messageDetail.setUserIds(realUserIds); messageDetail.setUserIds(realUserIds);
// 处理 WeCom Ding context // 处理 WeCom Ding context
@ -50,7 +50,7 @@ public abstract class AbstractNoticeSender implements NoticeSender {
default: default:
break; break;
} }
return context; return getContent(context, noticeModel.getParamMap());
} }
protected String getHtmlContext(MessageDetail messageDetail, NoticeModel noticeModel) { protected String getHtmlContext(MessageDetail messageDetail, NoticeModel noticeModel) {
@ -59,7 +59,7 @@ public abstract class AbstractNoticeSender implements NoticeSender {
return getContent(messageDetail.getTemplate(), noticeModel.getParamMap()); return getContent(messageDetail.getTemplate(), noticeModel.getParamMap());
} }
// 处理 userIds 中包含的特殊值 // 处理 userIds 中包含的特殊值
List<String> realUserIds = getRealUserIds(messageDetail.getUserIds(), noticeModel.getRelatedUsers(), messageDetail.getEvent()); List<String> realUserIds = getRealUserIds(messageDetail.getUserIds(), noticeModel, messageDetail.getEvent());
messageDetail.setUserIds(realUserIds); messageDetail.setUserIds(realUserIds);
// 处理 mail context // 处理 mail context
@ -70,6 +70,10 @@ public abstract class AbstractNoticeSender implements NoticeSender {
case NoticeConstants.Event.UPDATE: case NoticeConstants.Event.UPDATE:
case NoticeConstants.Event.DELETE: case NoticeConstants.Event.DELETE:
case NoticeConstants.Event.COMMENT: 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"); URL resource = this.getClass().getResource("/mail/" + noticeModel.getMailTemplate() + ".html");
context = IOUtils.toString(resource, StandardCharsets.UTF_8); context = IOUtils.toString(resource, StandardCharsets.UTF_8);
break; break;
@ -82,6 +86,8 @@ public abstract class AbstractNoticeSender implements NoticeSender {
context = IOUtils.toString(resource2, StandardCharsets.UTF_8); context = IOUtils.toString(resource2, StandardCharsets.UTF_8);
break; break;
default: default:
URL resource3 = this.getClass().getResource("/mail/" + noticeModel.getMailTemplate() + ".html");
context = IOUtils.toString(resource3, StandardCharsets.UTF_8);
break; break;
} }
} catch (IOException e) { } catch (IOException e) {
@ -103,7 +109,11 @@ public abstract class AbstractNoticeSender implements NoticeSender {
return template; 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<UserDetail> list = userService.queryTypeByIds(userIds);
List<String> phoneList = new ArrayList<>(); List<String> phoneList = new ArrayList<>();
list.forEach(u -> phoneList.add(u.getPhone())); list.forEach(u -> phoneList.add(u.getPhone()));
@ -111,7 +121,11 @@ public abstract class AbstractNoticeSender implements NoticeSender {
return phoneList.stream().distinct().collect(Collectors.toList()); 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<UserDetail> list = userService.queryTypeByIds(userIds);
List<String> phoneList = new ArrayList<>(); List<String> phoneList = new ArrayList<>();
list.forEach(u -> phoneList.add(u.getEmail())); list.forEach(u -> phoneList.add(u.getEmail()));
@ -119,24 +133,35 @@ public abstract class AbstractNoticeSender implements NoticeSender {
return phoneList.stream().distinct().collect(Collectors.toList()); 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<>(); List<String> toUserIds = new ArrayList<>();
Map<String, Object> paramMap = noticeModel.getParamMap();
for (String userId : userIds) { for (String userId : userIds) {
switch (userId) { switch (userId) {
case NoticeConstants.RelatedUser.EXECUTOR: case NoticeConstants.RelatedUser.EXECUTOR:
if (StringUtils.equals(NoticeConstants.Event.CREATE, event)) { if (StringUtils.equals(NoticeConstants.Event.CREATE, event)) {
toUserIds.addAll(relatedUsers); toUserIds.addAll(noticeModel.getRelatedUsers());
} }
break; break;
case NoticeConstants.RelatedUser.FOUNDER: case NoticeConstants.RelatedUser.CREATOR:
if (StringUtils.equals(NoticeConstants.Event.UPDATE, event) Object creator = paramMap.get("creator");
|| StringUtils.equals(NoticeConstants.Event.DELETE, event)) { if (creator != null) {
toUserIds.addAll(relatedUsers); toUserIds.add(creator.toString());
}
Object createUser = paramMap.get("createUser");
if (createUser != null) {
toUserIds.add(createUser.toString());
} }
break; break;
case NoticeConstants.RelatedUser.MAINTAINER: case NoticeConstants.RelatedUser.MAINTAINER:
if (StringUtils.equals(NoticeConstants.Event.COMMENT, event)) { 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; break;
default: default:

View File

@ -13,6 +13,10 @@ public class NoticeModel {
* 保存 测试id * 保存 测试id
*/ */
private String testId; 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 @Component
public class DingNoticeSender extends AbstractNoticeSender { 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(); List<String> userIds = messageDetail.getUserIds();
if (CollectionUtils.isEmpty(userIds)) { if (CollectionUtils.isEmpty(userIds)) {
return; return;
@ -28,7 +28,7 @@ public class DingNoticeSender extends AbstractNoticeSender {
text.setContent(context); text.setContent(context);
request.setText(text); request.setText(text);
OapiRobotSendRequest.At at = new OapiRobotSendRequest.At(); OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
List<String> phoneList = super.getUserPhones(userIds); List<String> phoneList = super.getUserPhones(noticeModel, userIds);
LogUtil.info("收件人地址: " + phoneList); LogUtil.info("收件人地址: " + phoneList);
at.setAtMobiles(phoneList); at.setAtMobiles(phoneList);
request.setAt(at); request.setAt(at);
@ -42,6 +42,6 @@ public class DingNoticeSender extends AbstractNoticeSender {
@Override @Override
public void send(MessageDetail messageDetail, NoticeModel noticeModel) { public void send(MessageDetail messageDetail, NoticeModel noticeModel) {
String context = super.getContext(messageDetail, 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("发件人地址" + javaMailSender.getUsername());
LogUtil.info("helper" + helper); LogUtil.info("helper" + helper);
helper.setSubject("MeterSphere " + noticeModel.getSubject()); 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]); String[] users = emails.toArray(new String[0]);
LogUtil.info("收件人地址: " + emails); LogUtil.info("收件人地址: " + emails);
helper.setText(context, true); helper.setText(context, true);

View File

@ -16,13 +16,13 @@ import java.util.List;
public class WeComNoticeSender extends AbstractNoticeSender { 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(); List<String> userIds = messageDetail.getUserIds();
if (CollectionUtils.isEmpty(userIds)) { if (CollectionUtils.isEmpty(userIds)) {
return; return;
} }
TextMessage message = new TextMessage(context); TextMessage message = new TextMessage(context);
List<String> phoneLists = super.getUserPhones(userIds); List<String> phoneLists = super.getUserPhones(noticeModel, userIds);
message.setMentionedMobileList(phoneLists); message.setMentionedMobileList(phoneLists);
try { try {
WxChatbotClient.send(messageDetail.getWebhook(), message); WxChatbotClient.send(messageDetail.getWebhook(), message);
@ -34,6 +34,6 @@ public class WeComNoticeSender extends AbstractNoticeSender {
@Override @Override
public void send(MessageDetail messageDetail, NoticeModel noticeModel) { public void send(MessageDetail messageDetail, NoticeModel noticeModel) {
String context = super.getContext(messageDetail, 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 com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.LoadTestReportLog; import io.metersphere.base.domain.LoadTestReportLog;
import io.metersphere.base.domain.LoadTestReportWithBLOBs; 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.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants; import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.dto.LogDetailDTO; import io.metersphere.dto.LogDetailDTO;
import io.metersphere.dto.ReportDTO; import io.metersphere.dto.ReportDTO;
import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.performance.base.*; import io.metersphere.performance.base.*;
import io.metersphere.performance.controller.request.DeleteReportRequest; import io.metersphere.performance.controller.request.DeleteReportRequest;
import io.metersphere.performance.controller.request.RenameReportRequest; import io.metersphere.performance.controller.request.RenameReportRequest;
import io.metersphere.performance.controller.request.ReportRequest; import io.metersphere.performance.controller.request.ReportRequest;
import io.metersphere.performance.dto.LoadTestExportJmx; import io.metersphere.performance.dto.LoadTestExportJmx;
import io.metersphere.performance.service.PerformanceReportService; import io.metersphere.performance.service.PerformanceReportService;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
@RestController @RestController
@RequestMapping(value = "performance/report") @RequestMapping(value = "performance/report")
@ -54,6 +51,8 @@ public class PerformanceReportController {
@PostMapping("/delete/{reportId}") @PostMapping("/delete/{reportId}")
@RequiresPermissions(PermissionConstants.PROJECT_PERFORMANCE_REPORT_READ_DELETE) @RequiresPermissions(PermissionConstants.PROJECT_PERFORMANCE_REPORT_READ_DELETE)
@MsAuditLog(module = "performance_test_report", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#reportId)", msClass = PerformanceReportService.class) @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) { public void deleteReport(@PathVariable String reportId) {
performanceReportService.deleteReport(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.FileMetadata;
import io.metersphere.base.domain.LoadTest; import io.metersphere.base.domain.LoadTest;
import io.metersphere.base.domain.Schedule; import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants; import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants; import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.PageUtils;
@ -17,6 +18,7 @@ import io.metersphere.dto.DashboardTestDTO;
import io.metersphere.dto.LoadTestDTO; import io.metersphere.dto.LoadTestDTO;
import io.metersphere.dto.ScheduleDao; import io.metersphere.dto.ScheduleDao;
import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.performance.dto.LoadTestExportJmx; import io.metersphere.performance.dto.LoadTestExportJmx;
import io.metersphere.performance.request.*; import io.metersphere.performance.request.*;
import io.metersphere.performance.service.PerformanceTestService; 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) @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) @RequiresPermissions(PermissionConstants.PROJECT_PERFORMANCE_TEST_READ_CREATE)
@CacheNode // 把监控节点缓存起来 @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("request") SaveTestPlanRequest request,
@RequestPart(value = "file", required = false) List<MultipartFile> files @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) @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) @RequiresPermissions(PermissionConstants.PROJECT_PERFORMANCE_TEST_READ_EDIT)
@CacheNode // 把监控节点缓存起来 @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("request") EditTestPlanRequest request,
@RequestPart(value = "file", required = false) List<MultipartFile> files @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) @MsAuditLog(module = "performance_test", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#request.id)", msClass = PerformanceTestService.class)
@RequiresPermissions(PermissionConstants.PROJECT_PERFORMANCE_TEST_READ_DELETE) @RequiresPermissions(PermissionConstants.PROJECT_PERFORMANCE_TEST_READ_DELETE)
@CacheNode // 把监控节点缓存起来 @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) { public void delete(@RequestBody DeleteTestPlanRequest request) {
checkPermissionService.checkPerformanceTestOwner(request.getId()); checkPermissionService.checkPerformanceTestOwner(request.getId());
performanceTestService.delete(request); performanceTestService.delete(request);

View File

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

View File

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

View File

@ -4,10 +4,12 @@ import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.Issues; import io.metersphere.base.domain.Issues;
import io.metersphere.base.domain.IssuesDao; import io.metersphere.base.domain.IssuesDao;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants; import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.Pager;
import io.metersphere.log.annotation.MsAuditLog; 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.PlatformUser;
import io.metersphere.track.issue.domain.zentao.ZentaoBuild; import io.metersphere.track.issue.domain.zentao.ZentaoBuild;
import io.metersphere.track.request.testcase.AuthUserIssueRequest; import io.metersphere.track.request.testcase.AuthUserIssueRequest;
@ -40,12 +42,16 @@ public class IssuesController {
@PostMapping("/add") @PostMapping("/add")
@MsAuditLog(module = "track_bug", type = OperLogConstants.CREATE, content = "#msClass.getLogDetails(#issuesRequest)", msClass = IssuesService.class) @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) { public void addIssues(@RequestBody IssuesUpdateRequest issuesRequest) {
issuesService.addIssues(issuesRequest); issuesService.addIssues(issuesRequest);
} }
@PostMapping("/update") @PostMapping("/update")
@MsAuditLog(module = "track_bug", type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#issuesRequest.id)", content = "#msClass.getLogDetails(#issuesRequest.id)", msClass = IssuesService.class) @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) { public void updateIssues(@RequestBody IssuesUpdateRequest issuesRequest) {
issuesService.updateIssues(issuesRequest); issuesService.updateIssues(issuesRequest);
} }
@ -88,6 +94,7 @@ public class IssuesController {
@GetMapping("/delete/{id}") @GetMapping("/delete/{id}")
@MsAuditLog(module = "track_bug", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#id)", msClass = IssuesService.class) @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) { public void delete(@PathVariable String id) {
issuesService.delete(id); issuesService.delete(id);
} }

View File

@ -1,11 +1,15 @@
package io.metersphere.track.controller; 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.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants; import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.track.dto.TestCaseCommentDTO; import io.metersphere.track.dto.TestCaseCommentDTO;
import io.metersphere.track.request.testreview.SaveCommentRequest; import io.metersphere.track.request.testreview.SaveCommentRequest;
import io.metersphere.track.service.TestCaseCommentService; import io.metersphere.track.service.TestCaseCommentService;
import io.metersphere.track.service.TestCaseService;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -23,9 +27,11 @@ public class TestCaseCommentController {
@PostMapping("/save") @PostMapping("/save")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_COMMENT) @RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_COMMENT)
@MsAuditLog(module = "track_test_case_review", type = OperLogConstants.CREATE, content = "#msClass.getLogDetails(#request.id)", msClass = TestCaseCommentService.class) @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()); request.setId(UUID.randomUUID().toString());
testCaseCommentService.saveComment(request); return testCaseCommentService.saveComment(request);
} }
@GetMapping("/list/{caseId}") @GetMapping("/list/{caseId}")
@ -43,7 +49,9 @@ public class TestCaseCommentController {
@PostMapping("/edit") @PostMapping("/edit")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_COMMENT) @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) @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) { // @SendNotice(taskType = NoticeConstants.TaskType.TRACK_TEST_CASE_TASK, target = "#targetClass.getTestCase(#request.caseId)", targetClass = TestCaseService.class,
testCaseCommentService.edit(request); // 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.automation.ApiScenarioRequest;
import io.metersphere.api.dto.definition.ApiTestCaseDTO; import io.metersphere.api.dto.definition.ApiTestCaseDTO;
import io.metersphere.api.dto.definition.ApiTestCaseRequest; 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.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants; import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.PageUtils;
@ -16,6 +21,7 @@ import io.metersphere.dto.LoadTestDTO;
import io.metersphere.dto.TestCaseTestDao; import io.metersphere.dto.TestCaseTestDao;
import io.metersphere.excel.domain.ExcelResponse; import io.metersphere.excel.domain.ExcelResponse;
import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.service.CheckPermissionService; import io.metersphere.service.CheckPermissionService;
import io.metersphere.service.FileService; import io.metersphere.service.FileService;
import io.metersphere.track.dto.TestCaseDTO; import io.metersphere.track.dto.TestCaseDTO;
@ -168,14 +174,18 @@ public class TestCaseController {
@PostMapping(value = "/add", consumes = {"multipart/form-data"}) @PostMapping(value = "/add", consumes = {"multipart/form-data"})
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_CASE_READ_CREATE) @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) @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()); request.setId(UUID.randomUUID().toString());
return testCaseService.save(request, files); return testCaseService.save(request, files);
} }
@PostMapping(value = "/edit", consumes = {"multipart/form-data"}) @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) @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); return testCaseService.edit(request, files);
} }
@ -194,6 +204,8 @@ public class TestCaseController {
@PostMapping("/deleteToGc/{testCaseId}") @PostMapping("/deleteToGc/{testCaseId}")
@MsAuditLog(module = "track_test_case", type = OperLogConstants.GC, beforeEvent = "#msClass.getLogDetails(#testCaseId)", msClass = TestCaseService.class) @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) { public int deleteToGC(@PathVariable String testCaseId) {
checkPermissionService.checkTestCaseOwner(testCaseId); checkPermissionService.checkTestCaseOwner(testCaseId);
return testCaseService.deleteTestCaseToGc(testCaseId); return testCaseService.deleteTestCaseToGc(testCaseId);
@ -204,26 +216,26 @@ public class TestCaseController {
@MsAuditLog(module = "track_test_case", type = OperLogConstants.IMPORT, project = "#projectId") @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) { public ExcelResponse testCaseImport(MultipartFile file, @PathVariable String projectId, @PathVariable String userId, @PathVariable String importType, HttpServletRequest request) {
checkPermissionService.checkProjectOwner(projectId); checkPermissionService.checkProjectOwner(projectId);
return testCaseService.testCaseImport(file, projectId, userId, importType,request); return testCaseService.testCaseImport(file, projectId, userId, importType, request);
} }
@PostMapping("/importIgnoreError/{projectId}/{userId}/{importType}") @PostMapping("/importIgnoreError/{projectId}/{userId}/{importType}")
@MsAuditLog(module = "track_test_case", type = OperLogConstants.IMPORT, project = "#projectId") @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) { public ExcelResponse testCaseImportIgnoreError(MultipartFile file, @PathVariable String projectId, @PathVariable String userId, @PathVariable String importType, HttpServletRequest request) {
checkPermissionService.checkProjectOwner(projectId); checkPermissionService.checkProjectOwner(projectId);
return testCaseService.testCaseImportIgnoreError(file, projectId, userId,importType, request); return testCaseService.testCaseImportIgnoreError(file, projectId, userId, importType, request);
} }
@GetMapping("/export/template/{projectId}/{importType}") @GetMapping("/export/template/{projectId}/{importType}")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_CASE_READ_EXPORT) @RequiresPermissions(PermissionConstants.PROJECT_TRACK_CASE_READ_EXPORT)
public void testCaseTemplateExport(@PathVariable String projectId,@PathVariable String importType,HttpServletResponse response) { public void testCaseTemplateExport(@PathVariable String projectId, @PathVariable String importType, HttpServletResponse response) {
testCaseService.testCaseTemplateExport(projectId,importType,response); testCaseService.testCaseTemplateExport(projectId, importType, response);
} }
@GetMapping("/export/xmindTemplate/{projectId}/{importType}") @GetMapping("/export/xmindTemplate/{projectId}/{importType}")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_CASE_READ_EXPORT) @RequiresPermissions(PermissionConstants.PROJECT_TRACK_CASE_READ_EXPORT)
public void xmindTemplate(@PathVariable String projectId,@PathVariable String importType,HttpServletResponse response) { public void xmindTemplate(@PathVariable String projectId, @PathVariable String importType, HttpServletResponse response) {
testCaseService.testCaseXmindTemplateExport(projectId,importType,response); testCaseService.testCaseXmindTemplateExport(projectId, importType, response);
} }
@PostMapping("/export/testcase") @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.Project;
import io.metersphere.base.domain.TestCaseReview; import io.metersphere.base.domain.TestCaseReview;
import io.metersphere.base.domain.User; import io.metersphere.base.domain.User;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants; import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants; import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils; import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.service.CheckPermissionService; import io.metersphere.service.CheckPermissionService;
import io.metersphere.track.dto.TestCaseReviewDTO; import io.metersphere.track.dto.TestCaseReviewDTO;
import io.metersphere.track.dto.TestReviewDTOWithMetric; import io.metersphere.track.dto.TestReviewDTOWithMetric;
@ -45,7 +47,8 @@ public class TestCaseReviewController {
@PostMapping("/save") @PostMapping("/save")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_CREATE) @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) @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()); reviewRequest.setId(UUID.randomUUID().toString());
return testCaseReviewService.saveTestCaseReview(reviewRequest); return testCaseReviewService.saveTestCaseReview(reviewRequest);
} }
@ -70,13 +73,16 @@ public class TestCaseReviewController {
@PostMapping("/edit") @PostMapping("/edit")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_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) @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); return testCaseReviewService.editCaseReview(testCaseReview);
} }
@GetMapping("/delete/{reviewId}") @GetMapping("/delete/{reviewId}")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_DELETE) @RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_DELETE)
@MsAuditLog(module = "track_test_case_review", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#reviewId)", msClass = TestCaseReviewService.class) @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) { public void deleteCaseReview(@PathVariable String reviewId) {
checkPermissionService.checkTestReviewOwner(reviewId); checkPermissionService.checkTestReviewOwner(reviewId);
testCaseReviewService.deleteCaseReview(reviewId); testCaseReviewService.deleteCaseReview(reviewId);
@ -117,6 +123,7 @@ public class TestCaseReviewController {
@PostMapping("/edit/status/{reviewId}") @PostMapping("/edit/status/{reviewId}")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_EDIT) @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) { public void editTestPlanStatus(@PathVariable String reviewId) {
checkPermissionService.checkTestReviewOwner(reviewId); checkPermissionService.checkTestReviewOwner(reviewId);
testCaseReviewService.editTestReviewStatus(reviewId); testCaseReviewService.editTestReviewStatus(reviewId);

View File

@ -3,15 +3,21 @@ package io.metersphere.track.controller;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page; import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper; 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.Project;
import io.metersphere.base.domain.Schedule;
import io.metersphere.base.domain.TestPlan; import io.metersphere.base.domain.TestPlan;
import io.metersphere.base.domain.TestPlanWithBLOBs; import io.metersphere.base.domain.TestPlanWithBLOBs;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants; import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants; import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.Pager;
import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.service.CheckPermissionService; import io.metersphere.service.CheckPermissionService;
import io.metersphere.service.ScheduleService;
import io.metersphere.track.dto.*; import io.metersphere.track.dto.*;
import io.metersphere.track.request.testcase.PlanCaseRelevanceRequest; import io.metersphere.track.request.testcase.PlanCaseRelevanceRequest;
import io.metersphere.track.request.testcase.QueryTestPlanRequest; import io.metersphere.track.request.testcase.QueryTestPlanRequest;
@ -40,6 +46,10 @@ public class TestPlanController {
TestPlanProjectService testPlanProjectService; TestPlanProjectService testPlanProjectService;
@Resource @Resource
CheckPermissionService checkPermissionService; CheckPermissionService checkPermissionService;
@Resource
private ScheduleService scheduleService;
@Resource
private ApiAutomationService apiAutomationService;
@PostMapping("/autoCheck/{testPlanId}") @PostMapping("/autoCheck/{testPlanId}")
public void autoCheck(@PathVariable String testPlanId) { public void autoCheck(@PathVariable String testPlanId) {
@ -87,17 +97,18 @@ public class TestPlanController {
@PostMapping("/add") @PostMapping("/add")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_PLAN_READ_CREATE) @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) @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()); testPlan.setId(UUID.randomUUID().toString());
return testPlanService.addTestPlan(testPlan); return testPlanService.addTestPlan(testPlan);
} }
@PostMapping("/edit") @PostMapping("/edit")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_PLAN_READ_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) @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) { @SendNotice(taskType = NoticeConstants.TaskType.TEST_PLAN_TASK, event = NoticeConstants.Event.UPDATE, mailTemplate = "track/TestPlanEnd", subject = "测试计划通知")
return testPlanService.editTestPlan(testPlanDTO, true); public TestPlan editTestPlan(@RequestBody TestPlanDTO testPlanDTO) {
return testPlanService.editTestPlan(testPlanDTO);
} }
@PostMapping("/edit/status/{planId}") @PostMapping("/edit/status/{planId}")
@ -111,6 +122,7 @@ public class TestPlanController {
@PostMapping("/delete/{testPlanId}") @PostMapping("/delete/{testPlanId}")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_PLAN_READ_DELETE) @RequiresPermissions(PermissionConstants.PROJECT_TRACK_PLAN_READ_DELETE)
@MsAuditLog(module = "track_test_plan", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#testPlanId)", msClass = TestPlanService.class) @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) { public int deleteTestPlan(@PathVariable String testPlanId) {
checkPermissionService.checkTestPlanOwner(testPlanId); checkPermissionService.checkTestPlanOwner(testPlanId);
return testPlanService.deleteTestPlan(testPlanId); return testPlanService.deleteTestPlan(testPlanId);
@ -194,12 +206,12 @@ public class TestPlanController {
} }
@GetMapping("/report/{planId}") @GetMapping("/report/{planId}")
public TestPlanSimpleReportDTO getReport(@PathVariable String planId){ public TestPlanSimpleReportDTO getReport(@PathVariable String planId) {
return testPlanService.getReport(planId); return testPlanService.getReport(planId);
} }
@GetMapping("/report/functional/result") @GetMapping("/report/functional/result")
public TestCaseReportStatusResultDTO getFunctionalResultReport(@PathVariable String planId){ public TestCaseReportStatusResultDTO getFunctionalResultReport(@PathVariable String planId) {
return testPlanService.getFunctionalResultReport(planId); return testPlanService.getFunctionalResultReport(planId);
} }
@ -207,4 +219,13 @@ public class TestPlanController {
public void editReport(@RequestBody TestPlanWithBLOBs testPlanWithBLOBs) { public void editReport(@RequestBody TestPlanWithBLOBs testPlanWithBLOBs) {
testPlanService.editReport(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.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.TestPlanReport; import io.metersphere.base.domain.TestPlanReport;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants; import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.ReportTriggerMode; import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils; import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.track.dto.TestPlanReportDTO; import io.metersphere.track.dto.TestPlanReportDTO;
import io.metersphere.track.request.report.QueryTestPlanReportRequest; import io.metersphere.track.request.report.QueryTestPlanReportRequest;
import io.metersphere.track.request.report.TestPlanReportSaveRequest; import io.metersphere.track.request.report.TestPlanReportSaveRequest;
@ -30,11 +32,13 @@ public class TestPlanReportController {
@Resource @Resource
private TestPlanReportService testPlanReportService; private TestPlanReportService testPlanReportService;
@PostMapping("/list/{goPage}/{pageSize}") @PostMapping("/list/{goPage}/{pageSize}")
public Pager<List<TestPlanReportDTO>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestPlanReportRequest request) { public Pager<List<TestPlanReportDTO>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestPlanReportRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true); Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, testPlanReportService.list(request)); return PageUtils.setPageInfo(page, testPlanReportService.list(request));
} }
@GetMapping("/getMetric/{planId}") @GetMapping("/getMetric/{planId}")
public TestPlanReportDTO getMetric(@PathVariable String planId) { public TestPlanReportDTO getMetric(@PathVariable String planId) {
return testPlanReportService.getMetric(planId); return testPlanReportService.getMetric(planId);
@ -56,6 +60,8 @@ public class TestPlanReportController {
@PostMapping("/delete") @PostMapping("/delete")
@MsAuditLog(module = "track_report", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#testPlanReportIdList)", msClass = TestPlanReportService.class) @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) { public void delete(@RequestBody List<String> testPlanReportIdList) {
testPlanReportService.delete(testPlanReportIdList); testPlanReportService.delete(testPlanReportIdList);
} }
@ -67,20 +73,20 @@ public class TestPlanReportController {
@GetMapping("/apiExecuteFinish/{planId}/{userId}") @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(); 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); 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}") @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 userId = SessionUtils.getUser().getId();
String reportId = UUID.randomUUID().toString(); 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); TestPlanReport report = testPlanReportService.genTestPlanReport(saveRequest);
testPlanReportService.countReportByTestPlanReportId(report.getId(),null, triggerMode,null); testPlanReportService.countReportByTestPlanReportId(report.getId(), null, triggerMode, null);
return "success"; return "success";
} }
} }

View File

@ -13,12 +13,10 @@ import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.user.SessionUser; import io.metersphere.commons.user.SessionUser;
import io.metersphere.commons.utils.*; import io.metersphere.commons.utils.*;
import io.metersphere.controller.request.IntegrationRequest; import io.metersphere.controller.request.IntegrationRequest;
import io.metersphere.i18n.Translator;
import io.metersphere.log.utils.ReflexObjectUtil; import io.metersphere.log.utils.ReflexObjectUtil;
import io.metersphere.log.vo.DetailColumn; import io.metersphere.log.vo.DetailColumn;
import io.metersphere.log.vo.OperatingLogDetails; import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.log.vo.track.TestPlanReference; import io.metersphere.log.vo.track.TestPlanReference;
import io.metersphere.notice.sender.NoticeModel;
import io.metersphere.notice.service.NoticeSendService; import io.metersphere.notice.service.NoticeSendService;
import io.metersphere.service.IntegrationService; import io.metersphere.service.IntegrationService;
import io.metersphere.service.IssueTemplateService; import io.metersphere.service.IssueTemplateService;
@ -90,7 +88,6 @@ public class IssuesService {
} }
public void addIssues(IssuesUpdateRequest issuesRequest) { public void addIssues(IssuesUpdateRequest issuesRequest) {
List<AbstractIssuePlatform> platformList = getUpdatePlatforms(issuesRequest); List<AbstractIssuePlatform> platformList = getUpdatePlatforms(issuesRequest);
platformList.forEach(platform -> { platformList.forEach(platform -> {
@ -108,27 +105,6 @@ public class IssuesService {
LogUtil.error("处理bug数量报错caseId: {}, message: {}", l, ExceptionUtils.getStackTrace(e)); 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); testCaseIssuesMapper.deleteByExample(example);
} }
public IssuesWithBLOBs get(String id) {
return issuesMapper.selectByPrimaryKey(id);
}
private static String getIssuesContext(SessionUser user, IssuesUpdateRequest issuesRequest, String type) { private static String getIssuesContext(SessionUser user, IssuesUpdateRequest issuesRequest, String type) {
String context = ""; String context = "";
if (StringUtils.equals(NoticeConstants.Event.CREATE, type)) { if (StringUtils.equals(NoticeConstants.Event.CREATE, type)) {
@ -476,7 +456,7 @@ public class IssuesService {
ClassLoader loader = Thread.currentThread().getContextClassLoader(); ClassLoader loader = Thread.currentThread().getContextClassLoader();
try { try {
Class clazz = loader.loadClass("io.metersphere.xpack.issue.azuredevops.AzureDevopsPlatform"); 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); AbstractIssuePlatform azureDevopsPlatform = (AbstractIssuePlatform) cons.newInstance(issuesRequest);
syncThirdPartyIssues(azureDevopsPlatform::syncIssues, project, azureDevopsIssues); syncThirdPartyIssues(azureDevopsPlatform::syncIssues, project, azureDevopsIssues);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {

View File

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

View File

@ -93,7 +93,7 @@ public class TestCaseReviewService {
private ApiDefinitionMapper apiDefinitionMapper; private ApiDefinitionMapper apiDefinitionMapper;
public String saveTestCaseReview(SaveTestCaseReviewRequest reviewRequest) { public TestCaseReview saveTestCaseReview(SaveTestCaseReviewRequest reviewRequest) {
checkCaseReviewExist(reviewRequest); checkCaseReviewExist(reviewRequest);
String reviewId = reviewRequest.getId(); String reviewId = reviewRequest.getId();
List<String> userIds = reviewRequest.getUserIds();//执行人 List<String> userIds = reviewRequest.getUserIds();//执行人
@ -115,19 +115,7 @@ public class TestCaseReviewService {
reviewRequest.setProjectId(SessionUtils.getCurrentProjectId()); reviewRequest.setProjectId(SessionUtils.getCurrentProjectId());
} }
testCaseReviewMapper.insert(reviewRequest); testCaseReviewMapper.insert(reviewRequest);
// 发送通知 return 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();
} }
//评审内容 //评审内容
@ -221,25 +209,12 @@ public class TestCaseReviewService {
return extTestCaseReviewMapper.listByWorkspaceId(currentWorkspaceId, SessionUtils.getUserId(), SessionUtils.getCurrentProjectId()); return extTestCaseReviewMapper.listByWorkspaceId(currentWorkspaceId, SessionUtils.getUserId(), SessionUtils.getCurrentProjectId());
} }
public String editCaseReview(SaveTestCaseReviewRequest testCaseReview) { public TestCaseReview editCaseReview(SaveTestCaseReviewRequest testCaseReview) {
editCaseReviewer(testCaseReview); editCaseReviewer(testCaseReview);
testCaseReview.setUpdateTime(System.currentTimeMillis()); testCaseReview.setUpdateTime(System.currentTimeMillis());
checkCaseReviewExist(testCaseReview); checkCaseReviewExist(testCaseReview);
testCaseReviewMapper.updateByPrimaryKeySelective(testCaseReview); testCaseReviewMapper.updateByPrimaryKeySelective(testCaseReview);
// 发送通知 return 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();
} }
private void editCaseReviewer(SaveTestCaseReviewRequest testCaseReview) { private void editCaseReviewer(SaveTestCaseReviewRequest testCaseReview) {
@ -284,31 +259,10 @@ public class TestCaseReviewService {
} }
public void deleteCaseReview(String reviewId) { public void deleteCaseReview(String reviewId) {
TestCaseReview testCaseReview = getTestReview(reviewId);
deleteCaseReviewProject(reviewId); deleteCaseReviewProject(reviewId);
deleteCaseReviewUsers(reviewId); deleteCaseReviewUsers(reviewId);
deleteCaseReviewTestCase(reviewId); deleteCaseReviewTestCase(reviewId);
testCaseReviewMapper.deleteByPrimaryKey(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) { private void deleteCaseReviewProject(String reviewId) {
@ -467,28 +421,6 @@ public class TestCaseReviewService {
} }
testCaseReview.setStatus(TestCaseReviewStatus.Completed.name()); testCaseReview.setStatus(TestCaseReviewStatus.Completed.name());
testCaseReviewMapper.updateByPrimaryKeySelective(testCaseReview); 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) { public List<TestReviewDTOWithMetric> listRelateAll(ReviewRelateRequest relateRequest) {

View File

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

View File

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

View File

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

View File

@ -40,4 +40,13 @@ CREATE TABLE `load_test_report_result_realtime`
DEFAULT CHARSET = utf8mb4 DEFAULT CHARSET = utf8mb4
COLLATE utf8mb4_general_ci; 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 '测试计划报告总结'; ALTER TABLE test_plan ADD report_summary TEXT NULL COMMENT '测试计划报告总结';

View File

@ -78,7 +78,7 @@
<table tableName="test_plan"/> <table tableName="test_plan"/>
<table tableName="test_case_test"/>--> <table tableName="test_case_test"/>-->
<!-- <table tableName="api_test_environment"></table>--> <!-- <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="custom_field"></table>-->
<!-- <table tableName="test_case"></table>--> <!-- <table tableName="test_case"></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> </head>
<body> <body>
<div> <div>
<p>${creator}发起了一个缺陷:${issuesName},请跟进</p> <p>${operator}创建了缺陷: ${title}</p>
</div> </div>
</body> </body>
</html> </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> </head>
<body> <body>
<div> <div>
<p style="text-align: left">${creator} 发起的:<br> <p style="text-align: left">${operator}更新了测试评审: ${name} <br>
${reviewName}<br>
计划开始时间是:${start}<br>
计划结束时间为:${end}<br>
${status}<br>
点击下面链接进入用例评审页面</p> 点击下面链接进入用例评审页面</p>
<a href="${url}/#/track/review/view">${url}/#/track/review/view</a> <a href="${url}/#/track/review/view">${url}/#/track/review/view</a>
</div> </div>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -40,12 +40,27 @@
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="8">
<el-form-item :label="$t('commons.tag')" prop="tag"> <el-form-item :label="$t('commons.tag')" prop="tag">
<ms-input-tag :currentScenario="basicForm" ref="tag"/> <ms-input-tag :currentScenario="basicForm" ref="tag"/>
</el-form-item> </el-form-item>
</el-col> </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-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea" <el-input class="ms-http-textarea"
v-model="basicForm.description" v-model="basicForm.description"
@ -136,4 +151,7 @@
</script> </script>
<style scoped> <style scoped>
.ms-http-textarea {
width: 100%;
}
</style> </style>

View File

@ -68,7 +68,22 @@
<ms-input-tag :currentScenario="httpForm" ref="tag"/> <ms-input-tag :currentScenario="httpForm" ref="tag"/>
</el-form-item> </el-form-item>
</el-col> </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-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea" <el-input class="ms-http-textarea"
v-model="httpForm.description" v-model="httpForm.description"

View File

@ -47,12 +47,27 @@
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="8">
<el-form-item :label="$t('commons.tag')" prop="tag"> <el-form-item :label="$t('commons.tag')" prop="tag">
<ms-input-tag :currentScenario="basicForm" ref="tag"/> <ms-input-tag :currentScenario="basicForm" ref="tag"/>
</el-form-item> </el-form-item>
</el-col> </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-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea" <el-input class="ms-http-textarea"
v-model="basicForm.description" v-model="basicForm.description"
@ -151,4 +166,7 @@
</script> </script>
<style scoped> <style scoped>
.ms-http-textarea {
width: 100%;
}
</style> </style>

View File

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

View File

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

View File

@ -1,38 +1,110 @@
<template> <template>
<div> <div v-loading="result.loading">
<el-alert <el-alert :closable="false"
title="Notice:" type="info">
type="info"
show-icon>
<template v-slot:default> <template v-slot:default>
{{ $t('organization.message.notes') }} <span v-html="$t('organization.message.notes')"></span>
</template> </template>
</el-alert> </el-alert>
<jenkins-notification :jenkins-receiver-options="jenkinsReceiverOptions"/> <div style="padding-top: 10px;"></div>
<test-plan-task-notification :test-plan-receiver-options="testPlanReceiverOptions"/> <el-collapse accordion class="task-notification">
<test-review-notification :review-receiver-options="reviewReceiverOptions"/> <el-collapse-item name="2">
<defect-task-notification :defect-receiver-options="defectReceiverOptions"/> <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> </div>
</template> </template>
<script> <script>
import {getCurrentOrganizationId, getCurrentUser} from "@/common/js/utils"; import {getCurrentOrganizationId, getCurrentUser} from "@/common/js/utils";
import JenkinsNotification from "@/business/components/settings/organization/components/JenkinsNotification"; import JenkinsNotification from "@/business/components/settings/organization/components/jenkins/JenkinsNotification";
import TestPlanTaskNotification from "@/business/components/settings/organization/components/TestPlanTaskNotification"; import TestPlanTaskNotification
import TestReviewNotification from "@/business/components/settings/organization/components/TestReviewNotification"; from "@/business/components/settings/organization/components/track/TestPlanTaskNotification";
import DefectTaskNotification from "@/business/components/settings/organization/components/DefectTaskNotification"; 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 MsContainer from "@/business/components/common/components/MsContainer";
import MsMainContainer from "@/business/components/common/components/MsMainContainer"; 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 { export default {
name: "TaskNotification", name: "TaskNotification",
components: { components: {
ApiHomeNotification,
PerformanceReportNotification,
PerformanceTestNotification,
ApiReportNotification,
ApiAutomationNotification,
ApiDefinitionNotification,
TrackReportNotification,
TestCaseNotification,
TrackHomeNotification,
HomeNotification,
DefectTaskNotification, TestReviewNotification, TestPlanTaskNotification, JenkinsNotification, MsContainer, DefectTaskNotification, TestReviewNotification, TestPlanTaskNotification, JenkinsNotification, MsContainer,
MsMainContainer, MsMainContainer,
}, },
data() { data() {
return { return {
jenkinsNoticeSize: 0,
apiNoticeSize: 0,
performanceNoticeSize: 0,
trackNoticeSize: 0,
jenkinsReceiverOptions: [], jenkinsReceiverOptions: [],
// //
testPlanReceiverOptions: [], testPlanReceiverOptions: [],
@ -40,7 +112,8 @@ export default {
reviewReceiverOptions: [], reviewReceiverOptions: [],
// //
defectReceiverOptions: [], defectReceiverOptions: [],
} result: {}
};
}, },
activated() { activated() {
@ -50,7 +123,7 @@ export default {
handleEdit(index, data) { handleEdit(index, data) {
data.isReadOnly = true; data.isReadOnly = true;
if (data.type === 'EMAIL') { if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly data.isReadOnly = !data.isReadOnly;
} }
}, },
currentUser: () => { currentUser: () => {
@ -63,16 +136,38 @@ export default {
organizationId: getCurrentOrganizationId() organizationId: getCurrentOrganizationId()
}; };
this.result = this.$post('user/org/member/list/all', param, response => { this.result = this.$post('user/org/member/list/all', param, response => {
this.jenkinsReceiverOptions = response.data this.jenkinsReceiverOptions = response.data;
this.reviewReceiverOptions = response.data this.reviewReceiverOptions = response.data;
this.defectReceiverOptions = response.data this.defectReceiverOptions = response.data;
this.testPlanReceiverOptions = 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> </script>
<style scoped> <style scoped>
.task-notification {
height: calc(100vh - 200px);
overflow: auto;
}
</style> </style>

View File

@ -2,8 +2,9 @@
<div> <div>
<el-row> <el-row>
<el-col :span="10"> <el-col :span="10">
<h3>{{ $t('organization.message.test_review_task_notice') }}</h3> <h5>接口自动化</h5>
<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') }} {{ $t('organization.message.create_new_notification') }}
</el-button> </el-button>
<el-popover <el-popover
@ -19,8 +20,9 @@
<el-popover <el-popover
placement="right-end" placement="right-end"
title="示例" title="示例"
width="600" width="400"
trigger="click"> trigger="click"
:content="robotTitle">
<ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/> <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"> <el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }} {{ $t('organization.message.robot_template') }}
@ -31,7 +33,7 @@
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
<el-table <el-table
:data="reviewTask" :data="defectTask"
class="tb-edit" class="tb-edit"
border border
:cell-style="rowClass" :cell-style="rowClass"
@ -40,10 +42,10 @@
<el-table-column :label="$t('schedule.event')" min-width="15%" prop="events"> <el-table-column :label="$t('schedule.event')" min-width="15%" prop="events">
<template slot-scope="scope"> <template slot-scope="scope">
<el-select v-model="scope.row.event" :placeholder="$t('organization.message.select_events')" size="mini" <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"> prop="event" :disabled="!scope.row.isSet">
<el-option <el-option
v-for="item in reviewTaskEventOptions" v-for="item in eventOptions"
:key="item.value" :key="item.value"
:label="item.label" :label="item.label"
:value="item.value"> :value="item.value">
@ -57,7 +59,7 @@
:placeholder="$t('commons.please_select')" :placeholder="$t('commons.please_select')"
style="width: 100%;" :disabled="!row.isSet"> style="width: 100%;" :disabled="!row.isSet">
<el-option <el-option
v-for="item in row.reviewReceiverOptions" v-for="item in row.receiverOptions"
:key="item.id" :key="item.id"
:label="item.name" :label="item.name"
:value="item.id"> :value="item.id">
@ -87,43 +89,49 @@
</el-table-column> </el-table-column>
<el-table-column :label="$t('commons.operating')" min-width="25%" prop="result"> <el-table-column :label="$t('commons.operating')" min-width="25%" prop="result">
<template v-slot:default="scope"> <template v-slot:default="scope">
<el-button <ms-tip-button
circle
type="success" type="success"
size="mini" size="mini"
v-if="scope.row.isSet" v-if="scope.row.isSet"
v-xpack v-xpack
@click="handleTemplate(scope.$index,scope.row)" @click="handleTemplate(scope.$index,scope.row)"
>{{ $t('organization.message.template') }} :tip="$t('organization.message.template')"
</el-button> icon="el-icon-tickets"/>
<el-button <ms-tip-button
circle
type="primary" type="primary"
size="mini" size="mini"
v-show="scope.row.isSet" v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)" @click="handleAddTask(scope.$index,scope.row)"
>{{ $t('commons.add') }} :tip="$t('commons.add')"
</el-button> icon="el-icon-check"/>
<el-button <ms-tip-button
circle
size="mini" size="mini"
v-show="scope.row.isSet" v-show="scope.row.isSet"
@click.native.prevent="removeRowTask(scope.$index,reviewTask)" @click="removeRowTask(scope.$index,defectTask)"
>{{ $t('commons.cancel') }} :tip="$t('commons.cancel')"
</el-button> icon="el-icon-refresh-left"/>
<el-button <ms-tip-button
el-button
circle
type="primary" type="primary"
size="mini" size="mini"
icon="el-icon-edit"
v-show="!scope.row.isSet" v-show="!scope.row.isSet"
:tip="$t('commons.edit')"
@click="handleEditTask(scope.$index,scope.row)" @click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']" v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
>{{ $t('commons.edit') }} <ms-tip-button
</el-button> circle
<el-button
type="danger" type="danger"
icon="el-icon-delete" icon="el-icon-delete"
size="mini" size="mini"
v-show="!scope.row.isSet" v-show="!scope.row.isSet"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']" @click="deleteRowTask(scope.$index,scope.row)"
@click.native.prevent="deleteRowTask(scope.$index,scope.row)" :tip="$t('commons.delete')"
></el-button> v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -136,19 +144,21 @@
<script> <script>
import {hasLicense} from "@/common/js/utils"; import {hasLicense} from "@/common/js/utils";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit"; 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 requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {}; const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
export default { export default {
name: "TestReviewNotification", name: "ApiAutomationNotification",
components: { components: {
MsTipButton,
MsCodeEdit, MsCodeEdit,
"NoticeTemplate": noticeTemplate.default "NoticeTemplate": noticeTemplate.default
}, },
props: { props: {
reviewReceiverOptions: { receiverOptions: {
type: Array type: Array
} }
}, },
@ -163,20 +173,13 @@ export default {
"</head>\n" + "</head>\n" +
"<body>\n" + "<body>\n" +
"<div>\n" + "<div>\n" +
" <p style=\"text-align: left\">${creator} 创建的:<br>\n" + " <p>${creator}创建了测试用例</p>\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" + "</div>\n" +
"</body>\n" + "</body>\n" +
"</html>", "</html>",
robotTitle: "【任务通知】:${creator} 创建的:${reviewName}待开始,计划开始时间是:${start}," + robotTitle: "【任务通知】:${creator}创建了测试用例",
"计划结束时间是:${end}请跟进!/ ${status}!点击下面链接进入测试评审页面${url}/#/track/review/view/${id}", defectTask: [{
reviewTask: [{ taskType: "defectTask",
taskType: "reviewTask",
event: "", event: "",
userIds: [], userIds: [],
type: [], type: [],
@ -185,29 +188,29 @@ export default {
identification: "", identification: "",
isReadOnly: false, isReadOnly: false,
}], }],
reviewTaskEventOptions: [ eventOptions: [
{value: 'CREATE', label: this.$t('commons.create')}, {value: 'CREATE', label: this.$t('commons.create')},
{value: 'UPDATE', label: this.$t('commons.update')}, {value: 'UPDATE', label: this.$t('commons.update')},
{value: 'DELETE', label: this.$t('commons.delete')}, {value: 'DELETE', label: this.$t('commons.delete')},
{value: 'COMMENT', label: this.$t('commons.comment')}
], ],
receiveTypeOptions: [ receiveTypeOptions: [
{value: 'EMAIL', label: this.$t('organization.message.mail')}, {value: 'EMAIL', label: this.$t('organization.message.mail')},
{value: 'NAIL_ROBOT', label: this.$t('organization.message.nail_robot')}, {value: 'NAIL_ROBOT', label: this.$t('organization.message.nail_robot')},
{value: 'WECHAT_ROBOT', label: this.$t('organization.message.enterprise_wechat_robot')}, {value: 'WECHAT_ROBOT', label: this.$t('organization.message.enterprise_wechat_robot')},
{value: 'LARK', label: this.$t('organization.message.lark')} {value: 'LARK', label: this.$t('organization.message.lark')}
], ],
}; };
}, },
methods: { methods: {
initForm() { initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => { this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.reviewTask = response.data; this.defectTask = response.data;
this.reviewTask.forEach(planTask => { //
this.handleReviewReceivers(planTask); this.$emit("noticeSize", {taskType: 'api', size: this.defectTask.length});
this.defectTask.forEach(planTask => {
this.handleReceivers(planTask);
}); });
}) });
}, },
handleEdit(index, data) { handleEdit(index, data) {
data.isReadOnly = true; data.isReadOnly = true;
@ -226,15 +229,16 @@ export default {
} }
}, },
handleAddTaskModel() { handleAddTaskModel() {
let Task = {}; let task = {};
Task.event = []; task.receiverOptions = this.receiverOptions;
Task.userIds = []; task.event = [];
Task.type = ''; task.userIds = [];
Task.webhook = ''; task.type = '';
Task.isSet = true; task.webhook = '';
Task.identification = ''; task.isSet = true;
Task.taskType = TASK_TYPE task.identification = '';
this.reviewTask.push(Task) task.taskType = TASK_TYPE;
this.defectTask.push(task);
}, },
handleAddTask(index, data) { handleAddTask(index, data) {
@ -258,11 +262,11 @@ export default {
this.result = this.$post("/notice/save/message/task", data, () => { this.result = this.$post("/notice/save/message/task", data, () => {
this.initForm(); this.initForm();
this.$success(this.$t('commons.save_success')); this.$success(this.$t('commons.save_success'));
}) });
}, },
removeRowTask(index, data) { // removeRowTask(index, data) { //
if (!data[index].identification) { if (!data[index].identification) {
data.splice(index, 1) data.splice(index, 1);
} else { } else {
data[index].isSet = false; data[index].isSet = false;
} }
@ -270,50 +274,59 @@ export default {
deleteRowTask(index, data) { // deleteRowTask(index, data) { //
this.result = this.$get("/notice/delete/message/" + data.identification, response => { this.result = this.$get("/notice/delete/message/" + data.identification, response => {
this.$success(this.$t('commons.delete_success')); this.$success(this.$t('commons.delete_success'));
this.initForm() this.initForm();
}) });
}, },
rowClass() { rowClass() {
return "text-align:center" return "text-align:center";
}, },
headClass() { headClass() {
return "text-align:center;background:'#ededed'" 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;
}, },
handleTemplate(index, row) { handleTemplate(index, row) {
if (hasLicense()) { if (hasLicense()) {
this.$refs.noticeTemplate.open(row); 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: { watch: {
reviewReceiverOptions(value) { receiverOptions(value) {
if (value && value.length > 0) { if (value && value.length > 0) {
this.initForm(); this.initForm();
} }
} }
} }
} };
</script> </script>
<style scoped> <style scoped>
@ -322,20 +335,6 @@ export default {
} }
.el-button { .el-button {
margin-left: 10px; 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> </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-row>
<el-col :span="10"> <el-col :span="10">
<h3>{{ $t('organization.message.jenkins_task_notification') }}</h3> <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') }} {{ $t('organization.message.create_new_notification') }}
</el-button> </el-button>
<el-popover <el-popover
@ -90,43 +91,49 @@
</el-table-column> </el-table-column>
<el-table-column :label="$t('commons.operating')" min-width="25%" prop="result"> <el-table-column :label="$t('commons.operating')" min-width="25%" prop="result">
<template v-slot:default="scope"> <template v-slot:default="scope">
<el-button <ms-tip-button
circle
type="success" type="success"
size="mini" size="mini"
v-if="scope.row.isSet" v-if="scope.row.isSet"
v-xpack v-xpack
@click="handleTemplate(scope.$index,scope.row)" @click="handleTemplate(scope.$index,scope.row)"
>{{ $t('organization.message.template') }} :tip="$t('organization.message.template')"
</el-button> icon="el-icon-tickets"/>
<el-button <ms-tip-button
circle
type="primary" type="primary"
size="mini" size="mini"
v-if="scope.row.isSet" v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)" @click="handleAddTask(scope.$index,scope.row)"
>{{ $t('commons.add') }} :tip="$t('commons.add')"
</el-button> icon="el-icon-check"/>
<el-button <ms-tip-button
circle
size="mini" size="mini"
v-if="scope.row.isSet" v-show="scope.row.isSet"
@click.native.prevent="removeRowTask(scope.$index,jenkinsTask)" @click="removeRowTask(scope.$index,jenkinsTask)"
>{{ $t('commons.cancel') }} :tip="$t('commons.cancel')"
</el-button> icon="el-icon-refresh-left"/>
<el-button <ms-tip-button
el-button
circle
type="primary" type="primary"
size="mini" 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)" @click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']" v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
>{{ $t('commons.edit') }} <ms-tip-button
</el-button> circle
<el-button
type="danger" type="danger"
icon="el-icon-delete" icon="el-icon-delete"
size="mini" size="mini"
v-show="!scope.row.isSet" v-show="!scope.row.isSet"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']" @click="deleteRowTask(scope.$index,scope.row)"
@click.native.prevent="deleteRowTask(scope.$index,scope.row)" :tip="$t('commons.delete')"
></el-button> v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -139,6 +146,7 @@
<script> <script>
import {hasLicense} from "@/common/js/utils"; import {hasLicense} from "@/common/js/utils";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit"; import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import MsTipButton from "@/business/components/common/components/MsTipButton";
const TASK_TYPE = 'JENKINS_TASK'; const TASK_TYPE = 'JENKINS_TASK';
@ -148,6 +156,7 @@ const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./
export default { export default {
name: "JenkinsNotification", name: "JenkinsNotification",
components: { components: {
MsTipButton,
MsCodeEdit, MsCodeEdit,
"NoticeTemplate": noticeTemplate.default "NoticeTemplate": noticeTemplate.default
}, },
@ -213,7 +222,7 @@ export default {
{value: 'WECHAT_ROBOT', label: this.$t('organization.message.enterprise_wechat_robot')}, {value: 'WECHAT_ROBOT', label: this.$t('organization.message.enterprise_wechat_robot')},
{value: 'LARK', label: this.$t('organization.message.lark')} {value: 'LARK', label: this.$t('organization.message.lark')}
], ],
} };
}, },
activated() { activated() {
this.initForm(); this.initForm();
@ -222,7 +231,9 @@ export default {
initForm() { initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => { this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.jenkinsTask = response.data; this.jenkinsTask = response.data;
}) //
this.$emit("noticeSize", {taskType: 'jenkins', size: this.jenkinsTask.length});
});
}, },
handleEdit(index, data) { handleEdit(index, data) {
data.isReadOnly = true; data.isReadOnly = true;
@ -239,8 +250,8 @@ export default {
Task.webhook = ''; Task.webhook = '';
Task.isSet = true; Task.isSet = true;
Task.identification = ''; Task.identification = '';
Task.taskType = TASK_TYPE Task.taskType = TASK_TYPE;
this.jenkinsTask.push(Task) this.jenkinsTask.push(Task);
}, },
handleAddTask(index, data) { handleAddTask(index, data) {
if (data.event && data.userIds.length > 0 && data.type) { if (data.event && data.userIds.length > 0 && data.type) {
@ -259,7 +270,7 @@ export default {
} }
}, },
handleEditTask(index, data) { handleEditTask(index, data) {
data.isSet = true data.isSet = true;
if (data.type === 'EMAIL') { if (data.type === 'EMAIL') {
data.isReadOnly = false; data.isReadOnly = false;
data.webhook = ''; data.webhook = '';
@ -271,11 +282,11 @@ export default {
this.result = this.$post("/notice/save/message/task", data, () => { this.result = this.$post("/notice/save/message/task", data, () => {
this.initForm(); this.initForm();
this.$success(this.$t('commons.save_success')); this.$success(this.$t('commons.save_success'));
}) });
}, },
removeRowTask(index, data) { // removeRowTask(index, data) { //
if (!data[index].identification) { if (!data[index].identification) {
data.splice(index, 1) data.splice(index, 1);
} else { } else {
data[parseInt(index)].isSet = false; data[parseInt(index)].isSet = false;
} }
@ -284,14 +295,14 @@ export default {
deleteRowTask(index, data) { // deleteRowTask(index, data) { //
this.result = this.$get("/notice/delete/message/" + data.identification, response => { this.result = this.$get("/notice/delete/message/" + data.identification, response => {
this.$success(this.$t('commons.delete_success')); this.$success(this.$t('commons.delete_success'));
this.initForm() this.initForm();
}) });
}, },
rowClass() { rowClass() {
return "text-align:center" return "text-align:center";
}, },
headClass() { headClass() {
return "text-align:center;background:'#ededed'" return "text-align:center;background:'#ededed'";
}, },
handleTemplate(index, row) { handleTemplate(index, row) {
if (hasLicense()) { if (hasLicense()) {
@ -299,7 +310,7 @@ export default {
} }
} }
} }
} };
</script> </script>
<style scoped> <style scoped>
@ -308,7 +319,7 @@ export default {
} }
.el-button { .el-button {
margin-left: 10px; margin-right: 10px;
} }
/deep/ .el-select .el-input.is-disabled .el-input__inner { /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> <div>
<el-row> <el-row>
<el-col :span="10"> <el-col :span="10">
<h3>{{ $t('organization.message.test_plan_task_notification') }}</h3> <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']"> <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') }} {{ $t('organization.message.create_new_notification') }}
</el-button> </el-button>
<el-popover <el-popover
@ -86,43 +87,49 @@
</el-table-column> </el-table-column>
<el-table-column :label="$t('commons.operating')" min-width="25%" prop="result"> <el-table-column :label="$t('commons.operating')" min-width="25%" prop="result">
<template v-slot:default="scope"> <template v-slot:default="scope">
<el-button <ms-tip-button
circle
type="success" type="success"
size="mini" size="mini"
v-if="scope.row.isSet" v-if="scope.row.isSet"
v-xpack v-xpack
@click="handleTemplate(scope.$index,scope.row)" @click="handleTemplate(scope.$index,scope.row)"
>{{ $t('organization.message.template') }} :tip="$t('organization.message.template')"
</el-button> icon="el-icon-tickets"/>
<el-button <ms-tip-button
circle
type="primary" type="primary"
size="mini" size="mini"
v-show="scope.row.isSet" v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)" @click="handleAddTask(scope.$index,scope.row)"
>{{ $t('commons.add') }} :tip="$t('commons.add')"
</el-button> icon="el-icon-check"/>
<el-button <ms-tip-button
circle
size="mini" size="mini"
v-show="scope.row.isSet" v-show="scope.row.isSet"
@click.native.prevent="removeRowTask(scope.$index,testCasePlanTask)" @click="removeRowTask(scope.$index,testCasePlanTask)"
>{{ $t('commons.cancel') }} :tip="$t('commons.cancel')"
</el-button> icon="el-icon-refresh-left"/>
<el-button <ms-tip-button
el-button
circle
type="primary" type="primary"
size="mini" size="mini"
icon="el-icon-edit"
v-show="!scope.row.isSet" v-show="!scope.row.isSet"
:tip="$t('commons.edit')"
@click="handleEditTask(scope.$index,scope.row)" @click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']" v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
>{{ $t('commons.edit') }} <ms-tip-button
</el-button> circle
<el-button
type="danger" type="danger"
icon="el-icon-delete" icon="el-icon-delete"
size="mini" size="mini"
v-show="!scope.row.isSet" v-show="!scope.row.isSet"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']" @click="deleteRowTask(scope.$index,scope.row)"
@click.native.prevent="deleteRowTask(scope.$index,scope.row)" :tip="$t('commons.delete')"
></el-button> v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -136,6 +143,7 @@
<script> <script>
import {hasLicense} from "@/common/js/utils"; import {hasLicense} from "@/common/js/utils";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit"; import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import MsTipButton from "@/business/components/common/components/MsTipButton";
const TASK_TYPE = 'TEST_PLAN_TASK'; const TASK_TYPE = 'TEST_PLAN_TASK';
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/); const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
@ -144,6 +152,7 @@ const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./
export default { export default {
name: "TestPlanTaskNotification", name: "TestPlanTaskNotification",
components: { components: {
MsTipButton,
MsCodeEdit, MsCodeEdit,
"NoticeTemplate": noticeTemplate.default "NoticeTemplate": noticeTemplate.default
}, },
@ -189,7 +198,10 @@ export default {
otherEventOptions: [ otherEventOptions: [
{value: 'CREATE', label: this.$t('commons.create')}, {value: 'CREATE', label: this.$t('commons.create')},
{value: 'UPDATE', label: this.$t('commons.update')}, {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: [ receiveTypeOptions: [
{value: 'EMAIL', label: this.$t('organization.message.mail')}, {value: 'EMAIL', label: this.$t('organization.message.mail')},
@ -203,20 +215,22 @@ export default {
initForm() { initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => { this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.testCasePlanTask = response.data; this.testCasePlanTask = response.data;
//
this.$emit("noticeSize", {taskType: 'track', size: this.testCasePlanTask.length});
this.testCasePlanTask.forEach(planTask => { this.testCasePlanTask.forEach(planTask => {
this.handleTestPlanReceivers(planTask); this.handleTestPlanReceivers(planTask);
}); });
}) });
}, },
handleEdit(index, data) { handleEdit(index, data) {
data.isReadOnly = true; data.isReadOnly = true;
if (data.type === 'EMAIL') { if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly data.isReadOnly = !data.isReadOnly;
data.webhook = ''; data.webhook = '';
} }
}, },
handleEditTask(index, data) { handleEditTask(index, data) {
data.isSet = true data.isSet = true;
if (data.type === 'EMAIL') { if (data.type === 'EMAIL') {
data.isReadOnly = false; data.isReadOnly = false;
data.webhook = ''; data.webhook = '';
@ -232,8 +246,8 @@ export default {
Task.webhook = ''; Task.webhook = '';
Task.isSet = true; Task.isSet = true;
Task.identification = ''; Task.identification = '';
Task.taskType = TASK_TYPE Task.taskType = TASK_TYPE;
this.testCasePlanTask.push(Task) this.testCasePlanTask.push(Task);
}, },
handleAddTask(index, data) { handleAddTask(index, data) {
@ -253,41 +267,45 @@ export default {
} }
}, },
addTask(data) { addTask(data) {
data.isSet = false data.isSet = false;
this.result = this.$post("/notice/save/message/task", data, () => { this.result = this.$post("/notice/save/message/task", data, () => {
this.initForm() this.initForm();
this.$success(this.$t('commons.save_success')); this.$success(this.$t('commons.save_success'));
}) });
}, },
removeRowTask(index, data) { // removeRowTask(index, data) { //
if (!data[index].identification) { if (!data[index].identification) {
data.splice(index, 1) data.splice(index, 1);
} else { } else {
data[index].isSet = false data[index].isSet = false;
} }
}, },
deleteRowTask(index, data) { // deleteRowTask(index, data) { //
this.result = this.$get("/notice/delete/message/" + data.identification, response => { this.result = this.$get("/notice/delete/message/" + data.identification, response => {
this.$success(this.$t('commons.delete_success')); this.$success(this.$t('commons.delete_success'));
this.initForm() this.initForm();
}) });
}, },
rowClass() { rowClass() {
return "text-align:center" return "text-align:center";
}, },
headClass() { headClass() {
return "text-align:center;background:'#ededed'" return "text-align:center;background:'#ededed'";
}, },
handleTestPlanReceivers(row) { handleTestPlanReceivers(row) {
let testPlanReceivers = JSON.parse(JSON.stringify(this.testPlanReceiverOptions)); let testPlanReceivers = JSON.parse(JSON.stringify(this.testPlanReceiverOptions));
switch (row.event) { switch (row.event) {
case "CREATE": 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; break;
case "UPDATE": case "UPDATE":
case "DELETE": case "DELETE":
case "COMMENT": 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; break;
default: default:
break; break;
@ -307,7 +325,7 @@ export default {
} }
} }
} }
} };
</script> </script>
<style scoped> <style scoped>
@ -316,7 +334,7 @@ export default {
} }
.el-button { .el-button {
margin-left: 10px; margin-right: 10px;
} }
/deep/ .el-select .el-input.is-disabled .el-input__inner { /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> <div>
<el-row> <el-row>
<el-col :span="10"> <el-col :span="10">
<h3>{{ $t('organization.message.defect_task_notification') }}</h3> <h5>报告</h5>
<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') }} {{ $t('organization.message.create_new_notification') }}
</el-button> </el-button>
<el-popover <el-popover
@ -41,9 +42,10 @@
<el-table-column :label="$t('schedule.event')" min-width="15%" prop="events"> <el-table-column :label="$t('schedule.event')" min-width="15%" prop="events">
<template slot-scope="scope"> <template slot-scope="scope">
<el-select v-model="scope.row.event" :placeholder="$t('organization.message.select_events')" size="mini" <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"> prop="event" :disabled="!scope.row.isSet">
<el-option <el-option
v-for="item in defectEventOptions" v-for="item in eventOptions"
:key="item.value" :key="item.value"
:label="item.label" :label="item.label"
:value="item.value"> :value="item.value">
@ -57,7 +59,7 @@
:placeholder="$t('commons.please_select')" :placeholder="$t('commons.please_select')"
style="width: 100%;" :disabled="!row.isSet"> style="width: 100%;" :disabled="!row.isSet">
<el-option <el-option
v-for="item in defectReceiverOptions" v-for="item in row.receiverOptions"
:key="item.id" :key="item.id"
:label="item.name" :label="item.name"
:value="item.id"> :value="item.id">
@ -87,43 +89,49 @@
</el-table-column> </el-table-column>
<el-table-column :label="$t('commons.operating')" min-width="25%" prop="result"> <el-table-column :label="$t('commons.operating')" min-width="25%" prop="result">
<template v-slot:default="scope"> <template v-slot:default="scope">
<el-button <ms-tip-button
circle
type="success" type="success"
size="mini" size="mini"
v-if="scope.row.isSet" v-if="scope.row.isSet"
v-xpack v-xpack
@click="handleTemplate(scope.$index,scope.row)" @click="handleTemplate(scope.$index,scope.row)"
>{{ $t('organization.message.template') }} :tip="$t('organization.message.template')"
</el-button> icon="el-icon-tickets"/>
<el-button <ms-tip-button
circle
type="primary" type="primary"
size="mini" size="mini"
v-show="scope.row.isSet" v-show="scope.row.isSet"
@click="handleAddTask(scope.$index,scope.row)" @click="handleAddTask(scope.$index,scope.row)"
>{{ $t('commons.add') }} :tip="$t('commons.add')"
</el-button> icon="el-icon-check"/>
<el-button <ms-tip-button
circle
size="mini" size="mini"
v-show="scope.row.isSet" v-show="scope.row.isSet"
@click.native.prevent="removeRowTask(scope.$index,defectTask)" @click="removeRowTask(scope.$index,defectTask)"
>{{ $t('commons.cancel') }} :tip="$t('commons.cancel')"
</el-button> icon="el-icon-refresh-left"/>
<el-button <ms-tip-button
el-button
circle
type="primary" type="primary"
size="mini" size="mini"
icon="el-icon-edit"
v-show="!scope.row.isSet" v-show="!scope.row.isSet"
:tip="$t('commons.edit')"
@click="handleEditTask(scope.$index,scope.row)" @click="handleEditTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']" v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
>{{ $t('commons.edit') }} <ms-tip-button
</el-button> circle
<el-button
type="danger" type="danger"
icon="el-icon-delete" icon="el-icon-delete"
size="mini" size="mini"
v-show="!scope.row.isSet" v-show="!scope.row.isSet"
@click="deleteRowTask(scope.$index,scope.row)" @click="deleteRowTask(scope.$index,scope.row)"
v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']" :tip="$t('commons.delete')"
></el-button> v-permission="['ORGANIZATION_MESSAGE:READ+EDIT']"/>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -136,19 +144,21 @@
<script> <script>
import {hasLicense} from "@/common/js/utils"; import {hasLicense} from "@/common/js/utils";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit"; 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 requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {}; const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
export default { export default {
name: "DefectTaskNotification", name: "TrackReportNotification",
components: { components: {
MsTipButton,
MsCodeEdit, MsCodeEdit,
"NoticeTemplate": noticeTemplate.default "NoticeTemplate": noticeTemplate.default
}, },
props: { props: {
defectReceiverOptions: { receiverOptions: {
type: Array type: Array
} }
}, },
@ -163,7 +173,7 @@ export default {
"</head>\n" + "</head>\n" +
"<body>\n" + "<body>\n" +
"<div>\n" + "<div>\n" +
" <p>${creator}发起了一个缺陷:${issuesName},请跟进</p>\n" + " <p>${creator}关闭了定时任务</p>\n" +
"</div>\n" + "</div>\n" +
"</body>\n" + "</body>\n" +
"</html>", "</html>",
@ -178,36 +188,38 @@ export default {
identification: "", identification: "",
isReadOnly: false, isReadOnly: false,
}], }],
defectEventOptions: [ eventOptions: [
{value: 'CREATE', label: this.$t('commons.create')}, {value: 'DELETE', label: this.$t('commons.delete')},
], ],
receiveTypeOptions: [ receiveTypeOptions: [
{value: 'EMAIL', label: this.$t('organization.message.mail')}, {value: 'EMAIL', label: this.$t('organization.message.mail')},
{value: 'NAIL_ROBOT', label: this.$t('organization.message.nail_robot')}, {value: 'NAIL_ROBOT', label: this.$t('organization.message.nail_robot')},
{value: 'WECHAT_ROBOT', label: this.$t('organization.message.enterprise_wechat_robot')}, {value: 'WECHAT_ROBOT', label: this.$t('organization.message.enterprise_wechat_robot')},
{value: 'LARK', label: this.$t('organization.message.lark')} {value: 'LARK', label: this.$t('organization.message.lark')}
], ],
}; };
}, },
activated() {
this.initForm()
},
methods: { methods: {
initForm() { initForm() {
this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => { this.result = this.$get('/notice/search/message/type/' + TASK_TYPE, response => {
this.defectTask = response.data; this.defectTask = response.data;
}) //
this.$emit("noticeSize", {taskType: 'track', size: this.defectTask.length});
this.defectTask.forEach(planTask => {
this.handleReceivers(planTask);
});
});
}, },
handleEdit(index, data) { handleEdit(index, data) {
data.isReadOnly = true; data.isReadOnly = true;
if (data.type === 'EMAIL') { if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly data.isReadOnly = !data.isReadOnly;
data.webhook = ''; data.webhook = '';
} }
}, },
handleEditTask(index, data) { handleEditTask(index, data) {
data.isSet = true data.isSet = true;
if (data.type === 'EMAIL') { if (data.type === 'EMAIL') {
data.isReadOnly = false; data.isReadOnly = false;
data.webhook = ''; data.webhook = '';
@ -223,8 +235,8 @@ export default {
Task.webhook = ''; Task.webhook = '';
Task.isSet = true; Task.isSet = true;
Task.identification = ''; Task.identification = '';
Task.taskType = TASK_TYPE Task.taskType = TASK_TYPE;
this.defectTask.push(Task) this.defectTask.push(Task);
}, },
handleAddTask(index, data) { handleAddTask(index, data) {
@ -244,61 +256,67 @@ export default {
} }
}, },
addTask(data) { addTask(data) {
data.isSet = false data.isSet = false;
this.result = this.$post("/notice/save/message/task", data, () => { this.result = this.$post("/notice/save/message/task", data, () => {
this.initForm() this.initForm();
this.$success(this.$t('commons.save_success')); this.$success(this.$t('commons.save_success'));
}) });
}, },
removeRowTask(index, data) { // removeRowTask(index, data) { //
if (!data[index].identification) { if (!data[index].identification) {
data.splice(index, 1) data.splice(index, 1);
} else { } else {
data[index].isSet = false data[index].isSet = false;
} }
}, },
deleteRowTask(index, data) { // deleteRowTask(index, data) { //
this.result = this.$get("/notice/delete/message/" + data.identification, response => { this.result = this.$get("/notice/delete/message/" + data.identification, response => {
this.$success(this.$t('commons.delete_success')); this.$success(this.$t('commons.delete_success'));
this.initForm() this.initForm();
}) });
}, },
rowClass() { rowClass() {
return "text-align:center" return "text-align:center";
}, },
headClass() { headClass() {
return "text-align:center;background:'#ededed'" return "text-align:center;background:'#ededed'";
}, },
handleTemplate(index, row) { handleTemplate(index, row) {
if (hasLicense()) { if (hasLicense()) {
this.$refs.noticeTemplate.open(row); 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> </script>
<style scoped> <style scoped>
.el-row { .el-row {
margin-bottom: 10px; margin-bottom: 10px;
} }
.el-button { .el-button {
margin-left: 10px; 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> </style>

View File

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

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