feat(任务中心): 系统任务中心后台任务列表查询

This commit is contained in:
WangXu10 2024-10-08 18:34:09 +08:00 committed by Craftsman
parent 44285e389a
commit 50a4a80884
16 changed files with 357 additions and 10 deletions

View File

@ -3,4 +3,8 @@ SET SESSION innodb_lock_wait_timeout = 7200;
-- 定时任务历史数据num值处理 -- 定时任务历史数据num值处理
UPDATE `schedule` set num = UUID_SHORT() % 10000000 UPDATE `schedule` set num = UUID_SHORT() % 10000000;
-- 定时任务历史数据name处理
update `schedule` set name = '定时同步缺陷' where name = 'Bug Sync Job';
update `schedule` set name = '定时同步需求' where name = 'Demand Sync Job';

View File

@ -122,4 +122,6 @@ permission.bug=Bug
# sync mode # sync mode
sync_mode.manual=Manual sync_mode.manual=Manual
sync_mode.auto=Auto sync_mode.auto=Auto
bug.sync.job=Bug sync job

View File

@ -122,4 +122,6 @@ permission.bug=缺陷
# sync mode # sync mode
sync_mode.manual=手动同步 sync_mode.manual=手动同步
sync_mode.auto=定时同步 sync_mode.auto=定时同步
bug.sync.job=定时同步缺陷

View File

@ -123,4 +123,6 @@ permission.bug=缺陷
# sync mode # sync mode
sync_mode.manual=手動同步 sync_mode.manual=手動同步
sync_mode.auto=定時同步 sync_mode.auto=定時同步
bug.sync.job=定時同步缺陷

View File

@ -296,4 +296,6 @@ case.export.system.other.columns.execute_comment=Execute comment
case.export.system.other.columns.review_comment=Review comment case.export.system.other.columns.review_comment=Review comment
export_case_task_stop=Stop export export_case_task_stop=Stop export
export_case_task_existed=Export task already exists export_case_task_existed=Export task already exists
demand.sync.job=Demand Sync Job

View File

@ -294,4 +294,6 @@ case.export.system.other.columns.execute_comment=执行评论
case.export.system.other.columns.review_comment=评审评论 case.export.system.other.columns.review_comment=评审评论
export_case_task_stop=停止导出 export_case_task_stop=停止导出
export_case_task_existed=已有导出任务 export_case_task_existed=已有导出任务
demand.sync.job=定时同步需求

View File

@ -297,4 +297,6 @@ case.export.system.other.columns.execute_comment=執行評論
case.export.system.other.columns.review_comment=評審評論 case.export.system.other.columns.review_comment=評審評論
export_case_task_stop=停止導出 export_case_task_stop=停止導出
export_case_task_existed=已有導出任務 export_case_task_existed=已有導出任務
demand.sync.job=定時同步需求

View File

