refactor(系统设置): 优化任务中心

This commit is contained in:
wxg0103 2024-04-11 14:39:23 +08:00 committed by 刘瑞斌
parent dbde710cbd
commit adc7599c66
33 changed files with 928 additions and 194 deletions

View File

@ -430,4 +430,6 @@ api_scenario_step.name.not_blank=步骤名称不能为空
api_scenario_step.resource_num.length_range=资源编号长度必须在1-50之间 api_scenario_step.resource_num.length_range=资源编号长度必须在1-50之间
tags_size_large_than=标签数量超过{0}个 tags_size_large_than=标签数量超过{0}个
no_permission_to_resource=无操作资源的权限
api_scenario_circular_reference_error=场景存在循环引用 api_scenario_circular_reference_error=场景存在循环引用

View File

@ -437,4 +437,6 @@ api_scenario.environment_id.length_range=Environment ID length must be between 0
api_report_default_env=Default environment api_report_default_env=Default environment
tags_size_large_than=The number of tags cannot exceed 10 tags_size_large_than=The number of tags cannot exceed 10
no_permission_to_resource=No permission to access the resource
api_scenario_circular_reference_error=There are circular references to the scenario api_scenario_circular_reference_error=There are circular references to the scenario

View File

@ -405,4 +405,6 @@ api_scenario.environment_id.length_range=环境ID长度必须在0-50之间
api_report_default_env=默认环境 api_report_default_env=默认环境
tags_size_large_than=标签数量超过{0}个 tags_size_large_than=标签数量超过{0}个
no_permission_to_resource=没有权限访问该资源
api_scenario_circular_reference_error=场景存在循环引用 api_scenario_circular_reference_error=场景存在循环引用

View File

@ -404,4 +404,6 @@ api_scenario.environment_id.length_range=環境ID長度必須在0-50之間
api_report_default_env=默认環境 api_report_default_env=默认環境
tags_size_large_than=標籤數量不能超過{max} tags_size_large_than=標籤數量不能超過{max}
no_permission_to_resource=無權限訪問資源
api_scenario_circular_reference_error=場景存在循環引用 api_scenario_circular_reference_error=場景存在循環引用

View File

@ -2,6 +2,9 @@ package io.metersphere.api.controller;
import io.metersphere.api.service.ApiTaskCenterService; import io.metersphere.api.service.ApiTaskCenterService;
import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.TaskCenterResourceType;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.taskcenter.TaskCenterDTO; import io.metersphere.system.dto.taskcenter.TaskCenterDTO;
import io.metersphere.system.dto.taskcenter.request.TaskCenterBatchRequest; import io.metersphere.system.dto.taskcenter.request.TaskCenterBatchRequest;
import io.metersphere.system.dto.taskcenter.request.TaskCenterPageRequest; import io.metersphere.system.dto.taskcenter.request.TaskCenterPageRequest;
@ -15,7 +18,9 @@ import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* @author: LAN * @author: LAN
@ -30,10 +35,13 @@ public class ApiTaskCenterController {
@Resource @Resource
private ApiTaskCenterService apiTaskCenterService; private ApiTaskCenterService apiTaskCenterService;
private static final String PROJECT = "project";
private static final String ORG = "org";
private static final String SYSTEM = "system";
@PostMapping("/api/project/real-time/page") @PostMapping("/api/project/real-time/page")
@Operation(summary = "项目-任务中心-接口用例/场景-实时任务列表") @Operation(summary = "项目-任务中心-接口用例/场景-实时任务列表")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ)
public Pager<List<TaskCenterDTO>> projectList(@Validated @RequestBody TaskCenterPageRequest request) { public Pager<List<TaskCenterDTO>> projectList(@Validated @RequestBody TaskCenterPageRequest request) {
return apiTaskCenterService.getProjectPage(request, SessionUtils.getCurrentProjectId()); return apiTaskCenterService.getProjectPage(request, SessionUtils.getCurrentProjectId());
} }
@ -54,36 +62,36 @@ public class ApiTaskCenterController {
@PostMapping("/api/system/stop") @PostMapping("/api/system/stop")
@Operation(summary = "系统-任务中心-接口用例/场景-停止任务") @Operation(summary = "系统-任务中心-接口用例/场景-停止任务")
@RequiresPermissions(PermissionConstants.SYSTEM_TASK_CENTER_READ)
public void systemStop(@Validated @RequestBody TaskCenterBatchRequest request) { public void systemStop(@Validated @RequestBody TaskCenterBatchRequest request) {
hasPermission(SYSTEM, request.getModuleType());
apiTaskCenterService.systemStop(request, SessionUtils.getUserId()); apiTaskCenterService.systemStop(request, SessionUtils.getUserId());
} }
@PostMapping("/api/org/stop") @PostMapping("/api/org/stop")
@Operation(summary = "组织-任务中心-接口用例/场景-停止任务") @Operation(summary = "组织-任务中心-接口用例/场景-停止任务")
@RequiresPermissions(PermissionConstants.ORGANIZATION_TASK_CENTER_READ_STOP)
public void orgStop(@Validated @RequestBody TaskCenterBatchRequest request) { public void orgStop(@Validated @RequestBody TaskCenterBatchRequest request) {
hasPermission(ORG, request.getModuleType());
apiTaskCenterService.orgStop(request, SessionUtils.getCurrentOrganizationId(), SessionUtils.getUserId()); apiTaskCenterService.orgStop(request, SessionUtils.getCurrentOrganizationId(), SessionUtils.getUserId());
} }
@PostMapping("/api/project/stop") @PostMapping("/api/project/stop")
@Operation(summary = "项目-任务中心-接口用例/场景-停止任务") @Operation(summary = "项目-任务中心-接口用例/场景-停止任务")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ)
public void projectStop(@Validated @RequestBody TaskCenterBatchRequest request) { public void projectStop(@Validated @RequestBody TaskCenterBatchRequest request) {
hasPermission(PROJECT, request.getModuleType());
apiTaskCenterService.projectStop(request, SessionUtils.getCurrentProjectId(), SessionUtils.getUserId()); apiTaskCenterService.projectStop(request, SessionUtils.getCurrentProjectId(), SessionUtils.getUserId());
} }
@GetMapping("/api/project/stop/{moduleType}/{id}") @GetMapping("/api/project/stop/{moduleType}/{id}")
@Operation(summary = "项目-任务中心-接口用例/场景-停止任务") @Operation(summary = "项目-任务中心-接口用例/场景-停止任务")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ)
public void stopById(@PathVariable String moduleType, @PathVariable String id) { public void stopById(@PathVariable String moduleType, @PathVariable String id) {
hasPermission(PROJECT, moduleType);
apiTaskCenterService.stopById(moduleType, id, SessionUtils.getUserId(), OperationLogModule.PROJECT_MANAGEMENT_TASK_CENTER, "/task/center/api/project/stop"); apiTaskCenterService.stopById(moduleType, id, SessionUtils.getUserId(), OperationLogModule.PROJECT_MANAGEMENT_TASK_CENTER, "/task/center/api/project/stop");
} }
@GetMapping("/api/org/stop/{moduleType}/{id}") @GetMapping("/api/org/stop/{moduleType}/{id}")
@Operation(summary = "组织-任务中心-接口用例/场景-停止任务") @Operation(summary = "组织-任务中心-接口用例/场景-停止任务")
@RequiresPermissions(PermissionConstants.ORGANIZATION_TASK_CENTER_READ_STOP)
public void stopOrgById(@PathVariable String moduleType, @PathVariable String id) { public void stopOrgById(@PathVariable String moduleType, @PathVariable String id) {
hasPermission(ORG, moduleType);
apiTaskCenterService.stopById(moduleType, id, SessionUtils.getUserId(), OperationLogModule.SETTING_ORGANIZATION_TASK_CENTER, "/task/center/api/org/stop"); apiTaskCenterService.stopById(moduleType, id, SessionUtils.getUserId(), OperationLogModule.SETTING_ORGANIZATION_TASK_CENTER, "/task/center/api/org/stop");
} }
@ -91,8 +99,34 @@ public class ApiTaskCenterController {
@Operation(summary = "系统-任务中心-接口用例/场景-停止任务") @Operation(summary = "系统-任务中心-接口用例/场景-停止任务")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ) @RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ)
public void stopSystemById(@PathVariable String moduleType,@PathVariable String id) { public void stopSystemById(@PathVariable String moduleType,@PathVariable String id) {
hasPermission(SYSTEM, moduleType);
apiTaskCenterService.stopById(moduleType ,id, SessionUtils.getUserId(), OperationLogModule.SETTING_SYSTEM_TASK_CENTER, "/task/center/api/system/stop"); apiTaskCenterService.stopById(moduleType ,id, SessionUtils.getUserId(), OperationLogModule.SETTING_SYSTEM_TASK_CENTER, "/task/center/api/system/stop");
} }
private void hasPermission(String type, String moduleType) {
Map<String, List<String>> orgPermission = new HashMap<>(2);
orgPermission.put(TaskCenterResourceType.API_CASE.toString(), List.of(PermissionConstants.ORGANIZATION_TASK_CENTER_READ_STOP, PermissionConstants.PROJECT_API_DEFINITION_CASE_EXECUTE));
orgPermission.put(TaskCenterResourceType.API_SCENARIO.toString(), List.of(PermissionConstants.ORGANIZATION_TASK_CENTER_READ_STOP, PermissionConstants.PROJECT_API_SCENARIO_EXECUTE));
Map<String, List<String>> projectPermission = new HashMap<>(2);
projectPermission.put(TaskCenterResourceType.API_CASE.toString(), List.of(PermissionConstants.PROJECT_API_DEFINITION_CASE_EXECUTE));
projectPermission.put(TaskCenterResourceType.API_SCENARIO.toString(), List.of(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE));
Map<String, List<String>> systemPermission = new HashMap<>(2);
systemPermission.put(TaskCenterResourceType.API_CASE.toString(), List.of(PermissionConstants.SYSTEM_TASK_CENTER_READ, PermissionConstants.PROJECT_API_DEFINITION_CASE_EXECUTE));
systemPermission.put(TaskCenterResourceType.API_SCENARIO.toString(), List.of(PermissionConstants.SYSTEM_TASK_CENTER_READ, PermissionConstants.PROJECT_API_SCENARIO_EXECUTE));
boolean hasPermission = switch (type) {
case ORG ->
orgPermission.get(moduleType).stream().anyMatch(item -> SessionUtils.hasPermission(SessionUtils.getCurrentOrganizationId(), SessionUtils.getCurrentProjectId(), item));
case PROJECT ->
projectPermission.get(moduleType).stream().anyMatch(item -> SessionUtils.hasPermission(SessionUtils.getCurrentOrganizationId(), SessionUtils.getCurrentProjectId(), item));
case SYSTEM ->
systemPermission.get(moduleType).stream().anyMatch(item -> SessionUtils.hasPermission(SessionUtils.getCurrentOrganizationId(), SessionUtils.getCurrentProjectId(), item));
default -> false;
};
if (!hasPermission) {
throw new MSException(Translator.get("no_permission_to_resource"));
}
}
} }

View File

