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之间
tags_size_large_than=标签数量超过{0}个
no_permission_to_resource=无操作资源的权限
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
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

View File

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

View File

@ -404,4 +404,6 @@ api_scenario.environment_id.length_range=環境ID長度必須在0-50之間
api_report_default_env=默认環境
tags_size_large_than=標籤數量不能超過{max}
no_permission_to_resource=無權限訪問資源
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.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.request.TaskCenterBatchRequest;
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.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author: LAN
@ -30,10 +35,13 @@ public class ApiTaskCenterController {
@Resource
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")
@Operation(summary = "项目-任务中心-接口用例/场景-实时任务列表")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ)
public Pager<List<TaskCenterDTO>> projectList(@Validated @RequestBody TaskCenterPageRequest request) {
return apiTaskCenterService.getProjectPage(request, SessionUtils.getCurrentProjectId());
}
@ -54,36 +62,36 @@ public class ApiTaskCenterController {
@PostMapping("/api/system/stop")
@Operation(summary = "系统-任务中心-接口用例/场景-停止任务")
@RequiresPermissions(PermissionConstants.SYSTEM_TASK_CENTER_READ)
public void systemStop(@Validated @RequestBody TaskCenterBatchRequest request) {
hasPermission(SYSTEM, request.getModuleType());
apiTaskCenterService.systemStop(request, SessionUtils.getUserId());
}
@PostMapping("/api/org/stop")
@Operation(summary = "组织-任务中心-接口用例/场景-停止任务")
@RequiresPermissions(PermissionConstants.ORGANIZATION_TASK_CENTER_READ_STOP)
public void orgStop(@Validated @RequestBody TaskCenterBatchRequest request) {
hasPermission(ORG, request.getModuleType());
apiTaskCenterService.orgStop(request, SessionUtils.getCurrentOrganizationId(), SessionUtils.getUserId());
}
@PostMapping("/api/project/stop")
@Operation(summary = "项目-任务中心-接口用例/场景-停止任务")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ)
public void projectStop(@Validated @RequestBody TaskCenterBatchRequest request) {
hasPermission(PROJECT, request.getModuleType());
apiTaskCenterService.projectStop(request, SessionUtils.getCurrentProjectId(), SessionUtils.getUserId());
}
@GetMapping("/api/project/stop/{moduleType}/{id}")
@Operation(summary = "项目-任务中心-接口用例/场景-停止任务")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ)
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");
}
@GetMapping("/api/org/stop/{moduleType}/{id}")
@Operation(summary = "组织-任务中心-接口用例/场景-停止任务")
@RequiresPermissions(PermissionConstants.ORGANIZATION_TASK_CENTER_READ_STOP)
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");
}
@ -91,8 +99,34 @@ public class ApiTaskCenterController {
@Operation(summary = "系统-任务中心-接口用例/场景-停止任务")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ)
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");
}
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}")
@Operation(summary = "接口测试-接口报告-报告获取")
@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) {
return apiReportService.get(id);
}
@ -94,7 +94,7 @@ public class ApiReportController {
@GetMapping("/get/detail/{reportId}/{stepId}")
@Operation(summary = "接口测试-接口报告-报告详情获取")
@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,
@PathVariable String stepId) {
return apiReportService.getDetail(reportId, stepId);

View File

@ -77,7 +77,7 @@ public class ApiScenarioReportController {
@GetMapping("/get/{id}")
@Operation(summary = "接口测试-接口报告-报告获取")
@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) {
return apiScenarioReportService.get(id);
}
@ -93,7 +93,7 @@ public class ApiScenarioReportController {
@GetMapping("/get/detail/{reportId}/{stepId}")
@Operation(summary = "接口测试-接口报告-报告详情获取")
@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,
@PathVariable String stepId) {
return apiScenarioReportService.getDetail(reportId, stepId);

View File

@ -142,6 +142,18 @@
and api_report.update_user in
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
</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>
</if>
</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 c ON a.api_test_case_id = c.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
and api_report.test_plan_id = 'NONE'
and api_report.start_time BETWEEN #{startTime} AND #{endTime}

View File

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

View File

@ -148,6 +148,7 @@
api_scenario_report.start_time as operationTime,
api_scenario_report.create_user as operationName,
api_scenario_report.trigger_mode,
api_scenario_report.script_identifier,
CASE
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 s on a.api_scenario_id = s.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
and api_scenario_report.test_plan_id = 'NONE'
and api_scenario_report.start_time BETWEEN #{startTime} AND #{endTime}
@ -265,6 +267,18 @@
and api_scenario_report.update_user in
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
</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>
</if>
</foreach>

View File

@ -203,7 +203,7 @@ public class ApiTaskCenterService {
}
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) {
@ -261,15 +261,17 @@ public class ApiTaskCenterService {
try {
LogUtils.info(String.format("开始发送停止请求到 %s 节点执行", endpoint), subList.toString());
TaskRunnerClient.stopApi(endpoint, subList);
} catch (Exception e) {
if (request.getModuleType().equals(TaskCenterResourceType.API_CASE.toString())) {
extApiReportMapper.updateReportStatus(subList, System.currentTimeMillis(), userId);
extApiReportMapper.updateApiCaseStatus(subList);
//记录日志
saveLog(subList, userId, path, method, module, TaskCenterResourceType.API_CASE.toString());
} else if (request.getModuleType().equals(TaskCenterResourceType.API_SCENARIO.toString())) {
extApiScenarioReportMapper.updateReportStatus(subList, System.currentTimeMillis(), userId);
extApiScenarioReportMapper.updateApiScenario(subList);
saveLog(subList, userId, path, method, module, TaskCenterResourceType.API_SCENARIO.toString());
}
} catch (Exception e) {
LogUtils.error(e);
}
});

View File

@ -274,7 +274,7 @@ public class ApiDefinitionImportUtilService {
Project project = projectMapper.selectByPrimaryKey(request.getProjectId());
List<ApiDefinitionCaseDTO> updateLists = new ArrayList<>();
//获取更新的日志
getUpdateLog(request, logData, updateLists, project, operationLogs);
apiUpdateLog(request, logData, updateLists, project, operationLogs);
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)) {
logData.forEach((k, v) -> {
ApiDefinitionDTO apiDefinitionDTO = new ApiDefinitionDTO();

View File

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

View File

@ -261,7 +261,9 @@ public class ApiScenarioReportService {
example.createCriteria().andReportIdEqualTo(id);
List<ApiScenarioReportLog> apiScenarioReportLogs = apiScenarioReportLogMapper.selectByExampleWithBLOBs(example);
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());

View File

@ -1,8 +1,14 @@
package io.metersphere.system.controller;
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.enums.ScheduleTagType;
import io.metersphere.system.dto.taskcenter.request.TaskCenterScheduleBatchRequest;
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.service.TaskCenterService;
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.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author: LAN
@ -28,11 +36,13 @@ public class TaskCenterController {
@Resource
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")
@Operation(summary = "项目-任务中心-定时任务列表")
@RequiresPermissions(PermissionConstants.PROJECT_BASE_INFO_READ)
public Pager<List<TaskCenterScheduleDTO>> projectScheduleList(@Validated @RequestBody TaskCenterSchedulePageRequest request) {
return taskCenterService.getProjectSchedulePage(request, SessionUtils.getCurrentProjectId());
}
@ -51,27 +61,145 @@ public class TaskCenterController {
return taskCenterService.getSystemSchedulePage(request);
}
@GetMapping("/schedule/delete/{id}")
@GetMapping("/system/schedule/delete/{moduleType}/{id}")
@Operation(summary = "系统-任务中心-删除定时任务")
@CheckOwner(resourceId = "#id", resourceType = "schedule")
public void delete(@PathVariable String id) {
taskCenterService.delete(id);
public void delete(@PathVariable String moduleType, @PathVariable String id) {
hasPermission(SYSTEM, moduleType);
taskCenterService.delete(id, SessionUtils.getUserId(), "/task/center/system/schedule/delete/", OperationLogModule.SETTING_SYSTEM_TASK_CENTER);
}
@GetMapping("/schedule/switch/{id}")
@Operation(summary = "系统-任务中心-关闭/开启定时任务")
@GetMapping("/org/schedule/delete/{moduleType}/{id}")
@Operation(summary = "组织-任务中心-删除定时任务")
@CheckOwner(resourceId = "#id", resourceType = "schedule")
public void enable(@PathVariable String id) {
taskCenterService.enable(id);
public void deleteOrg(@PathVariable String moduleType, @PathVariable String 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 = "系统-任务中心-修改定时任务")
@CheckOwner(resourceId = "#id", resourceType = "schedule")
public void update(@PathVariable String id, @RequestBody Object cron) {
taskCenterService.update(id, cron.toString());
public void update(@PathVariable String moduleType, @PathVariable String id, @RequestBody Object cron) {
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")
private String status;
@Schema(description = "脚本标识")
private String scriptIdentifier;
@Schema(description = "操作人")
private String operationName;

View File

@ -9,9 +9,10 @@ import java.util.List;
*/
public enum ScheduleTagType {
API_IMPORT("API_IMPORT"),
TEST_RESOURCE("API_SCENARIO", "UI_SCENARIO", "LOAD_TEST", "TEST_PLAN"),
ORDER("CLEAN_REPORT", "BUG_SYNC");
API_SCENARIO("API_SCENARIO"),
UI_SCENARIO("UI_TEST"),
LOAD_TEST("LOAD_TEST"),
TEST_PLAN("TEST_PLAN");
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_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 PROJECT_ENVIRONMENT_SETTING = "PROJECT_ENVIRONMENT_SETTING";
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.ApiTestCase;
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.request.TaskCenterScheduleBatchRequest;
import io.metersphere.system.dto.taskcenter.request.TaskCenterSchedulePageRequest;
import org.apache.ibatis.annotations.Param;
@ -17,7 +19,7 @@ public interface ExtScheduleMapper {
* @param request 列表请求参数
* @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);
@ -32,4 +34,9 @@ public interface ExtScheduleMapper {
long countQuartzCronTriggersByResourceId(String scheduleId);
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">
<mapper namespace="io.metersphere.system.mapper.ExtScheduleMapper">
<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
schedule.id,
schedule.name as taskname,
schedule.project_id,
'API_SCENARIO' as 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,
resource_type,
ads.num as resource_num,
ads.name as resource_name,
ads.id as resource_id,
@ -36,12 +20,29 @@
schedule
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
task.resource_type in
<foreach collection="resourceTypes" item="resourceType" separator="," open="(" close=")">
#{resourceType}
</foreach>
task.resource_type =#{request.scheduleTagType}
and task.project_id IN
<foreach collection="projectIds" item="projectId" separator="," open="(" close=")">
#{projectId}
@ -67,6 +68,18 @@
and task.resource_type in
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
</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>
</if>
</foreach>
@ -121,5 +134,72 @@
<select id="getScheduleByLimit" resultType="io.metersphere.system.domain.Schedule">
SELECT * FROM schedule ORDER BY create_time LIMIT #{start}, #{limit}
</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>

View File

@ -4,14 +4,22 @@ import com.github.pagehelper.Page;
import com.github.pagehelper.page.PageMethod;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.HttpMethodConstants;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.Organization;
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.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.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.schedule.BaseScheduleJob;
import io.metersphere.system.schedule.ScheduleService;
@ -19,11 +27,19 @@ import io.metersphere.system.utils.PageUtils;
import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource;
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.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.Stream;
@ -62,6 +78,10 @@ public class TaskCenterService {
@Resource
ScheduleService scheduleService;
@Resource
OperationLogService operationLogService;
@Resource
SqlSessionFactory sqlSessionFactory;
private static final String CREATE_TIME_SORT = "create_time desc";
@ -94,17 +114,13 @@ public class TaskCenterService {
List<TaskCenterScheduleDTO> list = new ArrayList<>();
if (request != null && !projectList.isEmpty()) {
List<String> projectIds = projectList.stream().map(OptionDTO::getId).toList();
ScheduleTagType scheduleTagType = ScheduleTagType.valueOf(request.getScheduleTagType());
List<String> resourceTypes = scheduleTagType.getNames();
if (!resourceTypes.isEmpty()) {
list = extScheduleMapper.taskCenterSchedulelist(request, projectIds, resourceTypes);
processTaskCenterSchedule(list, projectList, projectIds, request.getScheduleTagType());
}
list = extScheduleMapper.taskCenterSchedulelist(request, projectIds);
processTaskCenterSchedule(list, projectList, projectIds);
}
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()) {
// 组织
List<OptionDTO> orgListByProjectList = getOrgListByProjectIds(projectIds);
@ -122,44 +138,26 @@ public class TaskCenterService {
item.setCreateUserName(userMap.getOrDefault(item.getCreateUserName(), StringUtils.EMPTY));
item.setProjectName(projectMap.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);
}
private List<OptionDTO> getOrgProjectList(String orgId){
private List<OptionDTO> getOrgProjectList(String orgId) {
return baseProjectMapper.getProjectOptionsByOrgId(orgId);
}
private List<OptionDTO> getSystemProjectList(){
private List<OptionDTO> getSystemProjectList() {
return baseProjectMapper.getProjectOptions();
}
private List<OptionDTO> getOrgListByProjectIds(List<String> projectIds){
private List<OptionDTO> getOrgListByProjectIds(List<String> 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;
}
public void delete(String id) {
public void delete(String id, String userId, String path, String module) {
Schedule schedule = checkScheduleExit(id);
if (ScheduleTagType.API_IMPORT.getNames().contains(schedule.getResourceType())) {
extSwaggerMapper.deleteByPrimaryKey(schedule.getResourceId());
}
scheduleService.deleteByResourceId(schedule.getResourceId(), schedule.getJob());
saveLog(List.of(schedule), userId, path, HttpMethodConstants.GET.name(), module, OperationLogType.DELETE.name());
}
private Schedule checkScheduleExit(String id) {
@ -202,21 +201,91 @@ public class TaskCenterService {
return schedule;
}
public void enable(String id) {
public void enable(String id, String userId, String path, String module) {
Schedule schedule = checkScheduleExit(id);
schedule.setEnable(!schedule.getEnable());
scheduleService.editSchedule(schedule);
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.setValue(cron);
scheduleService.editSchedule(schedule);
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.domain.Schedule;
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.mapper.ExtSwaggerMapper;
import io.metersphere.system.mapper.ScheduleMapper;
@ -68,12 +69,12 @@ class TaskCenterScheduleControllerTests extends BaseTest {
doTaskCenterSchedulePage("KEYWORD", 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("FILTER", SCHEDULED_PROJECT_PAGE, ScheduleTagType.TEST_RESOURCE.toString());
doTaskCenterSchedulePage("KEYWORD", SCHEDULED_ORG_PAGE, ScheduleTagType.TEST_RESOURCE.toString());
doTaskCenterSchedulePage("FILTER", SCHEDULED_ORG_PAGE, ScheduleTagType.TEST_RESOURCE.toString());
doTaskCenterSchedulePage("KEYWORD", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.TEST_RESOURCE.toString());
doTaskCenterSchedulePage("FILTER", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.TEST_RESOURCE.toString());
doTaskCenterSchedulePage("KEYWORD", SCHEDULED_PROJECT_PAGE, ScheduleTagType.API_SCENARIO.toString());
doTaskCenterSchedulePage("FILTER", SCHEDULED_PROJECT_PAGE, ScheduleTagType.API_SCENARIO.toString());
doTaskCenterSchedulePage("KEYWORD", SCHEDULED_ORG_PAGE, ScheduleTagType.API_SCENARIO.toString());
doTaskCenterSchedulePage("FILTER", SCHEDULED_ORG_PAGE, ScheduleTagType.API_SCENARIO.toString());
doTaskCenterSchedulePage("KEYWORD", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.API_SCENARIO.toString());
doTaskCenterSchedulePage("FILTER", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.API_SCENARIO.toString());
}
private void doTaskCenterSchedulePage(String search, String url, String scheduleTagType) throws Exception {
@ -160,14 +161,16 @@ class TaskCenterScheduleControllerTests extends BaseTest {
String scheduleId = "1";
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);
Assertions.assertNull(schedule);
if (ScheduleTagType.API_IMPORT.getNames().contains(oldSchedule.getType())) {
int count = extSwaggerMapper.selectByPrimaryKey(oldSchedule.getResourceId());
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
@ -191,8 +194,25 @@ class TaskCenterScheduleControllerTests extends BaseTest {
scheduleService.getSchedule(schedule.getId());
scheduleService.editSchedule(schedule);
scheduleService.getScheduleByResource(schedule.getResourceId(), schedule.getJob());
this.requestGet("/task/center/schedule/switch" + "test-schedule-switch");
this.requestGet("/task/center/schedule/switch" + "test-schedule-switch");
this.requestPost("/task/center/schedule/update/" + "test-schedule-switch" ,"/0 0/2 * * * ?");
this.requestGet("/task/center/system/schedule/switch/" +"API_IMPORT/"+ "test-schedule-switch");
this.requestGet("/task/center/org/schedule/switch/" +"API_IMPORT/"+ "test-schedule-switch");
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 {
batchDisableScheduleOrgTaskUrl,
batchDisableScheduleProTaskUrl,
batchDisableScheduleSysTaskUrl,
batchEnableScheduleOrgTaskUrl,
batchEnableScheduleProTaskUrl,
batchEnableScheduleSysTaskUrl,
batchStopRealOrdApiUrl,
batchStopRealProjectApiUrl,
batchStopRealSystemApiUrl,
deleteScheduleOrgTaskUrl,
deleteScheduleProTaskUrl,
deleteScheduleSysTaskUrl,
enableSchedule,
enableScheduleOrgTaskUrl,
enableScheduleProTaskUrl,
enableScheduleSysTaskUrl,
scheduleOrgCenterListUrl,
scheduleProCenterListUrl,
scheduleSysCenterListUrl,
@ -14,7 +25,9 @@ import {
taskOrgRealCenterListUrl,
taskProRealCenterListUrl,
taskSysRealCenterListUrl,
updateRunRulesUrl,
updateScheduleOrgTaskUrl,
updateScheduleProTaskUrl,
updateScheduleSysTaskUrl,
} from '@/api/requrls/project-management/taskCenter';
import type { CommonList, TableQueryParams } from '@/models/common';
@ -69,14 +82,69 @@ export function getScheduleProApiCaseList(data: TableQueryParams) {
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) {
return MSR.get({ url: `${enableSchedule}/${id}` });
}
export function updateRunRules(id: string, data: string) {
return MSR.get({ url: `${updateRunRulesUrl}/${id}`, data });
}
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 deleteScheduleSysTaskUrl = '/task/center/schedule/delete';
// export const deleteScheduleSysTaskUrl = '/task/center/schedule/delete';
// 系统接口用例和场景停止实时任务
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 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 {
// @ts-ignore
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测试
LOAD_TEST = 'LOAD_TEST', // 性能测试
TEST_PLAN = 'TEST_PLAN', // 测试计划
TEST_RESOURCE = 'TEST_RESOURCE', // 测试资源
// TEST_RESOURCE = 'TEST_RESOURCE', // 测试资源
API_IMPORT = 'API_IMPORT', // API导入
}

View File

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

View File

@ -2,12 +2,26 @@
<div class="flex items-center justify-start">
<MsIcon :type="getExecutionResult().icon" :class="getExecutionResult()?.color" size="14" />
<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>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
import { useI18n } from '@/hooks/useI18n';
import { TaskCenterEnum } from '@/enums/taskCenter';
@ -16,6 +30,7 @@
const props = defineProps<{
status: string;
moduleType: keyof typeof TaskCenterEnum;
scriptIdentifier?: string;
}>();
export interface IconType {
@ -173,6 +188,7 @@
function getExecutionResult(): IconType {
return iconTypeStatus.value[props.moduleType][props.status];
}
const methodColor = 'rgb(var(--warning-7))';
</script>
<style scoped></style>

View File

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

View File

@ -64,8 +64,8 @@
const timingTabList = ref([
{
value: TaskCenterEnum.TEST_RESOURCE,
label: t('project.taskCenter.testResource'),
value: TaskCenterEnum.API_SCENARIO,
label: t('project.taskCenter.apiScenario'),
},
{
value: TaskCenterEnum.API_IMPORT,
@ -84,7 +84,7 @@
if (activeTask.value === 'real') {
activeTab.value = TaskCenterEnum.API_CASE;
} 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?',
'project.taskCenter.enableScheduleSuccess': 'Enable 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.enableScheduleSuccess': '启用定时任务成功',
'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': '关闭成功',
};