@ -5,6 +5,7 @@ import io.metersphere.project.domain.ProjectApplication;
import io.metersphere.sdk.constants.ProjectApplicationType; import io.metersphere.sdk.constants.ProjectApplicationType;
import io.metersphere.sdk.constants.ScheduleResourceType; import io.metersphere.sdk.constants.ScheduleResourceType;
import io.metersphere.sdk.constants.ScheduleType; import io.metersphere.sdk.constants.ScheduleType;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.Schedule; import io.metersphere.system.domain.Schedule;
import io.metersphere.system.schedule.ScheduleService; import io.metersphere.system.schedule.ScheduleService;
import io.metersphere.system.service.BaseBugScheduleService; import io.metersphere.system.service.BaseBugScheduleService;
@ -46,7 +47,7 @@ public class BugScheduleServiceImpl implements BaseBugScheduleService {
scheduleService.addOrUpdateCronJob(s, BugSyncJob.getJobKey(projectId), BugSyncJob.getTriggerKey(projectId), BugSyncJob.class); scheduleService.addOrUpdateCronJob(s, BugSyncJob.getJobKey(projectId), BugSyncJob.getTriggerKey(projectId), BugSyncJob.class);
}, () -> { }, () -> {
Schedule request = new Schedule(); Schedule request = new Schedule();
request.setName("Bug Sync Job"); request.setName(Translator.get("bug.sync.job"));
request.setResourceId(projectId); request.setResourceId(projectId);
request.setKey(IDGenerator.nextStr()); request.setKey(IDGenerator.nextStr());
request.setProjectId(projectId); request.setProjectId(projectId);

View File

@ -5,6 +5,7 @@ import io.metersphere.project.domain.ProjectApplication;
import io.metersphere.sdk.constants.ProjectApplicationType; import io.metersphere.sdk.constants.ProjectApplicationType;
import io.metersphere.sdk.constants.ScheduleResourceType; import io.metersphere.sdk.constants.ScheduleResourceType;
import io.metersphere.sdk.constants.ScheduleType; import io.metersphere.sdk.constants.ScheduleType;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.Schedule; import io.metersphere.system.domain.Schedule;
import io.metersphere.system.schedule.ScheduleService; import io.metersphere.system.schedule.ScheduleService;
import io.metersphere.system.service.BaseDemandScheduleService; import io.metersphere.system.service.BaseDemandScheduleService;
@ -43,7 +44,7 @@ public class DemandScheduleServiceImpl implements BaseDemandScheduleService {
scheduleService.addOrUpdateCronJob(s, DemandSyncJob.getJobKey(projectId), DemandSyncJob.getTriggerKey(projectId), DemandSyncJob.class); scheduleService.addOrUpdateCronJob(s, DemandSyncJob.getJobKey(projectId), DemandSyncJob.getTriggerKey(projectId), DemandSyncJob.class);
}, () -> { }, () -> {
Schedule request = new Schedule(); Schedule request = new Schedule();
request.setName("Demand Sync Job"); request.setName(Translator.get("demand.sync.job"));
request.setResourceId(projectId); request.setResourceId(projectId);
request.setKey(IDGenerator.nextStr()); request.setKey(IDGenerator.nextStr());
request.setProjectId(projectId); request.setProjectId(projectId);

View File

@ -3,6 +3,7 @@ package io.metersphere.system.controller;
import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.dto.sdk.BasePageRequest; import io.metersphere.system.dto.sdk.BasePageRequest;
import io.metersphere.system.dto.taskhub.TaskHubDTO; import io.metersphere.system.dto.taskhub.TaskHubDTO;
import io.metersphere.system.dto.taskhub.TaskHubScheduleDTO;
import io.metersphere.system.service.BaseTaskHubService; import io.metersphere.system.service.BaseTaskHubService;
import io.metersphere.system.utils.Pager; import io.metersphere.system.utils.Pager;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
@ -32,4 +33,12 @@ public class SystemTaskHubController {
return baseTaskHubService.getTaskList(request, null, null); return baseTaskHubService.getTaskList(request, null, null);
} }
@PostMapping("/schedule/page")
@Operation(summary = "系统-任务中心-后台执行任务列表")
@RequiresPermissions(PermissionConstants.SYSTEM_SCHEDULE_TASK_CENTER_READ)
public Pager<List<TaskHubScheduleDTO>> scheduleList(@Validated @RequestBody BasePageRequest request) {
return baseTaskHubService.getScheduleTaskList(request, null);
}
} }

View File

@ -0,0 +1,63 @@
package io.metersphere.system.dto.taskhub;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author wx
*/
@Data
public class TaskHubScheduleDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "所属组织")
private String organizationName;
@Schema(description = "所属项目")
private String projectName;
@Schema(description = "项目id")
private String projectId;
@Schema(description = "组织id")
private String organizationId;
@Schema(description = "任务id")
private String id;
@Schema(description = "任务名称")
private String taskName;
@Schema(description = "资源Id")
private String resourceId;
@Schema(description = "资源业务id")
private Long num;
@Schema(description = "类型")
private String resourceType;
@Schema(description = "运行规则cron表达式")
private String value;
@Schema(description = "下次执行时间")
private Long nextTime;
@Schema(description = "任务状态")
private boolean enable;
@Schema(description = "操作人")
private String createUserId;
@Schema(description = "操作人")
private String createUserName;
@Schema(description = "操作时间")
private Long createTime;
}

View File