@ -78,7 +78,7 @@ public class ApiReportController {
@GetMapping("/get/{id}") @GetMapping("/get/{id}")
@Operation(summary = "接口测试-接口报告-报告获取") @Operation(summary = "接口测试-接口报告-报告获取")
@CheckOwner(resourceId = "#id", resourceType = "api_report") @CheckOwner(resourceId = "#id", resourceType = "api_report")
@RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_DEFINITION_CASE_UPDATE}, logical = Logical.OR) @RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_DEFINITION_CASE_EXECUTE}, logical = Logical.OR)
public ApiReportDTO get(@PathVariable String id) { public ApiReportDTO get(@PathVariable String id) {
return apiReportService.get(id); return apiReportService.get(id);
} }
@ -94,7 +94,7 @@ public class ApiReportController {
@GetMapping("/get/detail/{reportId}/{stepId}") @GetMapping("/get/detail/{reportId}/{stepId}")
@Operation(summary = "接口测试-接口报告-报告详情获取") @Operation(summary = "接口测试-接口报告-报告详情获取")
@CheckOwner(resourceId = "#reportId", resourceType = "api_report") @CheckOwner(resourceId = "#reportId", resourceType = "api_report")
@RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_DEFINITION_CASE_UPDATE}, logical = Logical.OR) @RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_DEFINITION_CASE_EXECUTE}, logical = Logical.OR)
public List<ApiReportDetailDTO> getDetail(@PathVariable String reportId, public List<ApiReportDetailDTO> getDetail(@PathVariable String reportId,
@PathVariable String stepId) { @PathVariable String stepId) {
return apiReportService.getDetail(reportId, stepId); return apiReportService.getDetail(reportId, stepId);

View File

@ -77,7 +77,7 @@ public class ApiScenarioReportController {
@GetMapping("/get/{id}") @GetMapping("/get/{id}")
@Operation(summary = "接口测试-接口报告-报告获取") @Operation(summary = "接口测试-接口报告-报告获取")
@CheckOwner(resourceId = "#id", resourceType = "api_scenario_report") @CheckOwner(resourceId = "#id", resourceType = "api_scenario_report")
@RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_SCENARIO_UPDATE}, logical = Logical.OR) @RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_SCENARIO_EXECUTE}, logical = Logical.OR)
public ApiScenarioReportDTO get(@PathVariable String id) { public ApiScenarioReportDTO get(@PathVariable String id) {
return apiScenarioReportService.get(id); return apiScenarioReportService.get(id);
} }
@ -93,7 +93,7 @@ public class ApiScenarioReportController {
@GetMapping("/get/detail/{reportId}/{stepId}") @GetMapping("/get/detail/{reportId}/{stepId}")
@Operation(summary = "接口测试-接口报告-报告详情获取") @Operation(summary = "接口测试-接口报告-报告详情获取")
@CheckOwner(resourceId = "#reportId", resourceType = "api_scenario_report") @CheckOwner(resourceId = "#reportId", resourceType = "api_scenario_report")
@RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_SCENARIO_UPDATE}, logical = Logical.OR) @RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_SCENARIO_EXECUTE}, logical = Logical.OR)
public List<ApiScenarioReportDetailDTO> getDetail(@PathVariable String reportId, public List<ApiScenarioReportDetailDTO> getDetail(@PathVariable String reportId,
@PathVariable String stepId) { @PathVariable String stepId) {
return apiScenarioReportService.getDetail(reportId, stepId); return apiScenarioReportService.getDetail(reportId, stepId);

View File

@ -142,6 +142,18 @@
and api_report.update_user in and api_report.update_user in
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/> <include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
</when> </when>
<when test="key=='projectIds">
and api_report.project_id in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='organizationIds'">
and project.organization_id in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
</choose> </choose>
</if> </if>
</foreach> </foreach>
@ -179,6 +191,7 @@
LEFT JOIN api_test_case_record a ON api_report.id = a.api_report_id LEFT JOIN api_test_case_record a ON api_report.id = a.api_report_id
LEFT JOIN api_test_case c ON a.api_test_case_id = c.id LEFT JOIN api_test_case c ON a.api_test_case_id = c.id
LEFT JOIN test_resource_pool t ON api_report.pool_id = t.id LEFT JOIN test_resource_pool t ON api_report.pool_id = t.id
left join project on api_report.project_id = project.id
where api_report.deleted = false where api_report.deleted = false
and api_report.test_plan_id = 'NONE' and api_report.test_plan_id = 'NONE'
and api_report.start_time BETWEEN #{startTime} AND #{endTime} and api_report.start_time BETWEEN #{startTime} AND #{endTime}

View File

@ -48,7 +48,7 @@ public interface ExtApiScenarioReportMapper {
ApiScenarioBlob getScenarioBlob(String id); ApiScenarioBlob getScenarioBlob(String id);
void updateApiScenario(List<String> subList); void updateApiScenario(List<String> ids);
List<ApiScenarioReportStepDTO> selectStepDeatilByReportId(String id); List<ApiScenarioReportStepDTO> selectStepDeatilByReportId(String id);
} }

View File

@ -148,6 +148,7 @@
api_scenario_report.start_time as operationTime, api_scenario_report.start_time as operationTime,
api_scenario_report.create_user as operationName, api_scenario_report.create_user as operationName,
api_scenario_report.trigger_mode, api_scenario_report.trigger_mode,
api_scenario_report.script_identifier,
CASE CASE
WHEN api_scenario_report.integrated = 0 THEN WHEN api_scenario_report.integrated = 0 THEN
@ -169,6 +170,7 @@
left join api_scenario_record a on api_scenario_report.id = a.api_scenario_report_id left join api_scenario_record a on api_scenario_report.id = a.api_scenario_report_id
left JOIN api_scenario s on a.api_scenario_id = s.id left JOIN api_scenario s on a.api_scenario_id = s.id
left JOIN test_resource_pool t on api_scenario_report.pool_id = t.id left JOIN test_resource_pool t on api_scenario_report.pool_id = t.id
left join project on api_scenario_report.project_id = project.id
where api_scenario_report.deleted = false where api_scenario_report.deleted = false
and api_scenario_report.test_plan_id = 'NONE' and api_scenario_report.test_plan_id = 'NONE'
and api_scenario_report.start_time BETWEEN #{startTime} AND #{endTime} and api_scenario_report.start_time BETWEEN #{startTime} AND #{endTime}
@ -265,6 +267,18 @@
and api_scenario_report.update_user in and api_scenario_report.update_user in
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/> <include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
</when> </when>
<when test="key=='projectIds">
and api_scenario_report.project_id in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='organizationIds'">
and project.organization_id in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
</choose> </choose>
</if> </if>
</foreach> </foreach>

View File

@ -203,7 +203,7 @@ public class ApiTaskCenterService {
} }
public void systemStop(TaskCenterBatchRequest request, String userId) { public void systemStop(TaskCenterBatchRequest request, String userId) {
stopApiTask(request, null, userId, SYSTEM_STOP, HttpMethodConstants.POST.name(), OperationLogModule.SETTING_SYSTEM_TASK_CENTER); stopApiTask(request, getSystemProjectList().stream().map(OptionDTO::getId).toList(), userId, SYSTEM_STOP, HttpMethodConstants.POST.name(), OperationLogModule.SETTING_SYSTEM_TASK_CENTER);
} }
private void stopApiTask(TaskCenterBatchRequest request, List<String> projectIds, String userId, String path, String method, String module) { private void stopApiTask(TaskCenterBatchRequest request, List<String> projectIds, String userId, String path, String method, String module) {
@ -261,15 +261,17 @@ public class ApiTaskCenterService {
try { try {
LogUtils.info(String.format("开始发送停止请求到 %s 节点执行", endpoint), subList.toString()); LogUtils.info(String.format("开始发送停止请求到 %s 节点执行", endpoint), subList.toString());
TaskRunnerClient.stopApi(endpoint, subList); TaskRunnerClient.stopApi(endpoint, subList);
} catch (Exception e) {
if (request.getModuleType().equals(TaskCenterResourceType.API_CASE.toString())) { if (request.getModuleType().equals(TaskCenterResourceType.API_CASE.toString())) {
extApiReportMapper.updateReportStatus(subList, System.currentTimeMillis(), userId); extApiReportMapper.updateReportStatus(subList, System.currentTimeMillis(), userId);
extApiReportMapper.updateApiCaseStatus(subList);
//记录日志 //记录日志
saveLog(subList, userId, path, method, module, TaskCenterResourceType.API_CASE.toString()); saveLog(subList, userId, path, method, module, TaskCenterResourceType.API_CASE.toString());
} else if (request.getModuleType().equals(TaskCenterResourceType.API_SCENARIO.toString())) { } else if (request.getModuleType().equals(TaskCenterResourceType.API_SCENARIO.toString())) {
extApiScenarioReportMapper.updateReportStatus(subList, System.currentTimeMillis(), userId); extApiScenarioReportMapper.updateReportStatus(subList, System.currentTimeMillis(), userId);
extApiScenarioReportMapper.updateApiScenario(subList);
saveLog(subList, userId, path, method, module, TaskCenterResourceType.API_SCENARIO.toString()); saveLog(subList, userId, path, method, module, TaskCenterResourceType.API_SCENARIO.toString());
} }
} catch (Exception e) {
LogUtils.error(e); LogUtils.error(e);
} }
}); });

View File

@ -274,7 +274,7 @@ public class ApiDefinitionImportUtilService {
Project project = projectMapper.selectByPrimaryKey(request.getProjectId()); Project project = projectMapper.selectByPrimaryKey(request.getProjectId());
List<ApiDefinitionCaseDTO> updateLists = new ArrayList<>(); List<ApiDefinitionCaseDTO> updateLists = new ArrayList<>();
//获取更新的日志 //获取更新的日志
getUpdateLog(request, logData, updateLists, project, operationLogs); apiUpdateLog(request, logData, updateLists, project, operationLogs);
List<ApiDefinitionCaseDTO> createLists = new ArrayList<>(); List<ApiDefinitionCaseDTO> createLists = new ArrayList<>();
//获取新增的数据和日志 //获取新增的数据和日志
@ -365,7 +365,7 @@ public class ApiDefinitionImportUtilService {
}); });
} }
private static void getUpdateLog(ImportRequest request, Map<String, ApiDefinitionImportDetail> logData, List<ApiDefinitionCaseDTO> updateLists, Project project, List<LogDTO> operationLogs) { private static void apiUpdateLog(ImportRequest request, Map<String, ApiDefinitionImportDetail> logData, List<ApiDefinitionCaseDTO> updateLists, Project project, List<LogDTO> operationLogs) {
if (MapUtils.isNotEmpty(logData)) { if (MapUtils.isNotEmpty(logData)) {
logData.forEach((k, v) -> { logData.forEach((k, v) -> {
ApiDefinitionDTO apiDefinitionDTO = new ApiDefinitionDTO(); ApiDefinitionDTO apiDefinitionDTO = new ApiDefinitionDTO();

View File

@ -39,7 +39,7 @@ public class ApiScenarioReportLogService {
scenarioReport.getId(), scenarioReport.getId(),
null, null,
OperationLogType.DELETE.name(), OperationLogType.DELETE.name(),
OperationLogModule.API_REPORT, OperationLogModule.API_TEST_REPORT_SCENARIO,
scenarioReport.getName()); scenarioReport.getName());
dto.setPath("/api/report/scenario/delete/" + scenarioReport.getId()); dto.setPath("/api/report/scenario/delete/" + scenarioReport.getId());
@ -57,7 +57,7 @@ public class ApiScenarioReportLogService {
scenarioReport.getId(), scenarioReport.getId(),
null, null,
OperationLogType.UPDATE.name(), OperationLogType.UPDATE.name(),
OperationLogModule.API_REPORT, OperationLogModule.API_TEST_REPORT_SCENARIO,
scenarioReport.getName()); scenarioReport.getName());
dto.setPath("/api/report/scenario/rename/" + scenarioReport.getId() + "/" + scenarioReport.getName()); dto.setPath("/api/report/scenario/rename/" + scenarioReport.getId() + "/" + scenarioReport.getName());
@ -77,7 +77,7 @@ public class ApiScenarioReportLogService {
apiReport.getId(), apiReport.getId(),
userId, userId,
OperationLogType.DELETE.name(), OperationLogType.DELETE.name(),
OperationLogModule.API_REPORT, OperationLogModule.API_TEST_REPORT_SCENARIO,
apiReport.getName()); apiReport.getName());
dto.setPath("/api/report/scenario/batch/delete"); dto.setPath("/api/report/scenario/batch/delete");

View File

@ -261,7 +261,9 @@ public class ApiScenarioReportService {
example.createCriteria().andReportIdEqualTo(id); example.createCriteria().andReportIdEqualTo(id);
List<ApiScenarioReportLog> apiScenarioReportLogs = apiScenarioReportLogMapper.selectByExampleWithBLOBs(example); List<ApiScenarioReportLog> apiScenarioReportLogs = apiScenarioReportLogMapper.selectByExampleWithBLOBs(example);
if (CollectionUtils.isNotEmpty(apiScenarioReportLogs)) { if (CollectionUtils.isNotEmpty(apiScenarioReportLogs)) {
scenarioReportDTO.setConsole(new String(apiScenarioReportLogs.getFirst().getConsole())); //获取所有的console,生成集合
List<String> consoleList = apiScenarioReportLogs.stream().map(c -> new String (c.getConsole())).toList();
scenarioReportDTO.setConsole(String.join("\n", consoleList));
} }
//查询资源池名称 //查询资源池名称
scenarioReportDTO.setPoolName(testResourcePoolMapper.selectByPrimaryKey(scenarioReport.getPoolId()).getName()); scenarioReportDTO.setPoolName(testResourcePoolMapper.selectByPrimaryKey(scenarioReport.getPoolId()).getName());

View File

@ -1,8 +1,14 @@
package io.metersphere.system.controller; package io.metersphere.system.controller;
import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.TaskCenterResourceType;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.taskcenter.TaskCenterScheduleDTO; import io.metersphere.system.dto.taskcenter.TaskCenterScheduleDTO;
import io.metersphere.system.dto.taskcenter.enums.ScheduleTagType;
import io.metersphere.system.dto.taskcenter.request.TaskCenterScheduleBatchRequest;
import io.metersphere.system.dto.taskcenter.request.TaskCenterSchedulePageRequest; import io.metersphere.system.dto.taskcenter.request.TaskCenterSchedulePageRequest;
import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.security.CheckOwner; import io.metersphere.system.security.CheckOwner;
import io.metersphere.system.service.TaskCenterService; import io.metersphere.system.service.TaskCenterService;
import io.metersphere.system.utils.Pager; import io.metersphere.system.utils.Pager;
@ -14,7 +20,9 @@ import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* @author: LAN * @author: LAN
@ -28,11 +36,13 @@ public class TaskCenterController {
@Resource @Resource
private TaskCenterService taskCenterService; private TaskCenterService taskCenterService;
private static final String PROJECT = "project";
private static final String ORG = "org";
private static final String SYSTEM = "system";
@PostMapping("/project/schedule/page") @PostMapping("/project/schedule/page")
@Operation(summary = "项目-任务中心-定时任务列表") @Operation(summary = "项目-任务中心-定时任务列表")
@RequiresPermissions(PermissionConstants.PROJECT_BASE_INFO_READ)
public Pager<List<TaskCenterScheduleDTO>> projectScheduleList(@Validated @RequestBody TaskCenterSchedulePageRequest request) { public Pager<List<TaskCenterScheduleDTO>> projectScheduleList(@Validated @RequestBody TaskCenterSchedulePageRequest request) {
return taskCenterService.getProjectSchedulePage(request, SessionUtils.getCurrentProjectId()); return taskCenterService.getProjectSchedulePage(request, SessionUtils.getCurrentProjectId());
} }
@ -51,27 +61,145 @@ public class TaskCenterController {
return taskCenterService.getSystemSchedulePage(request); return taskCenterService.getSystemSchedulePage(request);
} }
@GetMapping("/schedule/delete/{id}") @GetMapping("/system/schedule/delete/{moduleType}/{id}")
@Operation(summary = "系统-任务中心-删除定时任务") @Operation(summary = "系统-任务中心-删除定时任务")
@CheckOwner(resourceId = "#id", resourceType = "schedule") @CheckOwner(resourceId = "#id", resourceType = "schedule")
public void delete(@PathVariable String id) { public void delete(@PathVariable String moduleType, @PathVariable String id) {
taskCenterService.delete(id); hasPermission(SYSTEM, moduleType);
taskCenterService.delete(id, SessionUtils.getUserId(), "/task/center/system/schedule/delete/", OperationLogModule.SETTING_SYSTEM_TASK_CENTER);
} }
@GetMapping("/schedule/switch/{id}") @GetMapping("/org/schedule/delete/{moduleType}/{id}")
@Operation(summary = "系统-任务中心-关闭/开启定时任务") @Operation(summary = "组织-任务中心-删除定时任务")
@CheckOwner(resourceId = "#id", resourceType = "schedule") @CheckOwner(resourceId = "#id", resourceType = "schedule")
public void enable(@PathVariable String id) { public void deleteOrg(@PathVariable String moduleType, @PathVariable String id) {
taskCenterService.enable(id); hasPermission(ORG, moduleType);
taskCenterService.delete(id, SessionUtils.getUserId(), "/task/center/org/schedule/delete/", OperationLogModule.SETTING_ORGANIZATION_TASK_CENTER);
} }
@PostMapping("/schedule/update/{id}") @GetMapping("/project/schedule/delete/{moduleType}/{id}")
@Operation(summary = "项目-任务中心-删除定时任务")
@CheckOwner(resourceId = "#id", resourceType = "schedule")
public void deleteProject(@PathVariable String moduleType, @PathVariable String id) {
hasPermission(PROJECT, moduleType);
taskCenterService.delete(id, SessionUtils.getUserId(), "/task/center/project/schedule/delete/", OperationLogModule.PROJECT_MANAGEMENT_TASK_CENTER);
}
@GetMapping("/system/schedule/switch/{moduleType}/{id}")
@Operation(summary = "系统-任务中心-定时任务开启关闭")
@CheckOwner(resourceId = "#id", resourceType = "schedule")
public void enable(@PathVariable String moduleType, @PathVariable String id) {
hasPermission(SYSTEM, moduleType);
taskCenterService.enable(id, SessionUtils.getUserId(), "/task/center/system/schedule/switch/", OperationLogModule.SETTING_SYSTEM_TASK_CENTER);
}
@GetMapping("/org/schedule/switch/{moduleType}/{id}")
@Operation(summary = "组织-任务中心-定时任务开启关闭")
@CheckOwner(resourceId = "#id", resourceType = "schedule")
public void enableOrg(@PathVariable String moduleType, @PathVariable String id) {
hasPermission(ORG, moduleType);
taskCenterService.enable(id, SessionUtils.getUserId(), "/task/center/org/schedule/switch/", OperationLogModule.SETTING_ORGANIZATION_TASK_CENTER);
}
@GetMapping("/project/schedule/switch/{moduleType}/{id}")
@Operation(summary = "项目-任务中心-定时任务开启关闭")
@CheckOwner(resourceId = "#id", resourceType = "schedule")
public void enableProject(@PathVariable String moduleType, @PathVariable String id) {
hasPermission(PROJECT, moduleType);
taskCenterService.enable(id, SessionUtils.getUserId(), "/task/center/project/schedule/switch/", OperationLogModule.PROJECT_MANAGEMENT_TASK_CENTER);
}
@PostMapping("/system/schedule/update/{moduleType}/{id}")
@Operation(summary = "系统-任务中心-修改定时任务") @Operation(summary = "系统-任务中心-修改定时任务")
@CheckOwner(resourceId = "#id", resourceType = "schedule") @CheckOwner(resourceId = "#id", resourceType = "schedule")
public void update(@PathVariable String id, @RequestBody Object cron) { public void update(@PathVariable String moduleType, @PathVariable String id, @RequestBody Object cron) {
taskCenterService.update(id, cron.toString()); hasPermission(SYSTEM, moduleType);
taskCenterService.update(id, cron.toString(), SessionUtils.getUserId(), "/task/center/system/schedule/update/", OperationLogModule.SETTING_SYSTEM_TASK_CENTER);
} }
@PostMapping("/org/schedule/update/{moduleType}/{id}")
@Operation(summary = "组织-任务中心-修改定时任务")
@CheckOwner(resourceId = "#id", resourceType = "schedule")
public void updateOrg(@PathVariable String moduleType, @PathVariable String id, @RequestBody Object cron) {
hasPermission(ORG, moduleType);
taskCenterService.update(id, cron.toString(), SessionUtils.getUserId(), "/task/center/org/schedule/update/", OperationLogModule.SETTING_ORGANIZATION_TASK_CENTER);
}
@PostMapping("/project/schedule/update/{moduleType}/{id}")
@Operation(summary = "项目-任务中心-修改定时任务")
@CheckOwner(resourceId = "#id", resourceType = "schedule")
public void updateProject(@PathVariable String moduleType, @PathVariable String id, @RequestBody Object cron) {
hasPermission(PROJECT, moduleType);
taskCenterService.update(id, cron.toString(), SessionUtils.getUserId(), "/task/center/project/schedule/update/", OperationLogModule.PROJECT_PROJECT_MANAGER);
}
@PostMapping("/system/schedule/batch-enable")
@Operation(summary = "系统-任务中心-定时任务批量开启")
public void batchEnable(@Validated @RequestBody TaskCenterScheduleBatchRequest request) {
hasPermission(SYSTEM, request.getScheduleTagType());
taskCenterService.batchEnable(request, SessionUtils.getUserId(), "/task/center/system/schedule/batch-enable", OperationLogModule.SETTING_SYSTEM_TASK_CENTER, true);
}
@PostMapping("/org/schedule/batch-enable")
@Operation(summary = "组织-任务中心-定时任务批量开启")
public void batchOrgEnable(@Validated @RequestBody TaskCenterScheduleBatchRequest request) {
hasPermission(ORG, request.getScheduleTagType());
taskCenterService.batchEnableOrg(request, SessionUtils.getUserId(), SessionUtils.getCurrentOrganizationId(), "/task/center/org/schedule/batch-enable", OperationLogModule.SETTING_ORGANIZATION_TASK_CENTER, true);
}
@PostMapping("/project/schedule/batch-enable")
@Operation(summary = "项目-任务中心-定时任务批量开启")
public void batchProjectEnable(@Validated @RequestBody TaskCenterScheduleBatchRequest request) {
hasPermission(PROJECT, request.getScheduleTagType());
taskCenterService.batchEnableProject(request, SessionUtils.getUserId(), SessionUtils.getCurrentProjectId(), "/task/center/project/schedule/batch-enable", OperationLogModule.PROJECT_MANAGEMENT_TASK_CENTER, true);
}
@PostMapping("/system/schedule/batch-disable")
@Operation(summary = "系统-任务中心-定时任务批量关闭")
public void batchDisable(@Validated @RequestBody TaskCenterScheduleBatchRequest request) {
hasPermission(SYSTEM, request.getScheduleTagType());
taskCenterService.batchEnable(request, SessionUtils.getUserId(), "/task/center/system/schedule/batch-disable", OperationLogModule.SETTING_SYSTEM_TASK_CENTER, false);
}
@PostMapping("/org/schedule/batch-disable")
@Operation(summary = "组织-任务中心-定时任务批量关闭")
public void batchOrgDisable(@Validated @RequestBody TaskCenterScheduleBatchRequest request) {
hasPermission(ORG, request.getScheduleTagType());
taskCenterService.batchEnableOrg(request, SessionUtils.getUserId(), SessionUtils.getCurrentOrganizationId(), "/task/center/org/schedule/batch-disable", OperationLogModule.SETTING_ORGANIZATION_TASK_CENTER, false);
}
@PostMapping("/project/schedule/batch-disable")
@Operation(summary = "项目-任务中心-定时任务批量关闭")
public void batchProjectDisable(@Validated @RequestBody TaskCenterScheduleBatchRequest request) {
hasPermission(PROJECT, request.getScheduleTagType());
taskCenterService.batchEnableProject(request, SessionUtils.getUserId(), SessionUtils.getCurrentProjectId(), "/task/center/project/schedule/batch-disable", OperationLogModule.PROJECT_MANAGEMENT_TASK_CENTER, false);
}
private void hasPermission(String type, String moduleType) {
Map<String, List<String>> projectPermission = new HashMap<>(2);
projectPermission.put(ScheduleTagType.API_IMPORT.toString(), List.of(PermissionConstants.PROJECT_API_DEFINITION_IMPORT));
projectPermission.put(TaskCenterResourceType.API_SCENARIO.toString(), List.of(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE));
Map<String, List<String>> orgPermission = new HashMap<>(2);
orgPermission.put(ScheduleTagType.API_IMPORT.toString(), List.of(PermissionConstants.ORGANIZATION_TASK_CENTER_READ_STOP, PermissionConstants.PROJECT_API_DEFINITION_IMPORT));
orgPermission.put(TaskCenterResourceType.API_SCENARIO.toString(), List.of(PermissionConstants.ORGANIZATION_TASK_CENTER_READ_STOP, PermissionConstants.PROJECT_API_SCENARIO_EXECUTE));
Map<String, List<String>> systemPermission = new HashMap<>(2);
systemPermission.put(ScheduleTagType.API_IMPORT.toString(), List.of(PermissionConstants.SYSTEM_TASK_CENTER_READ, PermissionConstants.PROJECT_API_DEFINITION_IMPORT));
systemPermission.put(TaskCenterResourceType.API_SCENARIO.toString(), List.of(PermissionConstants.SYSTEM_TASK_CENTER_READ, PermissionConstants.PROJECT_API_SCENARIO_EXECUTE));
boolean hasPermission = switch (type) {
case ORG ->
orgPermission.get(moduleType).stream().anyMatch(item -> SessionUtils.hasPermission(SessionUtils.getCurrentOrganizationId(), SessionUtils.getCurrentProjectId(), item));
case PROJECT ->
projectPermission.get(moduleType).stream().anyMatch(item -> SessionUtils.hasPermission(SessionUtils.getCurrentOrganizationId(), SessionUtils.getCurrentProjectId(), item));
case SYSTEM ->
systemPermission.get(moduleType).stream().anyMatch(item -> SessionUtils.hasPermission(SessionUtils.getCurrentOrganizationId(), SessionUtils.getCurrentProjectId(), item));
default -> false;
};
if (!hasPermission) {
throw new MSException(Translator.get("no_permission_to_resource"));
}
}
} }

View File

@ -46,6 +46,9 @@ public class TaskCenterDTO implements Serializable {
@Schema(description = "执行状态/SUCCESS/ERROR") @Schema(description = "执行状态/SUCCESS/ERROR")
private String status; private String status;
@Schema(description = "脚本标识")
private String scriptIdentifier;
@Schema(description = "操作人") @Schema(description = "操作人")
private String operationName; private String operationName;

View File

@ -9,9 +9,10 @@ import java.util.List;
*/ */
public enum ScheduleTagType { public enum ScheduleTagType {
API_IMPORT("API_IMPORT"), API_IMPORT("API_IMPORT"),
TEST_RESOURCE("API_SCENARIO", "UI_SCENARIO", "LOAD_TEST", "TEST_PLAN"), API_SCENARIO("API_SCENARIO"),
UI_SCENARIO("UI_TEST"),
ORDER("CLEAN_REPORT", "BUG_SYNC"); LOAD_TEST("LOAD_TEST"),
TEST_PLAN("TEST_PLAN");
private List<String> names; private List<String> names;

View File

@ -0,0 +1,21 @@
package io.metersphere.system.dto.taskcenter.request;
import io.metersphere.system.dto.table.TableBatchProcessDTO;
import io.metersphere.system.dto.taskcenter.enums.ScheduleTagType;
import io.metersphere.system.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
@Data
public class TaskCenterScheduleBatchRequest extends TableBatchProcessDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "所属模块", requiredMode = Schema.RequiredMode.REQUIRED)
@EnumValue(enumClass = ScheduleTagType.class)
private String scheduleTagType = ScheduleTagType.API_IMPORT.toString();
}

View File

@ -29,7 +29,8 @@ public class OperationLogModule {
public static final String API_TEST_SCENARIO_RECYCLE = "API_TEST_SCENARIO_RECYCLE"; public static final String API_TEST_SCENARIO_RECYCLE = "API_TEST_SCENARIO_RECYCLE";
public static final String API_TEST_MANAGEMENT_RECYCLE = "API_TEST_MANAGEMENT_RECYCLE"; public static final String API_TEST_MANAGEMENT_RECYCLE = "API_TEST_MANAGEMENT_RECYCLE";
public static final String API_REPORT = "API_TEST_REPORT"; public static final String API_REPORT = "API_TEST_REPORT_CASE";
public static final String API_TEST_REPORT_SCENARIO = "API_TEST_REPORT_SCENARIO";
public static final String AUTH_TITLE = "AUTH_TITLE"; public static final String AUTH_TITLE = "AUTH_TITLE";
public static final String PROJECT_ENVIRONMENT_SETTING = "PROJECT_ENVIRONMENT_SETTING"; public static final String PROJECT_ENVIRONMENT_SETTING = "PROJECT_ENVIRONMENT_SETTING";
public static final String PROJECT_PROJECT_MANAGER = "PROJECT_PROJECT_MANAGER"; public static final String PROJECT_PROJECT_MANAGER = "PROJECT_PROJECT_MANAGER";

View File

@ -3,7 +3,9 @@ package io.metersphere.system.mapper;
import io.metersphere.api.domain.ApiScenario; import io.metersphere.api.domain.ApiScenario;
import io.metersphere.api.domain.ApiTestCase; import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.system.domain.Schedule; import io.metersphere.system.domain.Schedule;
import io.metersphere.system.dto.ProjectDTO;
import io.metersphere.system.dto.taskcenter.TaskCenterScheduleDTO; import io.metersphere.system.dto.taskcenter.TaskCenterScheduleDTO;
import io.metersphere.system.dto.taskcenter.request.TaskCenterScheduleBatchRequest;
import io.metersphere.system.dto.taskcenter.request.TaskCenterSchedulePageRequest; import io.metersphere.system.dto.taskcenter.request.TaskCenterSchedulePageRequest;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
@ -17,7 +19,7 @@ public interface ExtScheduleMapper {
* @param request 列表请求参数 * @param request 列表请求参数
* @return 定时任务列表数据 * @return 定时任务列表数据
*/ */
List<TaskCenterScheduleDTO> taskCenterSchedulelist(@Param("request") TaskCenterSchedulePageRequest request, @Param("projectIds") List<String> projectIds, @Param("resourceTypes") List<String> resourceTypes); List<TaskCenterScheduleDTO> taskCenterSchedulelist(@Param("request") TaskCenterSchedulePageRequest request, @Param("projectIds") List<String> projectIds);
List<ApiTestCase> getApiTestCaseListByIds(@Param("ids") List<String> ids); List<ApiTestCase> getApiTestCaseListByIds(@Param("ids") List<String> ids);
@ -32,4 +34,9 @@ public interface ExtScheduleMapper {
long countQuartzCronTriggersByResourceId(String scheduleId); long countQuartzCronTriggersByResourceId(String scheduleId);
List<Schedule> getScheduleByLimit(@Param("start") int start, @Param("limit") int limit); List<Schedule> getScheduleByLimit(@Param("start") int start, @Param("limit") int limit);
List<ProjectDTO> getOrgListByProjectIds(List<String> ids);
List<Schedule> getSchedule(@Param("request") TaskCenterScheduleBatchRequest request, @Param("projectIds") List<String> projectIds);
} }

View File

@ -2,29 +2,13 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.system.mapper.ExtScheduleMapper"> <mapper namespace="io.metersphere.system.mapper.ExtScheduleMapper">
<select id="taskCenterSchedulelist" resultType="io.metersphere.system.dto.taskcenter.TaskCenterScheduleDTO"> <select id="taskCenterSchedulelist" resultType="io.metersphere.system.dto.taskcenter.TaskCenterScheduleDTO">
SELECT task.* from ( select task.*, QRTZ_TRIGGERS.TRIGGER_NAME as triggerName from (
<if test="request.scheduleTagType == 'API_IMPORT'">
SELECT SELECT
schedule.id, schedule.id,
schedule.name as taskname, schedule.name as taskname,
schedule.project_id, schedule.project_id,
'API_SCENARIO' as resource_type, resource_type,
api_scenario.num as resource_num,
api_scenario.name as resource_name,
api_scenario.id as resource_id,
schedule.value,
schedule.enable,
schedule.create_user AS createUserName,
schedule.create_time
FROM
schedule
inner join api_scenario on schedule.resource_id = api_scenario.id
union all
SELECT
schedule.id,
schedule.name as taskname,
schedule.project_id,
'API_IMPORT' as resource_type,
ads.num as resource_num, ads.num as resource_num,
ads.name as resource_name, ads.name as resource_name,
ads.id as resource_id, ads.id as resource_id,
@ -36,12 +20,29 @@
schedule schedule
inner join api_definition_swagger ads on schedule.resource_id = ads.id inner join api_definition_swagger ads on schedule.resource_id = ads.id
) task </if>
<if test="request.scheduleTagType == 'API_SCENARIO'">
SELECT
schedule.id,
schedule.name as taskname,
schedule.project_id,
resource_type,
api_scenario.num as resource_num,
api_scenario.name as resource_name,
api_scenario.id as resource_id,
schedule.value,
schedule.enable,
schedule.create_user AS createUserName,
schedule.create_time
FROM
schedule
inner join api_scenario on schedule.resource_id = api_scenario.id
</if>
) task left join project on task.project_id = project.id
left join QRTZ_TRIGGERS on task.resource_id = QRTZ_TRIGGERS.TRIGGER_NAME
where where
task.resource_type in task.resource_type =#{request.scheduleTagType}
<foreach collection="resourceTypes" item="resourceType" separator="," open="(" close=")">
#{resourceType}
</foreach>
and task.project_id IN and task.project_id IN
<foreach collection="projectIds" item="projectId" separator="," open="(" close=")"> <foreach collection="projectIds" item="projectId" separator="," open="(" close=")">
#{projectId} #{projectId}
@ -67,6 +68,18 @@
and task.resource_type in and task.resource_type in
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/> <include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
</when> </when>
<when test="key=='projectIds">
and task.project_id in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='organizationIds'">
and project.organization_id in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
</choose> </choose>
</if> </if>
</foreach> </foreach>
@ -121,5 +134,72 @@
<select id="getScheduleByLimit" resultType="io.metersphere.system.domain.Schedule"> <select id="getScheduleByLimit" resultType="io.metersphere.system.domain.Schedule">
SELECT * FROM schedule ORDER BY create_time LIMIT #{start}, #{limit} SELECT * FROM schedule ORDER BY create_time LIMIT #{start}, #{limit}
</select> </select>
<select id="getOrgListByProjectIds" resultType="io.metersphere.system.dto.ProjectDTO">
select
p.id ,
o.id as organizationId
from project p
inner join organization o on p.organization_id = o.id
where p.id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<select id="getSchedule" resultType="io.metersphere.system.domain.Schedule">
select task.* from (
<if test="request.scheduleTagType == 'API_IMPORT'">
SELECT
schedule.id,
schedule.name as taskname,
schedule.project_id,
resource_type,
ads.num as resource_num,
ads.name as resource_name,
ads.id as resource_id,
schedule.value,
schedule.enable,
schedule.create_user AS createUserName,
schedule.create_time
FROM
schedule
inner join api_definition_swagger ads on schedule.resource_id = ads.id
</if>
<if test="request.scheduleTagType == 'API_SCENARIO'">
SELECT
schedule.id,
schedule.name as taskname,
schedule.project_id,
resource_type,
api_scenario.num as resource_num,
api_scenario.name as resource_name,
api_scenario.id as resource_id,
schedule.value,
schedule.enable,
schedule.create_user AS createUserName,
schedule.create_time
FROM
schedule
inner join api_scenario on schedule.resource_id = api_scenario.id
</if>
) task left join project on task.project_id = project.id
where
task.resource_type =#{request.scheduleTagType}
and task.project_id IN
<foreach collection="projectIds" item="projectId" separator="," open="(" close=")">
#{projectId}
</foreach>
<if test="request.condition.keyword != null and request.condition.keyword != ''">
and (
task.resource_name like concat('%', #{request.condition.keyword},'%')
or
task.resource_num like concat('%', #{request.condition.keyword},'%')
)
</if>
<include refid="taskCenterScheduleFilters">
<property name="filter" value="request.condition.filter"/>
</include>
</select>
</mapper> </mapper>

View File

@ -4,14 +4,22 @@ import com.github.pagehelper.Page;
import com.github.pagehelper.page.PageMethod; import com.github.pagehelper.page.PageMethod;
import io.metersphere.project.domain.Project; import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper; import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.HttpMethodConstants;
import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.Translator; import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.Organization; import io.metersphere.system.domain.Organization;
import io.metersphere.system.domain.Schedule; import io.metersphere.system.domain.Schedule;
import io.metersphere.system.domain.ScheduleExample;
import io.metersphere.system.dto.ProjectDTO;
import io.metersphere.system.dto.builder.LogDTOBuilder;
import io.metersphere.system.dto.sdk.OptionDTO; import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.dto.taskcenter.TaskCenterScheduleDTO; import io.metersphere.system.dto.taskcenter.TaskCenterScheduleDTO;
import io.metersphere.system.dto.taskcenter.enums.ScheduleTagType; import io.metersphere.system.dto.taskcenter.enums.ScheduleTagType;
import io.metersphere.system.dto.taskcenter.request.TaskCenterScheduleBatchRequest;
import io.metersphere.system.dto.taskcenter.request.TaskCenterSchedulePageRequest; import io.metersphere.system.dto.taskcenter.request.TaskCenterSchedulePageRequest;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.log.dto.LogDTO;
import io.metersphere.system.log.service.OperationLogService;
import io.metersphere.system.mapper.*; import io.metersphere.system.mapper.*;
import io.metersphere.system.schedule.BaseScheduleJob; import io.metersphere.system.schedule.BaseScheduleJob;
import io.metersphere.system.schedule.ScheduleService; import io.metersphere.system.schedule.ScheduleService;
@ -19,11 +27,19 @@ import io.metersphere.system.utils.PageUtils;
import io.metersphere.system.utils.Pager; import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.quartz.*; import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.quartz.JobKey;
import org.quartz.TriggerKey;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.*; import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -62,6 +78,10 @@ public class TaskCenterService {
@Resource @Resource
ScheduleService scheduleService; ScheduleService scheduleService;
@Resource
OperationLogService operationLogService;
@Resource
SqlSessionFactory sqlSessionFactory;
private static final String CREATE_TIME_SORT = "create_time desc"; private static final String CREATE_TIME_SORT = "create_time desc";
@ -94,17 +114,13 @@ public class TaskCenterService {
List<TaskCenterScheduleDTO> list = new ArrayList<>(); List<TaskCenterScheduleDTO> list = new ArrayList<>();
if (request != null && !projectList.isEmpty()) { if (request != null && !projectList.isEmpty()) {
List<String> projectIds = projectList.stream().map(OptionDTO::getId).toList(); List<String> projectIds = projectList.stream().map(OptionDTO::getId).toList();
ScheduleTagType scheduleTagType = ScheduleTagType.valueOf(request.getScheduleTagType()); list = extScheduleMapper.taskCenterSchedulelist(request, projectIds);
List<String> resourceTypes = scheduleTagType.getNames(); processTaskCenterSchedule(list, projectList, projectIds);
if (!resourceTypes.isEmpty()) {
list = extScheduleMapper.taskCenterSchedulelist(request, projectIds, resourceTypes);
processTaskCenterSchedule(list, projectList, projectIds, request.getScheduleTagType());
}
} }
return list; return list;
} }
private void processTaskCenterSchedule(List<TaskCenterScheduleDTO> list, List<OptionDTO> projectList, List<String> projectIds, String scheduleTagType) { private void processTaskCenterSchedule(List<TaskCenterScheduleDTO> list, List<OptionDTO> projectList, List<String> projectIds) {
if (!list.isEmpty()) { if (!list.isEmpty()) {
// 组织 // 组织
List<OptionDTO> orgListByProjectList = getOrgListByProjectIds(projectIds); List<OptionDTO> orgListByProjectList = getOrgListByProjectIds(projectIds);
@ -122,44 +138,26 @@ public class TaskCenterService {
item.setCreateUserName(userMap.getOrDefault(item.getCreateUserName(), StringUtils.EMPTY)); item.setCreateUserName(userMap.getOrDefault(item.getCreateUserName(), StringUtils.EMPTY));
item.setProjectName(projectMap.getOrDefault(item.getProjectId(), StringUtils.EMPTY)); item.setProjectName(projectMap.getOrDefault(item.getProjectId(), StringUtils.EMPTY));
item.setOrganizationName(orgMap.getOrDefault(item.getProjectId(), StringUtils.EMPTY)); item.setOrganizationName(orgMap.getOrDefault(item.getProjectId(), StringUtils.EMPTY));
item.setNextTime(getNextTriggerTime(item.getValue()));
}); });
} }
} }
private List<OptionDTO> getProjectOption(String id){ private List<OptionDTO> getProjectOption(String id) {
return baseProjectMapper.getProjectOptionsById(id); return baseProjectMapper.getProjectOptionsById(id);
} }
private List<OptionDTO> getOrgProjectList(String orgId){ private List<OptionDTO> getOrgProjectList(String orgId) {
return baseProjectMapper.getProjectOptionsByOrgId(orgId); return baseProjectMapper.getProjectOptionsByOrgId(orgId);
} }
private List<OptionDTO> getSystemProjectList(){ private List<OptionDTO> getSystemProjectList() {
return baseProjectMapper.getProjectOptions(); return baseProjectMapper.getProjectOptions();
} }
private List<OptionDTO> getOrgListByProjectIds(List<String> projectIds){ private List<OptionDTO> getOrgListByProjectIds(List<String> projectIds) {
return extOrganizationMapper.getOrgListByProjectIds(projectIds); return extOrganizationMapper.getOrgListByProjectIds(projectIds);
} }
/**
* 获取下次执行时间getFireTimeAfter也可以下下次...
*
* @param cron cron表达式
* @return 下次执行时间
*/
private static Long getNextTriggerTime(String cron) {
if (!CronExpression.isValidExpression(cron)) {
return null;
}
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("Calculate Date").withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
Date time0 = trigger.getStartTime();
Date time1 = trigger.getFireTimeAfter(time0);
return time1 == null ? 0 : time1.getTime();
}
/** /**
* 查看项目是否存在 * 查看项目是否存在
* *
@ -186,12 +184,13 @@ public class TaskCenterService {
return organization; return organization;
} }
public void delete(String id) { public void delete(String id, String userId, String path, String module) {
Schedule schedule = checkScheduleExit(id); Schedule schedule = checkScheduleExit(id);
if (ScheduleTagType.API_IMPORT.getNames().contains(schedule.getResourceType())) { if (ScheduleTagType.API_IMPORT.getNames().contains(schedule.getResourceType())) {
extSwaggerMapper.deleteByPrimaryKey(schedule.getResourceId()); extSwaggerMapper.deleteByPrimaryKey(schedule.getResourceId());
} }
scheduleService.deleteByResourceId(schedule.getResourceId(), schedule.getJob()); scheduleService.deleteByResourceId(schedule.getResourceId(), schedule.getJob());
saveLog(List.of(schedule), userId, path, HttpMethodConstants.GET.name(), module, OperationLogType.DELETE.name());
} }
private Schedule checkScheduleExit(String id) { private Schedule checkScheduleExit(String id) {
@ -202,21 +201,91 @@ public class TaskCenterService {
return schedule; return schedule;
} }
public void enable(String id) { public void enable(String id, String userId, String path, String module) {
Schedule schedule = checkScheduleExit(id); Schedule schedule = checkScheduleExit(id);
schedule.setEnable(!schedule.getEnable()); schedule.setEnable(!schedule.getEnable());
scheduleService.editSchedule(schedule); scheduleService.editSchedule(schedule);
scheduleService.addOrUpdateCronJob(schedule, new JobKey(schedule.getKey(), schedule.getJob()), scheduleService.addOrUpdateCronJob(schedule, new JobKey(schedule.getKey(), schedule.getJob()),
new TriggerKey(schedule.getKey(),schedule.getJob()), BaseScheduleJob.class); new TriggerKey(schedule.getKey(), schedule.getJob()), BaseScheduleJob.class);
saveLog(List.of(schedule), userId, path, HttpMethodConstants.GET.name(), module, OperationLogType.UPDATE.name());
} }
public void update(String id, String cron) { public void update(String id, String cron, String userId, String path, String module) {
Schedule schedule = checkScheduleExit(id); Schedule schedule = checkScheduleExit(id);
schedule.setValue(cron); schedule.setValue(cron);
scheduleService.editSchedule(schedule); scheduleService.editSchedule(schedule);
scheduleService.addOrUpdateCronJob(schedule, new JobKey(schedule.getKey(), schedule.getJob()), scheduleService.addOrUpdateCronJob(schedule, new JobKey(schedule.getKey(), schedule.getJob()),
new TriggerKey(schedule.getKey(),schedule.getJob()), schedule.getJob().getClass()); new TriggerKey(schedule.getKey(), schedule.getJob()), schedule.getJob().getClass());
saveLog(List.of(schedule), userId, path, HttpMethodConstants.POST.name(), module, OperationLogType.UPDATE.name());
}
private void saveLog(List<Schedule> scheduleList, String userId, String path, String method, String module, String operationType) {
//取出所有的项目id
if (scheduleList.isEmpty()) {
return;
}
List<String> projectIds = scheduleList.stream().map(Schedule::getProjectId).distinct().toList();
//根据项目id取出组织id
List<ProjectDTO> orgList = extScheduleMapper.getOrgListByProjectIds(projectIds);
//生成map key:项目id value:组织id
Map<String, String> orgMap = orgList.stream().collect(Collectors.toMap(ProjectDTO::getId, ProjectDTO::getOrganizationId));
List<LogDTO> logs = new ArrayList<>();
scheduleList.forEach(s -> {
LogDTO dto = LogDTOBuilder.builder()
.projectId(s.getProjectId())
.organizationId(orgMap.get(s.getProjectId()))
.type(operationType)
.module(module)
.method(method)
.path(path)
.sourceId(s.getResourceId())
.content(s.getName())
.createUser(userId)
.build().getLogDTO();
logs.add(dto);
});
operationLogService.batchAdd(logs);
}
public void batchEnable(TaskCenterScheduleBatchRequest request, String userId, String path, String module, boolean enable) {
List<OptionDTO> projectList = getSystemProjectList();
batchOperation(request, userId, path, module, projectList, enable);
}
public void batchEnableOrg(TaskCenterScheduleBatchRequest request, String userId, String orgId, String path, String module, boolean enable) {
List<OptionDTO> projectList = getOrgProjectList(orgId);
batchOperation(request, userId, path, module, projectList, enable);
}
private void batchOperation(TaskCenterScheduleBatchRequest request, String userId, String path, String module, List<OptionDTO> projectList, boolean enable) {
List<Schedule> scheduleList = new ArrayList<>();
if (request.isSelectAll()) {
List<String> projectIds = projectList.stream().map(OptionDTO::getId).toList();
scheduleList = extScheduleMapper.getSchedule(request, projectIds);
} else {
ScheduleExample example = new ScheduleExample();
example.createCriteria().andIdIn(request.getSelectIds()).andResourceTypeEqualTo(request.getScheduleTagType());
scheduleList = scheduleMapper.selectByExample(example);
}
//过滤掉不需要的 和已经开启过的
scheduleList = scheduleList.stream().filter(s -> s.getEnable() != enable || !request.getExcludeIds().contains(s.getId())).collect(Collectors.toList());
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ScheduleMapper batchMapper = sqlSession.getMapper(ScheduleMapper.class);
scheduleList.forEach(s -> {
s.setEnable(enable);
batchMapper.updateByPrimaryKeySelective(s);
scheduleService.addOrUpdateCronJob(s, new JobKey(s.getKey(), s.getJob()),
new TriggerKey(s.getKey(), s.getJob()), BaseScheduleJob.class);
});
sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
saveLog(scheduleList, userId, path, HttpMethodConstants.POST.name(), module, OperationLogType.UPDATE.name());
}
public void batchEnableProject(TaskCenterScheduleBatchRequest request, String userId, String projectId, String path, String module, boolean enable) {
List<OptionDTO> projectList = getProjectOption(projectId);
batchOperation(request, userId, path, module, projectList, enable);
} }
} }

View File

@ -9,6 +9,7 @@ import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder; import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.domain.Schedule; import io.metersphere.system.domain.Schedule;
import io.metersphere.system.dto.taskcenter.enums.ScheduleTagType; import io.metersphere.system.dto.taskcenter.enums.ScheduleTagType;
import io.metersphere.system.dto.taskcenter.request.TaskCenterScheduleBatchRequest;
import io.metersphere.system.dto.taskcenter.request.TaskCenterSchedulePageRequest; import io.metersphere.system.dto.taskcenter.request.TaskCenterSchedulePageRequest;
import io.metersphere.system.mapper.ExtSwaggerMapper; import io.metersphere.system.mapper.ExtSwaggerMapper;
import io.metersphere.system.mapper.ScheduleMapper; import io.metersphere.system.mapper.ScheduleMapper;
@ -68,12 +69,12 @@ class TaskCenterScheduleControllerTests extends BaseTest {
doTaskCenterSchedulePage("KEYWORD", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.API_IMPORT.toString()); doTaskCenterSchedulePage("KEYWORD", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.API_IMPORT.toString());
doTaskCenterSchedulePage("FILTER", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.API_IMPORT.toString()); doTaskCenterSchedulePage("FILTER", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.API_IMPORT.toString());
doTaskCenterSchedulePage("KEYWORD", SCHEDULED_PROJECT_PAGE, ScheduleTagType.TEST_RESOURCE.toString()); doTaskCenterSchedulePage("KEYWORD", SCHEDULED_PROJECT_PAGE, ScheduleTagType.API_SCENARIO.toString());
doTaskCenterSchedulePage("FILTER", SCHEDULED_PROJECT_PAGE, ScheduleTagType.TEST_RESOURCE.toString()); doTaskCenterSchedulePage("FILTER", SCHEDULED_PROJECT_PAGE, ScheduleTagType.API_SCENARIO.toString());
doTaskCenterSchedulePage("KEYWORD", SCHEDULED_ORG_PAGE, ScheduleTagType.TEST_RESOURCE.toString()); doTaskCenterSchedulePage("KEYWORD", SCHEDULED_ORG_PAGE, ScheduleTagType.API_SCENARIO.toString());
doTaskCenterSchedulePage("FILTER", SCHEDULED_ORG_PAGE, ScheduleTagType.TEST_RESOURCE.toString()); doTaskCenterSchedulePage("FILTER", SCHEDULED_ORG_PAGE, ScheduleTagType.API_SCENARIO.toString());
doTaskCenterSchedulePage("KEYWORD", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.TEST_RESOURCE.toString()); doTaskCenterSchedulePage("KEYWORD", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.API_SCENARIO.toString());
doTaskCenterSchedulePage("FILTER", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.TEST_RESOURCE.toString()); doTaskCenterSchedulePage("FILTER", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.API_SCENARIO.toString());
} }
private void doTaskCenterSchedulePage(String search, String url, String scheduleTagType) throws Exception { private void doTaskCenterSchedulePage(String search, String url, String scheduleTagType) throws Exception {
@ -160,14 +161,16 @@ class TaskCenterScheduleControllerTests extends BaseTest {
String scheduleId = "1"; String scheduleId = "1";
Schedule oldSchedule = scheduleMapper.selectByPrimaryKey(scheduleId); Schedule oldSchedule = scheduleMapper.selectByPrimaryKey(scheduleId);
// @@请求成功 // @@请求成功
this.requestGet(SCHEDULED_DELETE + scheduleId); this.requestGet("/task/center/system/schedule/delete/" + "API_IMPORT/" + scheduleId);
Schedule schedule = scheduleMapper.selectByPrimaryKey(scheduleId); Schedule schedule = scheduleMapper.selectByPrimaryKey(scheduleId);
Assertions.assertNull(schedule); Assertions.assertNull(schedule);
if (ScheduleTagType.API_IMPORT.getNames().contains(oldSchedule.getType())) { if (ScheduleTagType.API_IMPORT.getNames().contains(oldSchedule.getType())) {
int count = extSwaggerMapper.selectByPrimaryKey(oldSchedule.getResourceId()); int count = extSwaggerMapper.selectByPrimaryKey(oldSchedule.getResourceId());
Assertions.assertTrue(count > 0); Assertions.assertTrue(count > 0);
} }
this.requestGet(SCHEDULED_DELETE + "schedule-121", ERROR_REQUEST_MATCHER); this.requestGet("/task/center/org/schedule/delete/" + "API_IMPORT/" + "4");
this.requestGet("/task/center/project/schedule/delete/" + "API_SCENARIO/" + "2");
this.requestGet("/task/center/system/schedule/delete/" + "API_SCENARIO/" + "schedule-121", ERROR_REQUEST_MATCHER);
} }
@Test @Test
@ -191,8 +194,25 @@ class TaskCenterScheduleControllerTests extends BaseTest {
scheduleService.getSchedule(schedule.getId()); scheduleService.getSchedule(schedule.getId());
scheduleService.editSchedule(schedule); scheduleService.editSchedule(schedule);
scheduleService.getScheduleByResource(schedule.getResourceId(), schedule.getJob()); scheduleService.getScheduleByResource(schedule.getResourceId(), schedule.getJob());
this.requestGet("/task/center/schedule/switch" + "test-schedule-switch"); this.requestGet("/task/center/system/schedule/switch/" +"API_IMPORT/"+ "test-schedule-switch");
this.requestGet("/task/center/schedule/switch" + "test-schedule-switch"); this.requestGet("/task/center/org/schedule/switch/" +"API_IMPORT/"+ "test-schedule-switch");
this.requestPost("/task/center/schedule/update/" + "test-schedule-switch" ,"/0 0/2 * * * ?"); this.requestGet("/task/center/project/schedule/switch/" +"API_IMPORT/"+ "test-schedule-switch");
this.requestPost("/task/center/system/schedule/update/" + "API_IMPORT/"+ "test-schedule-switch" ,"/0 0/2 * * * ?");
this.requestPost("/task/center/org/schedule/update/" + "API_IMPORT/"+ "test-schedule-switch" ,"/0 0/2 * * * ?");
this.requestPost("/task/center/project/schedule/update/" + "API_IMPORT/"+ "test-schedule-switch" ,"/0 0/2 * * * ?");
//批量操作
TaskCenterScheduleBatchRequest request = new TaskCenterScheduleBatchRequest();
request.setSelectIds(List.of("test-schedule-switch"));
request.setSelectAll(false);
this.requestPost("/task/center/system/schedule/batch-enable", request);
request.setSelectAll(true);
this.requestPost("/task/center/system/schedule/batch-disable", request);
this.requestPost("/task/center/org/schedule/batch-enable", request);
this.requestPost("/task/center/org/schedule/batch-disable", request);
this.requestPost("/task/center/project/schedule/batch-enable", request);
this.requestPost("/task/center/project/schedule/batch-disable", request);
} }
} }

View File

@ -1,10 +1,21 @@
import MSR from '@/api/http'; import MSR from '@/api/http';
import { import {
batchDisableScheduleOrgTaskUrl,
batchDisableScheduleProTaskUrl,
batchDisableScheduleSysTaskUrl,
batchEnableScheduleOrgTaskUrl,
batchEnableScheduleProTaskUrl,
batchEnableScheduleSysTaskUrl,
batchStopRealOrdApiUrl, batchStopRealOrdApiUrl,
batchStopRealProjectApiUrl, batchStopRealProjectApiUrl,
batchStopRealSystemApiUrl, batchStopRealSystemApiUrl,
deleteScheduleOrgTaskUrl,
deleteScheduleProTaskUrl,
deleteScheduleSysTaskUrl, deleteScheduleSysTaskUrl,
enableSchedule, enableSchedule,
enableScheduleOrgTaskUrl,
enableScheduleProTaskUrl,
enableScheduleSysTaskUrl,
scheduleOrgCenterListUrl, scheduleOrgCenterListUrl,
scheduleProCenterListUrl, scheduleProCenterListUrl,
scheduleSysCenterListUrl, scheduleSysCenterListUrl,
@ -14,7 +25,9 @@ import {
taskOrgRealCenterListUrl, taskOrgRealCenterListUrl,
taskProRealCenterListUrl, taskProRealCenterListUrl,
taskSysRealCenterListUrl, taskSysRealCenterListUrl,
updateRunRulesUrl, updateScheduleOrgTaskUrl,
updateScheduleProTaskUrl,
updateScheduleSysTaskUrl,
} from '@/api/requrls/project-management/taskCenter'; } from '@/api/requrls/project-management/taskCenter';
import type { CommonList, TableQueryParams } from '@/models/common'; import type { CommonList, TableQueryParams } from '@/models/common';
@ -69,14 +82,69 @@ export function getScheduleProApiCaseList(data: TableQueryParams) {
return MSR.post<CommonList<TimingTaskCenterApiCaseItem>>({ url: scheduleProCenterListUrl, data }); return MSR.post<CommonList<TimingTaskCenterApiCaseItem>>({ url: scheduleProCenterListUrl, data });
} }
export function deleteScheduleSysTask(id: string) { // 系统删除定时任务
return MSR.get({ url: `${deleteScheduleSysTaskUrl}/${id}` }); export function deleteScheduleSysTask(moduleType: keyof typeof TaskCenterEnum, id: string) {
return MSR.get({ url: `${deleteScheduleSysTaskUrl}/${moduleType}/${id}` });
}
// 组织删除定时任务
export function deleteScheduleOrgTask(moduleType: keyof typeof TaskCenterEnum, id: string) {
return MSR.get({ url: `${deleteScheduleOrgTaskUrl}/${moduleType}/${id}` });
}
// 项目删除定时任务
export function deleteScheduleProTask(moduleType: keyof typeof TaskCenterEnum, id: string) {
return MSR.get({ url: `${deleteScheduleProTaskUrl}/${moduleType}/${id}` });
}
// 系统启用定时任务
export function enableScheduleSysTask(moduleType: keyof typeof TaskCenterEnum, id: string) {
return MSR.get({ url: `${enableScheduleSysTaskUrl}/${moduleType}/${id}` });
}
// 组织启用定时任务
export function enableScheduleOrgTask(moduleType: keyof typeof TaskCenterEnum, id: string) {
return MSR.get({ url: `${enableScheduleOrgTaskUrl}/${moduleType}/${id}` });
}
// 项目启用定时任务
export function enableScheduleProTask(moduleType: keyof typeof TaskCenterEnum, id: string) {
return MSR.get({ url: `${enableScheduleProTaskUrl}/${moduleType}/${id}` });
}
// 系统更新定时任务规则
export function updateRunRules(moduleType: keyof typeof TaskCenterEnum, id: string, data: string) {
return MSR.post({ url: `${updateScheduleSysTaskUrl}/${moduleType}/${id}`, data });
}
// 组织更新定时任务规则
export function updateRunRulesOrg(moduleType: keyof typeof TaskCenterEnum, id: string, data: string) {
return MSR.post({ url: `${updateScheduleOrgTaskUrl}/${moduleType}/${id}`, data });
}
// 项目更新定时任务规则
export function updateRunRulesPro(moduleType: keyof typeof TaskCenterEnum, id: string, data: string) {
return MSR.post({ url: `${updateScheduleProTaskUrl}/${moduleType}/${id}`, data });
}
// 系统批量开启定时任务
export function batchEnableScheduleSysTask(data: TableQueryParams) {
return MSR.post({ url: `${batchEnableScheduleSysTaskUrl}`, data });
}
// 组织批量开启定时任务
export function batchEnableScheduleOrgTask(data: TableQueryParams) {
return MSR.post({ url: `${batchEnableScheduleOrgTaskUrl}`, data });
}
// 项目批量开启定时任务
export function batchEnableScheduleProTask(data: TableQueryParams) {
return MSR.post({ url: `${batchEnableScheduleProTaskUrl}`, data });
}
// 系统批量关闭定时任务
export function batchDisableScheduleSysTask(data: TableQueryParams) {
return MSR.post({ url: `${batchDisableScheduleSysTaskUrl}`, data });
}
// 组织批量关闭定时任务
export function batchDisableScheduleOrgTask(data: TableQueryParams) {
return MSR.post({ url: `${batchDisableScheduleOrgTaskUrl}`, data });
}
// 项目批量关闭定时任务
export function batchDisableScheduleProTask(data: TableQueryParams) {
return MSR.post({ url: `${batchDisableScheduleProTaskUrl}`, data });
} }
export function switchSchedule(id: string) { export function switchSchedule(id: string) {
return MSR.get({ url: `${enableSchedule}/${id}` }); return MSR.get({ url: `${enableSchedule}/${id}` });
} }
export function updateRunRules(id: string, data: string) {
return MSR.get({ url: `${updateRunRulesUrl}/${id}`, data });
}
export default {}; export default {};

View File

@ -4,7 +4,7 @@ export const taskSysRealCenterListUrl = '/task/center/api/system/real-time/page'
// 系统-任务中心-定时任务列表 // 系统-任务中心-定时任务列表
export const scheduleSysCenterListUrl = '/task/center/system/schedule/page'; export const scheduleSysCenterListUrl = '/task/center/system/schedule/page';
// 系统-任务中心-删除定时任务 // 系统-任务中心-删除定时任务
export const deleteScheduleSysTaskUrl = '/task/center/schedule/delete'; // export const deleteScheduleSysTaskUrl = '/task/center/schedule/delete';
// 系统接口用例和场景停止实时任务 // 系统接口用例和场景停止实时任务
export const batchStopRealSystemApiUrl = '/task/center/api/system/stop'; export const batchStopRealSystemApiUrl = '/task/center/api/system/stop';
@ -38,3 +38,33 @@ export const stopRealOrdApiUrl = '/task/center/api/org/stop';
export const stopRealProjectApiUrl = '/task/center/api/project/stop'; export const stopRealProjectApiUrl = '/task/center/api/project/stop';
// 更新定时任务运行规则 // 更新定时任务运行规则
export const updateRunRulesUrl = '/task/center/schedule/update'; export const updateRunRulesUrl = '/task/center/schedule/update';
// 系统定时任务 删除
export const deleteScheduleSysTaskUrl = '/task/center/system/schedule/delete/';
// 组织定时任务 删除
export const deleteScheduleOrgTaskUrl = '/task/center/org/schedule/delete/';
// 项目定时任务 删除
export const deleteScheduleProTaskUrl = '/task/center/project/schedule/delete/';
// 系统定时任务 启用
export const enableScheduleSysTaskUrl = '/task/center/system/schedule/switch/';
// 组织定时任务 启用
export const enableScheduleOrgTaskUrl = '/task/center/org/schedule/switch/';
// 项目定时任务 启用
export const enableScheduleProTaskUrl = '/task/center/project/schedule/switch/';
// 系统定时任务 更新
export const updateScheduleSysTaskUrl = '/task/center/system/schedule/update/';
// 组织定时任务 更新
export const updateScheduleOrgTaskUrl = '/task/center/org/schedule/update/';
// 项目定时任务 更新
export const updateScheduleProTaskUrl = '/task/center/project/schedule/update/';
// 系统定时任务 批量开启
export const batchEnableScheduleSysTaskUrl = '/task/center/system/schedule/batch-enable';
// 组织定时任务 批量开启
export const batchEnableScheduleOrgTaskUrl = '/task/center/org/schedule/batch-enable';
// 项目定时任务 批量开启
export const batchEnableScheduleProTaskUrl = '/task/center/project/schedule/batch-enable';
// 系统定时任务 批量关闭
export const batchDisableScheduleSysTaskUrl = '/task/center/system/schedule/batch-disable';
// 组织定时任务 批量关闭
export const batchDisableScheduleOrgTaskUrl = '/task/center/org/schedule/batch-disable';
// 项目定时任务 批量关闭
export const batchDisableScheduleProTaskUrl = '/task/center/project/schedule/batch-disable';

View File

@ -62,4 +62,5 @@ declare global {
declare global { declare global {
// @ts-ignore // @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue' export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
import('vue')
} }

View File

@ -5,7 +5,7 @@ export enum TaskCenterEnum {
UI_TEST = 'UI_TEST', // ui测试 UI_TEST = 'UI_TEST', // ui测试
LOAD_TEST = 'LOAD_TEST', // 性能测试 LOAD_TEST = 'LOAD_TEST', // 性能测试
TEST_PLAN = 'TEST_PLAN', // 测试计划 TEST_PLAN = 'TEST_PLAN', // 测试计划
TEST_RESOURCE = 'TEST_RESOURCE', // 测试资源 // TEST_RESOURCE = 'TEST_RESOURCE', // 测试资源
API_IMPORT = 'API_IMPORT', // API导入 API_IMPORT = 'API_IMPORT', // API导入
} }

View File

@ -1,15 +1,17 @@
<template> <template>
<div class="px-[16px]"> <div class="px-[16px]">
<div class="mb-4 flex items-center justify-end"> <div class="mb-[16px] flex items-center justify-between">
<!-- <span>{{ t('project.taskCenter.apiCaseList', { type: props.name }) }}</span> --> <div class="flex items-center"></div>
<a-input-search <div class="items-right flex gap-[8px]">
v-model:model-value="keyword" <a-input-search
:placeholder="t('system.organization.searchIndexPlaceholder')" v-model:model-value="keyword"
allow-clear :placeholder="t('system.organization.searchIndexPlaceholder')"
class="mx-[8px] w-[240px]" allow-clear
@search="searchList" class="mx-[8px] w-[240px]"
@press-enter="searchList" @search="searchList"
></a-input-search> @press-enter="searchList"
></a-input-search>
</div>
</div> </div>
<ms-base-table <ms-base-table
@ -21,19 +23,21 @@
> >
<template #resourceNum="{ record }"> <template #resourceNum="{ record }">
<div <div
v-if="!record.integrated && hasAnyPermission(permissionsMap[props.group][props.moduleType].jump)"
type="text" type="text"
class="one-line-text flex w-full text-[rgb(var(--primary-5))]" class="one-line-text flex w-full text-[rgb(var(--primary-5))]"
@click="showDetail(record.resourceId)" @click="showDetail(record.resourceId)"
>{{ record.resourceNum }}</div >{{ record.resourceNum }}
> </div>
</template> </template>
<template #resourceName="{ record }"> <template #resourceName="{ record }">
<div <div
v-if="!record.integrated && hasAnyPermission(permissionsMap[props.group][props.moduleType].jump)"
type="text" type="text"
class="one-line-text flex w-full text-[rgb(var(--primary-5))]" class="one-line-text flex w-full text-[rgb(var(--primary-5))]"
@click="showDetail(record.resourceId)" @click="showDetail(record.resourceId)"
>{{ record.resourceName }}</div >{{ record.resourceName }}
> </div>
</template> </template>
<template #statusFilter="{ columnConfig }"> <template #statusFilter="{ columnConfig }">
<a-trigger <a-trigger
@ -73,7 +77,11 @@
</a-trigger> </a-trigger>
</template> </template>
<template #status="{ record }"> <template #status="{ record }">
<ExecutionStatus :module-type="props.moduleType" :status="record.status" /> <ExecutionStatus
:module-type="props.moduleType"
:status="record.status"
:script-identifier="record.scriptIdentifier"
/>
</template> </template>
<template #triggerMode="{ record }"> <template #triggerMode="{ record }">
<span>{{ t(ExecutionMethodsLabel[record.triggerMode]) }}</span> <span>{{ t(ExecutionMethodsLabel[record.triggerMode]) }}</span>
@ -95,16 +103,22 @@
<span>{{ dayjs(record.operationTime).format('YYYY-MM-DD HH:mm:ss') }}</span> <span>{{ dayjs(record.operationTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
</template> </template>
<template #operation="{ record, rowIndex }"> <template #operation="{ record, rowIndex }">
<MsButton class="!mr-0" @click="viewReport(record.id, rowIndex)">{{ <MsButton
t('project.taskCenter.viewReport') class="!mr-0"
}}</MsButton> :disabled="!hasAnyPermission(permissionsMap[props.group][props.moduleType].report)"
@click="viewReport(record.id, rowIndex)"
>{{ t('project.taskCenter.viewReport') }}
</MsButton>
<a-divider v-if="['RUNNING', 'RERUNNING'].includes(record.status)" direction="vertical" /> <a-divider v-if="['RUNNING', 'RERUNNING'].includes(record.status)" direction="vertical" />
<MsButton <MsButton
v-if="['RUNNING', 'RERUNNING'].includes(record.status) && hasAnyPermission(permissionsMap[props.group].stop)" v-if="
['RUNNING', 'RERUNNING'].includes(record.status) &&
hasAnyPermission(permissionsMap[props.group][props.moduleType].stop)
"
class="!mr-0" class="!mr-0"
@click="stop(record)" @click="stop(record)"
>{{ t('project.taskCenter.stop') }}</MsButton >{{ t('project.taskCenter.stop') }}
> </MsButton>
</template> </template>
</ms-base-table> </ms-base-table>
</div> </div>
@ -165,7 +179,7 @@
const { t } = useI18n(); const { t } = useI18n();
const props = defineProps<{ const props = defineProps<{
group: 'system' | 'organization' | 'project'; group: string;
moduleType: keyof typeof TaskCenterEnum; moduleType: keyof typeof TaskCenterEnum;
name: string; name: string;
}>(); }>();
@ -174,13 +188,40 @@
const permissionsMap = { const permissionsMap = {
organization: { organization: {
stop: ['ORGANIZATION_TASK_CENTER:READ+STOP'], API_CASE: {
stop: ['ORGANIZATION_TASK_CENTER:READ+STOP', 'PROJECT_API_DEFINITION_CASE:READ+EXECUTE'],
jump: ['PROJECT_API_DEFINITION_CASE:READ'],
report: ['PROJECT_API_DEFINITION_CASE:READ+EXECUTE', 'PROJECT_API_REPORT:READ'],
},
API_SCENARIO: {
stop: ['ORGANIZATION_TASK_CENTER:READ+STOP', 'PROJECT_API_SCENARIO:READ+EXECUTE'],
jump: ['PROJECT_API_SCENARIO:READ'],
report: ['PROJECT_API_SCENARIO:READ+EXECUTE', 'PROJECT_API_REPORT:READ'],
},
}, },
system: { system: {
stop: ['ORGANIZATION_TASK_CENTER:READ+STOP'], API_CASE: {
stop: ['SYSTEM_TASK_CENTER:READ'],
jump: ['PROJECT_API_DEFINITION_CASE:READ'],
report: ['PROJECT_API_DEFINITION_CASE:READ+EXECUTE', 'PROJECT_API_REPORT:READ'],
},
API_SCENARIO: {
stop: ['SYSTEM_TASK_CENTER:READ'],
jump: ['PROJECT_API_SCENARIO:READ'],
report: ['PROJECT_API_SCENARIO:READ+EXECUTE', 'PROJECT_API_REPORT:READ'],
},
}, },
project: { project: {
stop: ['PROJECT_API_REPORT:READ'], API_CASE: {
stop: ['PROJECT_API_DEFINITION_CASE:READ+EXECUTE'],
jump: ['PROJECT_API_DEFINITION_CASE:READ'],
report: ['PROJECT_API_DEFINITION_CASE:READ+EXECUTE', 'PROJECT_API_REPORT:READ'],
},
API_SCENARIO: {
stop: ['PROJECT_API_SCENARIO:READ+EXECUTE'],
jump: ['PROJECT_API_SCENARIO:READ'],
report: ['PROJECT_API_SCENARIO:READ+EXECUTE', 'PROJECT_API_REPORT:READ'],
},
}, },
}; };
@ -226,7 +267,7 @@
columnSelectorDisabled: true, columnSelectorDisabled: true,
}, },
{ {
title: 'system.project.name', title: 'project.belongProject',
dataIndex: 'projectName', dataIndex: 'projectName',
slotName: 'projectName', slotName: 'projectName',
showTooltip: true, showTooltip: true,
@ -235,7 +276,7 @@
showInTable: true, showInTable: true,
}, },
{ {
title: 'system.organization.organizationName', title: 'project.belongOrganization',
dataIndex: 'organizationName', dataIndex: 'organizationName',
slotName: 'organizationName', slotName: 'organizationName',
showTooltip: true, showTooltip: true,
@ -376,6 +417,7 @@
{ {
label: 'project.taskCenter.batchStop', label: 'project.taskCenter.batchStop',
eventTag: 'batchStop', eventTag: 'batchStop',
permission: permissionsMap[props.group][props.moduleType].stop,
}, },
// { // {
// label: 'project.taskCenter.batchExecution', // label: 'project.taskCenter.batchExecution',
@ -389,6 +431,7 @@
excludeIds: [] as string[], excludeIds: [] as string[],
condition: {}, condition: {},
}); });
function batchStopRealTask() { function batchStopRealTask() {
openModal({ openModal({
type: 'warning', type: 'warning',
@ -478,6 +521,7 @@
const activeReportIndex = ref<number>(0); const activeReportIndex = ref<number>(0);
const showDetailDrawer = ref<boolean>(false); const showDetailDrawer = ref<boolean>(false);
const showCaseDetailDrawer = ref<boolean>(false); const showCaseDetailDrawer = ref<boolean>(false);
function viewReport(id: string, rowIndex: number) { function viewReport(id: string, rowIndex: number) {
if (props.moduleType === 'API_CASE') { if (props.moduleType === 'API_CASE') {
showCaseDetailDrawer.value = true; showCaseDetailDrawer.value = true;
@ -497,6 +541,7 @@
} }
} }
); );
/** /**
* 跳转接口用例详情 * 跳转接口用例详情
*/ */
@ -508,7 +553,7 @@
} }
if (props.moduleType === 'API_SCENARIO') { if (props.moduleType === 'API_SCENARIO') {
openNewPage(RouteEnum.API_TEST_SCENARIO, { openNewPage(RouteEnum.API_TEST_SCENARIO, {
sId: id, id,
}); });
} }
} }

View File

@ -2,12 +2,26 @@
<div class="flex items-center justify-start"> <div class="flex items-center justify-start">
<MsIcon :type="getExecutionResult().icon" :class="getExecutionResult()?.color" size="14" /> <MsIcon :type="getExecutionResult().icon" :class="getExecutionResult()?.color" size="14" />
<span class="ml-1">{{ t(getExecutionResult().label) }}</span> <span class="ml-1">{{ t(getExecutionResult().label) }}</span>
<a-tooltip v-if="props.scriptIdentifier" :content="t('report.detail.scenario.errorTip')">
<MsTag
class="ml-2"
:self-style="{
border: `1px solid ${methodColor}`,
color: methodColor,
backgroundColor: 'white',
}"
>
{{ t('report.detail.script.error') }}
</MsTag>
</a-tooltip>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { TaskCenterEnum } from '@/enums/taskCenter'; import { TaskCenterEnum } from '@/enums/taskCenter';
@ -16,6 +30,7 @@
const props = defineProps<{ const props = defineProps<{
status: string; status: string;
moduleType: keyof typeof TaskCenterEnum; moduleType: keyof typeof TaskCenterEnum;
scriptIdentifier?: string;
}>(); }>();
export interface IconType { export interface IconType {
@ -173,6 +188,7 @@
function getExecutionResult(): IconType { function getExecutionResult(): IconType {
return iconTypeStatus.value[props.moduleType][props.status]; return iconTypeStatus.value[props.moduleType][props.status];
} }
const methodColor = 'rgb(var(--warning-7))';
</script> </script>
<style scoped></style> <style scoped></style>

View File

@ -5,14 +5,17 @@
<!-- <a-button type="primary"> <!-- <a-button type="primary">
{{ t('project.taskCenter.createTask') }} {{ t('project.taskCenter.createTask') }}
</a-button>--> </a-button>-->
<a-input-search <div class="flex items-center"></div>
v-model:model-value="keyword" <div class="items-right flex gap-[8px]">
:placeholder="t('system.organization.searchIndexPlaceholder')" <a-input-search
allow-clear v-model:model-value="keyword"
class="mx-[8px] w-[240px]" :placeholder="t('system.organization.searchIndexPlaceholder')"
@search="searchList" allow-clear
@press-enter="searchList" class="mx-[8px] w-[240px]"
></a-input-search> @search="searchList"
@press-enter="searchList"
></a-input-search>
</div>
</div> </div>
<ms-base-table <ms-base-table
v-bind="propsRes" v-bind="propsRes"
@ -23,19 +26,27 @@
> >
<template #resourceNum="{ record }"> <template #resourceNum="{ record }">
<div <div
v-if="
props.moduleType === TaskCenterEnum.API_SCENARIO &&
hasAnyPermission(permissionsMap[props.group][props.moduleType].jump)
"
type="text" type="text"
class="one-line-text flex w-full text-[rgb(var(--primary-5))]" class="one-line-text flex w-full text-[rgb(var(--primary-5))]"
@click="showDetail(record.resourceId)" @click="showDetail(record.resourceId)"
>{{ record.resourceNum }}</div >{{ record.resourceNum }}
> </div>
</template> </template>
<template #resourceName="{ record }"> <template #resourceName="{ record }">
<div <div
v-if="
props.moduleType === TaskCenterEnum.API_SCENARIO &&
hasAnyPermission(permissionsMap[props.group][props.moduleType].jump)
"
type="text" type="text"
class="one-line-text flex w-full text-[rgb(var(--primary-5))]" class="one-line-text flex w-full text-[rgb(var(--primary-5))]"
@click="showDetail(record.resourceId)" @click="showDetail(record.resourceId)"
>{{ record.resourceName }}</div >{{ record.resourceName }}
> </div>
</template> </template>
<template #resourceType="{ record }"> <template #resourceType="{ record }">
<div type="text" class="flex w-full">{{ t(resourceTypeMap[record.resourceType].label) }}</div> <div type="text" class="flex w-full">{{ t(resourceTypeMap[record.resourceType].label) }}</div>
@ -45,7 +56,7 @@
v-model:model-value="record.value" v-model:model-value="record.value"
:placeholder="t('common.pleaseSelect')" :placeholder="t('common.pleaseSelect')"
class="param-input w-full min-w-[250px]" class="param-input w-full min-w-[250px]"
:disabled="!record.enable" :disabled="!record.enable || !hasAnyPermission(permissionsMap[props.group][props.moduleType].edit)"
@change="() => changeRunRules(record)" @change="() => changeRunRules(record)"
> >
<a-option v-for="item of syncFrequencyOptions" :key="item.value" :value="item.value"> <a-option v-for="item of syncFrequencyOptions" :key="item.value" :value="item.value">
@ -62,9 +73,15 @@
size="small" size="small"
type="line" type="line"
:before-change="() => handleBeforeEnableChange(record)" :before-change="() => handleBeforeEnableChange(record)"
:disabled="!hasAnyPermission(permissionsMap[props.group][props.moduleType].edit)"
/> />
<a-divider direction="vertical" /> <a-divider direction="vertical" />
<MsButton class="!mr-0" @click="delSchedule(record)">{{ t('common.delete') }}</MsButton> <MsButton
class="!mr-0"
:disabled="!hasAnyPermission(permissionsMap[props.group][props.moduleType].edit)"
@click="delSchedule(record)"
>{{ t('common.delete') }}
</MsButton>
<!-- TODO这一版不上 --> <!-- TODO这一版不上 -->
<!-- <a-divider direction="vertical" /> <!-- <a-divider direction="vertical" />
<MsButton class="!mr-0" @click="edit(record)">{{ t('common.edit') }}</MsButton> <MsButton class="!mr-0" @click="edit(record)">{{ t('common.edit') }}</MsButton>
@ -86,20 +103,33 @@
import useTable from '@/components/pure/ms-table/useTable'; import useTable from '@/components/pure/ms-table/useTable';
import type { ActionsItem } from '@/components/pure/ms-table-more-action/types'; import type { ActionsItem } from '@/components/pure/ms-table-more-action/types';
import { switchDefinitionSchedule } from '@/api/modules/api-test/management';
import { import {
batchDisableScheduleOrgTask,
batchDisableScheduleProTask,
batchDisableScheduleSysTask,
batchEnableScheduleOrgTask,
batchEnableScheduleProTask,
batchEnableScheduleSysTask,
deleteScheduleOrgTask,
deleteScheduleProTask,
deleteScheduleSysTask, deleteScheduleSysTask,
enableScheduleOrgTask,
enableScheduleProTask,
enableScheduleSysTask,
getScheduleOrgApiCaseList, getScheduleOrgApiCaseList,
getScheduleProApiCaseList, getScheduleProApiCaseList,
getScheduleSysApiCaseList, getScheduleSysApiCaseList,
switchSchedule,
updateRunRules, updateRunRules,
updateRunRulesOrg,
updateRunRulesPro,
} from '@/api/modules/project-management/taskCenter'; } from '@/api/modules/project-management/taskCenter';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import useOpenNewPage from '@/hooks/useOpenNewPage'; import useOpenNewPage from '@/hooks/useOpenNewPage';
import { useTableStore } from '@/store'; import { useTableStore } from '@/store';
import { hasAnyPermission } from '@/utils/permission';
import { BatchApiParams } from '@/models/common';
import { TimingTaskCenterApiCaseItem } from '@/models/projectManagement/taskCenter'; import { TimingTaskCenterApiCaseItem } from '@/models/projectManagement/taskCenter';
import { RouteEnum } from '@/enums/routeEnum'; import { RouteEnum } from '@/enums/routeEnum';
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
@ -114,7 +144,7 @@
const { t } = useI18n(); const { t } = useI18n();
const props = defineProps<{ const props = defineProps<{
group: 'system' | 'organization' | 'project'; group: string;
moduleType: keyof typeof TaskCenterEnum; moduleType: keyof typeof TaskCenterEnum;
name: string; name: string;
}>(); }>();
@ -141,15 +171,6 @@
columnSelectorDisabled: true, columnSelectorDisabled: true,
showInTable: true, showInTable: true,
}, },
{
title: 'project.taskCenter.resourceClassification',
dataIndex: 'resourceType',
slotName: 'resourceType',
showInTable: true,
width: 150,
showDrag: true,
showTooltip: true,
},
{ {
title: 'project.taskCenter.operationRule', title: 'project.taskCenter.operationRule',
dataIndex: 'value', dataIndex: 'value',
@ -183,10 +204,10 @@
showInTable: true, showInTable: true,
width: 200, width: 200,
showDrag: true, showDrag: true,
// sortable: { sortable: {
// sortDirections: ['ascend', 'descend'], sortDirections: ['ascend', 'descend'],
// sorter: true, sorter: true,
// }, },
}, },
{ {
title: 'common.operation', title: 'common.operation',
@ -205,13 +226,64 @@
]; ];
const loadRealMap = ref({ const loadRealMap = ref({
system: getScheduleSysApiCaseList, system: {
organization: getScheduleOrgApiCaseList, list: getScheduleSysApiCaseList,
project: getScheduleProApiCaseList, enable: enableScheduleSysTask,
delete: deleteScheduleSysTask,
edit: updateRunRules,
batchEnable: batchEnableScheduleSysTask,
batchDisable: batchDisableScheduleSysTask,
},
organization: {
list: getScheduleOrgApiCaseList,
enable: enableScheduleOrgTask,
delete: deleteScheduleOrgTask,
edit: updateRunRulesOrg,
batchEnable: batchEnableScheduleOrgTask,
batchDisable: batchDisableScheduleOrgTask,
},
project: {
list: getScheduleProApiCaseList,
enable: enableScheduleProTask,
delete: deleteScheduleProTask,
edit: updateRunRulesPro,
batchEnable: batchEnableScheduleProTask,
batchDisable: batchDisableScheduleProTask,
},
}); });
const permissionsMap = {
organization: {
API_IMPORT: {
edit: ['ORGANIZATION_TASK_CENTER:READ+STOP', 'PROJECT_API_DEFINITION:READ+IMPORT'],
},
API_SCENARIO: {
edit: ['ORGANIZATION_TASK_CENTER:READ+STOP', 'PROJECT_API_SCENARIO:READ+EXECUTE'],
jump: ['PROJECT_API_SCENARIO:READ'],
},
},
system: {
API_IMPORT: {
edit: ['SYSTEM_TASK_CENTER:READ', 'PROJECT_API_DEFINITION:READ+IMPORT'],
},
API_SCENARIO: {
edit: ['SYSTEM_TASK_CENTER:READ', 'PROJECT_API_SCENARIO:READ+EXECUTE'],
jump: ['PROJECT_API_SCENARIO:READ'],
},
},
project: {
API_IMPORT: {
edit: ['PROJECT_API_DEFINITION:READ+IMPORT'],
},
API_SCENARIO: {
edit: ['PROJECT_API_SCENARIO:READ+EXECUTE'],
jump: ['PROJECT_API_SCENARIO:READ'],
},
},
};
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable( const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
loadRealMap.value[props.group], loadRealMap.value[props.group].list,
{ {
tableKey: TableKeyEnum.TASK_SCHEDULE_TASK, tableKey: TableKeyEnum.TASK_SCHEDULE_TASK,
scroll: { scroll: {
@ -242,22 +314,21 @@
resetSelector(); resetSelector();
initData(); initData();
} }
const tableBatchActions = { const tableBatchActions = {
baseAction: [ baseAction: [
{ {
label: 'project.taskCenter.batchStop', label: 'project.taskCenter.batchEnable',
eventTag: 'batchStop', eventTag: 'batchEnable',
// permission: permissionsMap[props.group][props.moduleType].edit,
}, },
{ {
label: 'project.taskCenter.batchExecution', label: 'project.taskCenter.batchDisable',
eventTag: 'batchExecution', eventTag: 'batchDisable',
// permission: permissionsMap[props.group][props.moduleType].edit,
}, },
], ],
}; };
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {}
function edit(record: any) {} function edit(record: any) {}
function delSchedule(record: any) { function delSchedule(record: any) {
@ -273,7 +344,7 @@
maskClosable: false, maskClosable: false,
onBeforeOk: async () => { onBeforeOk: async () => {
try { try {
await deleteScheduleSysTask(record?.id as string); await loadRealMap.value[props.group].delete(props.moduleType, record?.id as string);
Message.success(t('project.taskCenter.delScheduleSuccess')); Message.success(t('project.taskCenter.delScheduleSuccess'));
initData(); initData();
} catch (error) { } catch (error) {
@ -287,7 +358,7 @@
async function handleBeforeEnableChange(record: TimingTaskCenterApiCaseItem) { async function handleBeforeEnableChange(record: TimingTaskCenterApiCaseItem) {
try { try {
await switchSchedule(record?.id as string); await loadRealMap.value[props.group].enable(props.moduleType, record?.id as string);
Message.success( Message.success(
t(record.enable ? 'project.taskCenter.disableScheduleSuccess' : 'project.taskCenter.enableScheduleSuccess') t(record.enable ? 'project.taskCenter.disableScheduleSuccess' : 'project.taskCenter.enableScheduleSuccess')
); );
@ -298,12 +369,13 @@
return false; return false;
} }
} }
/** /**
* 更新运行规则 * 更新运行规则
*/ */
async function changeRunRules(record: TimingTaskCenterApiCaseItem) { async function changeRunRules(record: TimingTaskCenterApiCaseItem) {
try { try {
await updateRunRules(record.id, record.value); await loadRealMap.value[props.group].edit(props.moduleType, record.id, record.value);
Message.success(t('common.updateSuccess')); Message.success(t('common.updateSuccess'));
} catch (error) { } catch (error) {
console.log(error); console.log(error);
@ -315,9 +387,9 @@
*/ */
function showDetail(id: string) { function showDetail(id: string) {
if (props.moduleType === 'TEST_RESOURCE') { if (props.moduleType === 'API_SCENARIO') {
openNewPage(RouteEnum.API_TEST_SCENARIO, { openNewPage(RouteEnum.API_TEST_SCENARIO, {
sId: id, id,
}); });
} }
} }
@ -330,8 +402,82 @@
}, },
]; ];
function handleMoreActionSelect(item: ActionsItem) {} const batchParams = ref<BatchApiParams>({
selectIds: [],
selectAll: false,
excludeIds: [] as string[],
condition: {},
});
function batchEnableTask() {
openModal({
type: 'warning',
title: t('project.taskCenter.batchEnableTask', { num: batchParams.value.selectIds.length }),
content: t('project.taskCenter.batchEnableTaskContent'),
okText: t('project.taskCenter.confirmEnable'),
cancelText: t('common.cancel'),
okButtonProps: {
status: 'danger',
},
onBeforeOk: async () => {
try {
const { selectIds, selectAll, excludeIds } = batchParams.value;
await loadRealMap.value[props.group].batchEnable({
selectIds: selectAll ? [] : selectIds,
selectAll,
scheduleTagType: props.moduleType,
excludeIds,
});
resetSelector();
Message.success(t('project.taskCenter.enableSuccess'));
initData();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
hideCancel: false,
});
}
function batchDisableTask() {
openModal({
type: 'warning',
title: t('project.taskCenter.batchDisableTask', { num: batchParams.value.selectIds.length }),
content: t('project.taskCenter.batchDisableTaskContent'),
okText: t('project.taskCenter.confirmDisable'),
cancelText: t('common.cancel'),
okButtonProps: {
status: 'danger',
},
onBeforeOk: async () => {
try {
const { selectIds, selectAll } = batchParams.value;
await loadRealMap.value[props.group].batchDisable({
selectIds: selectAll ? [] : selectIds,
selectAll,
scheduleTagType: props.moduleType,
});
resetSelector();
Message.success(t('project.taskCenter.disableSuccess'));
initData();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
},
hideCancel: false,
});
}
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
batchParams.value = { ...params, selectIds: params?.selectedIds || [], condition: {} };
if (event.eventTag === 'batchEnable') {
batchEnableTask();
} else if (event.eventTag === 'batchDisable') {
batchDisableTask();
}
}
onBeforeMount(() => { onBeforeMount(() => {
initData(); initData();
}); });
@ -342,6 +488,7 @@
if (val) { if (val) {
resetSelector(); resetSelector();
initData(); initData();
console.log(permissionsMap[props.group][props.moduleType].edit);
} }
} }
); );

View File

@ -64,8 +64,8 @@
const timingTabList = ref([ const timingTabList = ref([
{ {
value: TaskCenterEnum.TEST_RESOURCE, value: TaskCenterEnum.API_SCENARIO,
label: t('project.taskCenter.testResource'), label: t('project.taskCenter.apiScenario'),
}, },
{ {
value: TaskCenterEnum.API_IMPORT, value: TaskCenterEnum.API_IMPORT,
@ -84,7 +84,7 @@
if (activeTask.value === 'real') { if (activeTask.value === 'real') {
activeTab.value = TaskCenterEnum.API_CASE; activeTab.value = TaskCenterEnum.API_CASE;
} else { } else {
activeTab.value = TaskCenterEnum.TEST_RESOURCE; activeTab.value = TaskCenterEnum.API_SCENARIO;
} }
} }

View File

@ -47,4 +47,16 @@ export default {
'Deleting the scheduled task will cause the task to stop. Do you want to continue?', 'Deleting the scheduled task will cause the task to stop. Do you want to continue?',
'project.taskCenter.enableScheduleSuccess': 'Enable scheduled task successfully', 'project.taskCenter.enableScheduleSuccess': 'Enable scheduled task successfully',
'project.taskCenter.disableScheduleSuccess': 'Disable scheduled task successfully', 'project.taskCenter.disableScheduleSuccess': 'Disable scheduled task successfully',
'project.belongProject': 'Project',
'project.belongOrganization': 'Organization',
'project.taskCenter.batchEnable': 'Batch enable',
'project.taskCenter.batchDisable': 'Batch disable',
'project.taskCenter.batchEnableTask': 'Are you sure to enable {num} tasks?',
'project.taskCenter.batchDisableTask': 'Are you sure to disable {num} tasks?',
'project.taskCenter.batchEnableTaskContent': 'Enabling will execute the task',
'project.taskCenter.batchDisableTaskContent': 'Closing will affect the execution of the task',
'project.taskCenter.confirmEnable': 'Confirm enable',
'project.taskCenter.confirmDisable': 'Confirm disable',
'project.taskCenter.enableSuccess': 'Enable successfully',
'project.taskCenter.disableSuccess': 'Disable successfully',
}; };

View File

@ -45,4 +45,16 @@ export default {
'project.taskCenter.delSchedule.tip': '删除定时任务会导致任务停止,是否继续?', 'project.taskCenter.delSchedule.tip': '删除定时任务会导致任务停止,是否继续?',
'project.taskCenter.enableScheduleSuccess': '启用定时任务成功', 'project.taskCenter.enableScheduleSuccess': '启用定时任务成功',
'project.taskCenter.disableScheduleSuccess': '关闭定时任务成功', 'project.taskCenter.disableScheduleSuccess': '关闭定时任务成功',
'project.belongProject': '所属项目',
'project.belongOrganization': '所属组织',
'project.taskCenter.batchEnable': '批量开启',
'project.taskCenter.batchDisable': '批量关闭',
'project.taskCenter.batchEnableTask': '确定开启 {num} 个任务吗?',
'project.taskCenter.batchDisableTask': '确定关闭 {num} 个任务吗?',
'project.taskCenter.batchEnableTaskContent': '开启会执行任务',
'project.taskCenter.batchDisableTaskContent': '关闭后会影响任务的执行',
'project.taskCenter.confirmEnable': '确认开启',
'project.taskCenter.confirmDisable': '确认关闭',
'project.taskCenter.enableSuccess': '开启成功',
'project.taskCenter.disableSuccess': '关闭成功',
}; };