@ -4,9 +4,11 @@ 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.ProjectDTO;
import io.metersphere.system.dto.sdk.BasePageRequest;
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.TaskCenterScheduleBatchRequest;
import io.metersphere.system.dto.taskcenter.request.TaskCenterSchedulePageRequest; import io.metersphere.system.dto.taskcenter.request.TaskCenterSchedulePageRequest;
import io.metersphere.system.dto.taskhub.TaskHubScheduleDTO;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@ -41,4 +43,6 @@ public interface ExtScheduleMapper {
int countByProjectIds(@Param("ids") List<String> ids); int countByProjectIds(@Param("ids") List<String> ids);
List<TaskHubScheduleDTO> selectScheduleList(@Param("request") BasePageRequest request, @Param("projectIds") List<String> projectIds);
} }

View File

@ -249,4 +249,167 @@
</if> </if>
</select> </select>
<select id="selectScheduleList" resultType="io.metersphere.system.dto.taskhub.TaskHubScheduleDTO">
select task.* from (
<!-- api导入 -->
SELECT
schedule.id,
schedule.project_id,
resource_type,
schedule.num as num,
ads.name as taskname,
ads.id as resource_id,
schedule.value,
schedule.enable,
schedule.create_user AS createUserName,
schedule.create_time,
QRTZ_TRIGGERS.NEXT_FIRE_TIME AS next_time,
project.organization_id,
project.name as projectName
FROM
schedule
inner join api_definition_swagger ads on schedule.resource_id = ads.id
left join project on schedule.project_id = project.id
left join QRTZ_TRIGGERS on ads.id = QRTZ_TRIGGERS.TRIGGER_NAME
union all
<!-- 接口场景 -->
SELECT
schedule.id,
schedule.project_id,
resource_type,
schedule.num as num,
api_scenario.name as taskname,
api_scenario.id as resource_id,
schedule.value,
schedule.enable,
schedule.create_user AS createUserName,
schedule.create_time,
QRTZ_TRIGGERS.NEXT_FIRE_TIME AS next_time,
project.organization_id,
project.name as projectName
FROM
schedule
inner join api_scenario on schedule.resource_id = api_scenario.id
left join project on schedule.project_id = project.id
left join QRTZ_TRIGGERS on api_scenario.id = QRTZ_TRIGGERS.TRIGGER_NAME
union all
<!-- 测试计划 -->
SELECT
schedule.id,
schedule.project_id,
resource_type,
schedule.num as num,
test_plan.name as taskname,
test_plan.id as resource_id,
schedule.value,
schedule.enable,
schedule.create_user AS createUserName,
schedule.create_time,
QRTZ_TRIGGERS.NEXT_FIRE_TIME AS next_time,
project.organization_id,
project.name as projectName
FROM
schedule
inner join test_plan on schedule.resource_id = test_plan.id
left join project on schedule.project_id = project.id
left join QRTZ_TRIGGERS on test_plan.id = QRTZ_TRIGGERS.TRIGGER_NAME
union all
<!-- 缺陷 -->
SELECT DISTINCT
schedule.id,
schedule.project_id,
resource_type,
schedule.num as num,
schedule.name as taskname,
'' as resource_id,
schedule.value,
schedule.enable,
schedule.create_user AS createUserName,
schedule.create_time,
QRTZ_TRIGGERS.NEXT_FIRE_TIME AS next_time,
project.organization_id,
project.name as projectName
FROM
schedule
left join project on schedule.project_id = project.id
left join QRTZ_TRIGGERS on schedule.job = QRTZ_TRIGGERS.JOB_GROUP and schedule.resource_id =
QRTZ_TRIGGERS.TRIGGER_NAME
where resource_type = 'BUG_SYNC'
union all
<!-- 需求 -->
SELECT DISTINCT
schedule.id,
schedule.project_id,
resource_type,
schedule.num as num,
schedule.name as taskname,
'' as resource_id,
schedule.value,
schedule.enable,
schedule.create_user AS createUserId,
schedule.create_time,
QRTZ_TRIGGERS.NEXT_FIRE_TIME AS nextTime,
project.organization_id,
project.name as projectName
FROM
schedule
left join project on schedule.project_id = project.id
left join QRTZ_TRIGGERS on schedule.job = QRTZ_TRIGGERS.JOB_GROUP and schedule.resource_id =
QRTZ_TRIGGERS.TRIGGER_NAME
where resource_type ='DEMAND_SYNC'
) task
<where>
<include refid="taskCenterQuery">
<property name="request" value="request"/>
<property name="projectIds" value="projectIds"/>
</include>
</where>
</select>
<sql id="taskCenterQuery">
<if test="projectIds != null and projectIds.size() > 0">
and task.project_id IN
<foreach collection="projectIds" item="projectId" separator="," open="(" close=")">
#{projectId}
</foreach>
</if>
<if test="request.keyword != null and request.keyword != ''">
and (
task.taskname like concat('%', #{request.keyword},'%')
or
task.num like concat('%', #{request.keyword},'%')
)
</if>
<include refid="taskCenterFilters">
<property name="filter" value="request.filter"/>
</include>
</sql>
<sql id="taskCenterFilters">
<if test="${filter} != null and ${filter}.size() > 0">
<foreach collection="${filter}.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key=='resourceType'">
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 task.organization_id in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
</choose>
</if>
</foreach>
</if>
</sql>
</mapper> </mapper>

View File

@ -3,16 +3,26 @@ package io.metersphere.system.service;
import com.github.pagehelper.Page; import com.github.pagehelper.Page;
import com.github.pagehelper.page.PageMethod; import com.github.pagehelper.page.PageMethod;
import io.metersphere.system.dto.sdk.BasePageRequest; import io.metersphere.system.dto.sdk.BasePageRequest;
import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.dto.taskhub.TaskHubDTO; import io.metersphere.system.dto.taskhub.TaskHubDTO;
import io.metersphere.system.dto.taskhub.TaskHubScheduleDTO;
import io.metersphere.system.mapper.ExtExecTaskMapper; import io.metersphere.system.mapper.ExtExecTaskMapper;
import io.metersphere.system.mapper.ExtOrganizationMapper;
import io.metersphere.system.mapper.ExtScheduleMapper;
import io.metersphere.system.utils.PageUtils; 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.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
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.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* @author wx * @author wx
@ -23,7 +33,12 @@ public class BaseTaskHubService {
@Resource @Resource
private ExtExecTaskMapper extExecTaskMapper; private ExtExecTaskMapper extExecTaskMapper;
@Resource
private ExtScheduleMapper extScheduleMapper;
@Resource
ExtOrganizationMapper extOrganizationMapper;
@Resource
UserLoginService userLoginService;
/** /**
* 系统-获取执行任务列表 * 系统-获取执行任务列表
@ -44,4 +59,48 @@ public class BaseTaskHubService {
} }
/**
* 系统-获取后台执行任务列表
*
* @param request
* @param projectIds
* @return
*/
public Pager<List<TaskHubScheduleDTO>> getScheduleTaskList(BasePageRequest request, List<String> projectIds) {
Page<Object> page = PageMethod.startPage(request.getCurrent(), request.getPageSize(),
StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "create_time desc");
return PageUtils.setPageInfo(page, getSchedulePage(request, projectIds));
}
private List<TaskHubScheduleDTO> getSchedulePage(BasePageRequest request, List<String> projectIds) {
List<TaskHubScheduleDTO> list = extScheduleMapper.selectScheduleList(request, projectIds);
processTaskCenterSchedule(list, projectIds);
return list;
}
private void processTaskCenterSchedule(List<TaskHubScheduleDTO> list, List<String> projectIds) {
if (CollectionUtils.isNotEmpty(list)) {
if (CollectionUtils.isEmpty(projectIds)) {
projectIds = list.stream().map(TaskHubScheduleDTO::getProjectId).collect(Collectors.toList());
}
// 组织
List<OptionDTO> orgListByProjectList = getOrgListByProjectIds(projectIds);
Map<String, String> orgMap = orgListByProjectList.stream().collect(Collectors.toMap(OptionDTO::getId, OptionDTO::getName));
// 取所有的userid
Set<String> userSet = list.stream()
.flatMap(item -> Stream.of(item.getCreateUserName()))
.collect(Collectors.toSet());
Map<String, String> userMap = userLoginService.getUserNameMap(new ArrayList<>(userSet));
list.forEach(item -> {
item.setCreateUserName(userMap.getOrDefault(item.getCreateUserName(), StringUtils.EMPTY));
item.setOrganizationName(orgMap.getOrDefault(item.getProjectId(), StringUtils.EMPTY));
});
}
}
private List<OptionDTO> getOrgListByProjectIds(List<String> projectIds) {
return extOrganizationMapper.getOrgListByProjectIds(projectIds);
}
} }

View File

@ -22,6 +22,7 @@ public class BaseTaskHubControllerTests extends BaseTest {
* 系统任务中心测试用例 * 系统任务中心测试用例
*/ */
public static final String SYSTEM_TASK_PAGE = "/system/task-center/exec-task/page"; public static final String SYSTEM_TASK_PAGE = "/system/task-center/exec-task/page";
public static final String SYSTEM_SCHEDULE_TASK_PAGE = "/system/task-center/schedule/page";
@Test @Test
@Order(1) @Order(1)
@ -40,6 +41,25 @@ public class BaseTaskHubControllerTests extends BaseTest {
} }
/**
* 系统后台任务
*/
@Test
@Order(2)
public void getSystemSchedulePage() throws Exception {
BasePageRequest request = new BasePageRequest();
this.requestPost(SYSTEM_SCHEDULE_TASK_PAGE, request);
request.setCurrent(1);
request.setPageSize(10);
MvcResult mvcResult = this.requestPostWithOkAndReturn(SYSTEM_SCHEDULE_TASK_PAGE, request);
// 获取返回值
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
// 返回请求正常
Assertions.assertNotNull(resultHolder);
}
/** /**
* 组织任务中心测试用例 * 组织任务中心测试用例
*/ */

View File

@ -3,3 +3,14 @@ VALUES
('1', 1, '测试任务1', 'SUCCESS', 10, 'SUCCESS', 'FUNCTIONAL', 'API', '100001100001', '100001', 1727676089639, 'wx', 1727676089639, 1727676089639), ('1', 1, '测试任务1', 'SUCCESS', 10, 'SUCCESS', 'FUNCTIONAL', 'API', '100001100001', '100001', 1727676089639, 'wx', 1727676089639, 1727676089639),
('2', 2, '测试任务2', 'SUCCESS', 11, 'SUCCESS', 'FUNCTIONAL', 'API', '12345567', '11234', 1727676089639, 'wx', 1727676089639, 1727676089639), ('2', 2, '测试任务2', 'SUCCESS', 11, 'SUCCESS', 'FUNCTIONAL', 'API', '12345567', '11234', 1727676089639, 'wx', 1727676089639, 1727676089639),
('3', 3, '测试任务3', 'SUCCESS', 11, 'SUCCESS', 'FUNCTIONAL', 'API', '100001100001', '11234', 1727676089639, 'wx', 1727676089639, 1727676089639); ('3', 3, '测试任务3', 'SUCCESS', 11, 'SUCCESS', 'FUNCTIONAL', 'API', '100001100001', '11234', 1727676089639, 'wx', 1727676089639, 1727676089639);
INSERT INTO `schedule` (`id`, `key`, `type`, `value`, `job`, `resource_type`, `enable`, `resource_id`, `create_user`, `create_time`, `update_time`, `project_id`, `name`, `config`, `num`)
VALUES
('wx_1', 'wx_key_1', 'cron', '1233213', 'JobClass1', 'API_IMPORT', b'1', 'NONE', 'admin', 1640776000000, 1640777000000, '100001100001', 'Schedule 1', '{\"param1\": \"value1\", \"param2\": \"value2\"}', 100),
('wx_2', 'wx_key_2', 'cron', '1231321231', 'JobClass15', 'BUG_SYNC', b'0', 'NONE', 'admin', 1640777400000, 1640778400000, '100001100001', 'Schedule 15', '', 101),
('wx_3', 'wx_key_3', 'cron', '50 15 10 20 05 ?', 'JobClass22', 'DEMAND_SYNC', b'1', 'NONE', 'admin', 1640778100000, 1640779100000, '100001100001', 'Schedule 22', '', 102),
('wx_4', 'wx_key_4', 'cron', '59 46 16 01 06 ?', 'JobClass29', 'API_SCENARIO', b'1', 'NONE', 'admin', 1640778800000, 1640779800000, '100001100001', 'Schedule 29', '{\"param1\": \"value1\", \"param2\": \"value2\"}', 103),
('wx_5', 'wx_key_5', 'cron', '59 46 16 01 06 ?', 'JobClass29', 'TEST_PLAN', b'1', 'NONE', 'admin', 1640778800000, 1640779800000, '100001100001', 'Schedule 29', '{\"param1\": \"value1\", \"param2\": \"value2\"}', 104);