软件编程
位置:首页>> 软件编程>> java编程>> Springboot Vue可配置调度任务实现示例详解

Springboot Vue可配置调度任务实现示例详解

作者:harhar  发布时间:2023-11-09 03:33:19 

标签:Springboot,Vue,配置,任务调度

Springboot + Vue,定时任务调度的全套实现方案。

这里用了quartz这个框架,实现分布式调度任务很不错,关于quarz的使用方式改天补一篇。相当简单。

1、表结构:

sys_job




列名数据类型长度是否可空是否主键说明
job_idbigint
任务ID
job_namevarchar64任务名称
job_groupvarchar64任务组名
invoke_targetvarchar500调用目标字符串
cron_expressionvarchar255cron执行表达式
misfire_policyvarchar20计划执行错误策略(1立即执行 2执行一次 3放弃执行)
concurrentchar1是否并发执行(0允许 1禁止)
statuschar1状态(0正常 1暂停)
create_byvarchar64创建者
create_timedatetime
创建时间
update_byvarchar64更新者
update_timedatetime
更新时间
remarkvarchar500备注信息

2、接口:

@RestController
@RequestMapping("/job")
public class SysJobController extends BaseController
{
   @Autowired
   private ISysJobService jobService;

   /**
    * 查询定时任务列表
    */
   @GetMapping("/list")
   public TableDataInfo list(SysJob sysJob)
   {
       startPage();
       List<SysJob> list = jobService.selectJobList(sysJob);
       return getDataTable(list);
   }

   /**
    * 导出定时任务列表
    */
   @PostMapping("/export")
   public void export(HttpServletResponse response, SysJob sysJob)
   {
       List<SysJob> list = jobService.selectJobList(sysJob);
       ExcelUtil<SysJob> util = new ExcelUtil<SysJob>(SysJob.class);
       util.exportExcel(response, list, "定时任务");
   }

   /**
    * 获取定时任务详细信息
    */
   @GetMapping(value = "/{jobId}")
   public AjaxResult getInfo(@PathVariable("jobId") Long jobId)
   {
       return success(jobService.selectJobById(jobId));
   }

   /**
    * 新增定时任务
    */
   @PostMapping
   public AjaxResult add(@RequestBody SysJob job) throws SchedulerException, TaskException
   {
       if (!CronUtils.isValid(job.getCronExpression()))
       {
           return error("新增任务'" + job.getJobName() + "'失败,Cron表达式不正确");
       }
       else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
       {
           return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
       }
       else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
       {
           return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
       }
       else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
       {
           return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
       }
       else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
       {
           return error("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规");
       }
       else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
       {
           return error("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
       }
       job.setCreateBy(getUsername());
       return toAjax(jobService.insertJob(job));
   }

   /**
    * 修改定时任务
    */
   @PutMapping
   public AjaxResult edit(@RequestBody SysJob job) throws SchedulerException, TaskException
   {
       if (!CronUtils.isValid(job.getCronExpression()))
       {
           return error("修改任务'" + job.getJobName() + "'失败,Cron表达式不正确");
       }
       else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
       {
           return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
       }
       else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
       {
           return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
       }
       else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
       {
           return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
       }
       else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
       {
           return error("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规");
       }
       else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
       {
           return error("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
       }
       job.setUpdateBy(getUsername());
       return toAjax(jobService.updateJob(job));
   }

   /**
    * 定时任务状态修改
    */
   @PutMapping("/changeStatus")
   public AjaxResult changeStatus(@RequestBody SysJob job) throws SchedulerException
   {
       SysJob newJob = jobService.selectJobById(job.getJobId());
       newJob.setStatus(job.getStatus());
       return toAjax(jobService.changeStatus(newJob));
   }

   /**
    * 定时任务立即执行一次
    */
   @PutMapping("/run")
   public AjaxResult run(@RequestBody SysJob job) throws SchedulerException
   {
       boolean result = jobService.run(job);
       return result ? success() : error("任务不存在或已过期!");
   }

   /**
    * 删除定时任务
    */
   @DeleteMapping("/{jobIds}")
   public AjaxResult remove(@PathVariable Long[] jobIds) throws SchedulerException, TaskException
   {
       jobService.deleteJobByIds(jobIds);
       return success();
   }
复制代码

3、业务层:

public interface ISysJobService
{
   /**
    * 获取quartz调度器的计划任务
    *
    * @param job 调度信息
    * @return 调度任务集合
    */
   public List<SysJob> selectJobList(SysJob job);

   /**
    * 通过调度任务ID查询调度信息
    *
    * @param jobId 调度任务ID
    * @return 调度任务对象信息
    */
   public SysJob selectJobById(Long jobId);

   /**
    * 暂停任务
    *
    * @param job 调度信息
    * @return 结果
    */
   public int pauseJob(SysJob job) throws SchedulerException;

   /**
    * 恢复任务
    *
    * @param job 调度信息
    * @return 结果
    */
   public int resumeJob(SysJob job) throws SchedulerException;

   /**
    * 删除任务后,所对应的trigger也将被删除
    *
    * @param job 调度信息
    * @return 结果
    */
   public int deleteJob(SysJob job) throws SchedulerException;

   /**
    * 批量删除调度信息
    *
    * @param jobIds 需要删除的任务ID
    * @return 结果
    */
   public void deleteJobByIds(Long[] jobIds) throws SchedulerException;

   /**
    * 任务调度状态修改
    *
    * @param job 调度信息
    * @return 结果
    */
   public int changeStatus(SysJob job) throws SchedulerException;

   /**
    * 立即运行任务
    *
    * @param job 调度信息
    * @return 结果
    */
   public boolean run(SysJob job) throws SchedulerException;

   /**
    * 新增任务
    *
    * @param job 调度信息
    * @return 结果
    */
   public int insertJob(SysJob job) throws SchedulerException, TaskException;

   /**
    * 更新任务
    *
    * @param job 调度信息
    * @return 结果
    */
   public int updateJob(SysJob job) throws SchedulerException, TaskException;

   /**
    * 校验cron表达式是否有效
    *
    * @param cronExpression 表达式
    * @return 结果
    */
   public boolean checkCronExpressionIsValid(String cronExpression);
}
复制代码
@Service
public class SysJobServiceImpl implements ISysJobService
{
   @Autowired
   private Scheduler scheduler;

   @Autowired
   private SysJobMapper jobMapper;

   /**
    * 项目启动时,初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据)
    */
   @PostConstruct
   public void init() throws SchedulerException, TaskException
   {
       scheduler.clear();
       List<SysJob> jobList = jobMapper.selectJobAll();
       for (SysJob job : jobList)
       {
           ScheduleUtils.createScheduleJob(scheduler, job);
       }
   }

   /**
    * 获取quartz调度器的计划任务列表
    *
    * @param job 调度信息
    * @return
    */
   @Override
   public List<SysJob> selectJobList(SysJob job)
   {
       return jobMapper.selectJobList(job);
   }

   /**
    * 通过调度任务ID查询调度信息
    *
    * @param jobId 调度任务ID
    * @return 调度任务对象信息
    */
   @Override
   public SysJob selectJobById(Long jobId)
   {
       return jobMapper.selectJobById(jobId);
   }

   /**
    * 暂停任务
    *
    * @param job 调度信息
    */
   @Override
   @Transactional(rollbackFor = Exception.class)
   public int pauseJob(SysJob job) throws SchedulerException
   {
       Long jobId = job.getJobId();
       String jobGroup = job.getJobGroup();
       job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
       int rows = jobMapper.updateJob(job);
       if (rows > 0)
       {
           scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
       }
       return rows;
   }

   /**
    * 恢复任务
    *
    * @param job 调度信息
    */
   @Override
   @Transactional(rollbackFor = Exception.class)
   public int resumeJob(SysJob job) throws SchedulerException
   {
       Long jobId = job.getJobId();
       String jobGroup = job.getJobGroup();
       job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
       int rows = jobMapper.updateJob(job);
       if (rows > 0)
       {
           scheduler.resumeJob(ScheduleUtils.getJobKey(jobId, jobGroup));
       }
       return rows;
   }

   /**
    * 删除任务后,所对应的trigger也将被删除
    *
    * @param job 调度信息
    */
   @Override
   @Transactional(rollbackFor = Exception.class)
   public int deleteJob(SysJob job) throws SchedulerException
   {
       Long jobId = job.getJobId();
       String jobGroup = job.getJobGroup();
       int rows = jobMapper.deleteJobById(jobId);
       if (rows > 0)
       {
           scheduler.deleteJob(ScheduleUtils.getJobKey(jobId, jobGroup));
       }
       return rows;
   }

   /**
    * 批量删除调度信息
    *
    * @param jobIds 需要删除的任务ID
    * @return 结果
    */
   @Override
   @Transactional(rollbackFor = Exception.class)
   public void deleteJobByIds(Long[] jobIds) throws SchedulerException
   {
       for (Long jobId : jobIds)
       {
           SysJob job = jobMapper.selectJobById(jobId);
           deleteJob(job);
       }
   }

   /**
    * 任务调度状态修改
    *
    * @param job 调度信息
    */
   @Override
   @Transactional(rollbackFor = Exception.class)
   public int changeStatus(SysJob job) throws SchedulerException
   {
       int rows = 0;
       String status = job.getStatus();
       if (ScheduleConstants.Status.NORMAL.getValue().equals(status))
       {
           rows = resumeJob(job);
       }
       else if (ScheduleConstants.Status.PAUSE.getValue().equals(status))
       {
           rows = pauseJob(job);
       }
       return rows;
   }

   /**
    * 立即运行任务
    *
    * @param job 调度信息
    */
   @Override
   @Transactional(rollbackFor = Exception.class)
   public boolean run(SysJob job) throws SchedulerException
   {
       boolean result = false;
       Long jobId = job.getJobId();
       String jobGroup = job.getJobGroup();
       SysJob properties = selectJobById(job.getJobId());
       // 参数
       JobDataMap dataMap = new JobDataMap();
       dataMap.put(ScheduleConstants.TASK_PROPERTIES, properties);
       JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
       if (scheduler.checkExists(jobKey))
       {
           result = true;
           scheduler.triggerJob(jobKey, dataMap);
       }
       return result;
   }

   /**
    * 新增任务
    *
    * @param job 调度信息 调度信息
    */
   @Override
   @Transactional(rollbackFor = Exception.class)
   public int insertJob(SysJob job) throws SchedulerException, TaskException
   {
       job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
       int rows = jobMapper.insertJob(job);
       if (rows > 0)
       {
           ScheduleUtils.createScheduleJob(scheduler, job);
       }
       return rows;
   }

   /**
    * 更新任务的时间表达式
    *
    * @param job 调度信息
    */
   @Override
   @Transactional(rollbackFor = Exception.class)
   public int updateJob(SysJob job) throws SchedulerException, TaskException
   {
       SysJob properties = selectJobById(job.getJobId());
       int rows = jobMapper.updateJob(job);
       if (rows > 0)
       {
           updateSchedulerJob(job, properties.getJobGroup());
       }
       return rows;
   }

   /**
    * 更新任务
    *
    * @param job 任务对象
    * @param jobGroup 任务组名
    */
   public void updateSchedulerJob(SysJob job, String jobGroup) throws SchedulerException, TaskException
   {
       Long jobId = job.getJobId();
       // 判断是否存在
       JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
       if (scheduler.checkExists(jobKey))
       {
           // 防止创建时存在数据问题 先移除,然后在执行创建操作
           scheduler.deleteJob(jobKey);
       }
       ScheduleUtils.createScheduleJob(scheduler, job);
   }

   /**
    * 校验cron表达式是否有效
    *
    * @param cronExpression 表达式
    * @return 结果
    */
   @Override
   public boolean checkCronExpressionIsValid(String cronExpression)
   {
       return CronUtils.isValid(cronExpression);
   }
}
复制代码

4、Mapper

public interface SysJobMapper
{
   /**
    * 查询调度任务日志集合
    *
    * @param job 调度信息
    * @return 操作日志集合
    */
   public List<SysJob> selectJobList(SysJob job);

   /**
    * 查询所有调度任务
    *
    * @return 调度任务列表
    */
   public List<SysJob> selectJobAll();

   /**
    * 通过调度ID查询调度任务信息
    *
    * @param jobId 调度ID
    * @return 角色对象信息
    */
   public SysJob selectJobById(Long jobId);

   /**
    * 通过调度ID删除调度任务信息
    *
    * @param jobId 调度ID
    * @return 结果
    */
   public int deleteJobById(Long jobId);

   /**
    * 批量删除调度任务信息
    *
    * @param ids 需要删除的数据ID
    * @return 结果
    */
   public int deleteJobByIds(Long[] ids);

   /**
    * 修改调度任务信息
    *
    * @param job 调度任务信息
    * @return 结果
    */
   public int updateJob(SysJob job);

   /**
    * 新增调度任务信息
    *
    * @param job 调度任务信息
    * @return 结果
    */
   public int insertJob(SysJob job);
}
复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.job.quartz.mapper.SysJobMapper">

   <resultMap type="SysJob" id="SysJobResult">
       <id     property="jobId"          column="job_id"          />
       <result property="jobName"        column="job_name"        />
       <result property="jobGroup"       column="job_group"       />
       <result property="invokeTarget"   column="invoke_target"   />
       <result property="cronExpression" column="cron_expression" />
       <result property="misfirePolicy"  column="misfire_policy"  />
       <result property="concurrent"     column="concurrent"      />
       <result property="status"         column="status"          />
       <result property="createBy"       column="create_by"       />
       <result property="createTime"     column="create_time"     />
       <result property="updateBy"       column="update_by"       />
       <result property="updateTime"     column="update_time"     />
       <result property="remark"         column="remark"          />
   </resultMap>

<sql id="selectJobVo">
       select job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark
       from sys_job
   </sql>

<select id="selectJobList" parameterType="SysJob" resultMap="SysJobResult">
       <include refid="selectJobVo"/>
       <where>
           <if test="jobName != null and jobName != ''">
               AND job_name like concat('%', #{jobName}, '%')
           </if>
           <if test="jobGroup != null and jobGroup != ''">
               AND job_group = #{jobGroup}
           </if>
           <if test="status != null and status != ''">
               AND status = #{status}
           </if>
           <if test="invokeTarget != null and invokeTarget != ''">
               AND invoke_target like concat('%', #{invokeTarget}, '%')
           </if>
       </where>
   </select>

<select id="selectJobAll" resultMap="SysJobResult">
       <include refid="selectJobVo"/>
   </select>

<select id="selectJobById" parameterType="Long" resultMap="SysJobResult">
       <include refid="selectJobVo"/>
       where job_id = #{jobId}
   </select>

<delete id="deleteJobById" parameterType="Long">
       delete from sys_job where job_id = #{jobId}
   </delete>

<delete id="deleteJobByIds" parameterType="Long">
       delete from sys_job where job_id in
       <foreach collection="array" item="jobId" open="(" separator="," close=")">
           #{jobId}
       </foreach>
   </delete>

<update id="updateJob" parameterType="SysJob">
       update sys_job
       <set>
           <if test="jobName != null and jobName != ''">job_name = #{jobName},</if>
           <if test="jobGroup != null and jobGroup != ''">job_group = #{jobGroup},</if>
           <if test="invokeTarget != null and invokeTarget != ''">invoke_target = #{invokeTarget},</if>
           <if test="cronExpression != null and cronExpression != ''">cron_expression = #{cronExpression},</if>
           <if test="misfirePolicy != null and misfirePolicy != ''">misfire_policy = #{misfirePolicy},</if>
           <if test="concurrent != null and concurrent != ''">concurrent = #{concurrent},</if>
           <if test="status !=null">status = #{status},</if>
           <if test="remark != null and remark != ''">remark = #{remark},</if>
           <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
           update_time = sysdate()
       </set>
       where job_id = #{jobId}
   </update>

<insert id="insertJob" parameterType="SysJob" useGeneratedKeys="true" keyProperty="jobId">
       insert into sys_job(
           <if test="jobId != null and jobId != 0">job_id,</if>
           <if test="jobName != null and jobName != ''">job_name,</if>
           <if test="jobGroup != null and jobGroup != ''">job_group,</if>
           <if test="invokeTarget != null and invokeTarget != ''">invoke_target,</if>
           <if test="cronExpression != null and cronExpression != ''">cron_expression,</if>
           <if test="misfirePolicy != null and misfirePolicy != ''">misfire_policy,</if>
           <if test="concurrent != null and concurrent != ''">concurrent,</if>
           <if test="status != null and status != ''">status,</if>
           <if test="remark != null and remark != ''">remark,</if>
           <if test="createBy != null and createBy != ''">create_by,</if>
           create_time
       )values(
           <if test="jobId != null and jobId != 0">#{jobId},</if>
           <if test="jobName != null and jobName != ''">#{jobName},</if>
           <if test="jobGroup != null and jobGroup != ''">#{jobGroup},</if>
           <if test="invokeTarget != null and invokeTarget != ''">#{invokeTarget},</if>
           <if test="cronExpression != null and cronExpression != ''">#{cronExpression},</if>
           <if test="misfirePolicy != null and misfirePolicy != ''">#{misfirePolicy},</if>
           <if test="concurrent != null and concurrent != ''">#{concurrent},</if>
           <if test="status != null and status != ''">#{status},</if>
           <if test="remark != null and remark != ''">#{remark},</if>
           <if test="createBy != null and createBy != ''">#{createBy},</if>
           sysdate()
       )
   </insert>

</mapper>
复制代码

5、前端(Vue):

import request from '@/utils/request'

// 查询定时任务调度列表
export function listJob(query) {
 return request({
   url: '/monitor/job/list',
   method: 'get',
   params: query
 })
}

// 查询定时任务调度详细
export function getJob(jobId) {
 return request({
   url: '/monitor/job/' + jobId,
   method: 'get'
 })
}

// 新增定时任务调度
export function addJob(data) {
 return request({
   url: '/monitor/job',
   method: 'post',
   data: data
 })
}

// 修改定时任务调度
export function updateJob(data) {
 return request({
   url: '/monitor/job',
   method: 'put',
   data: data
 })
}

// 删除定时任务调度
export function delJob(jobId) {
 return request({
   url: '/monitor/job/' + jobId,
   method: 'delete'
 })
}

// 任务状态修改
export function changeJobStatus(jobId, status) {
 const data = {
   jobId,
   status
 }
 return request({
   url: '/monitor/job/changeStatus',
   method: 'put',
   data: data
 })
}


// 定时任务立即执行一次
export function runJob(jobId, jobGroup) {
 const data = {
   jobId,
   jobGroup
 }
 return request({
   url: '/monitor/job/run',
   method: 'put',
   data: data
 })
}
复制代码
import request from '@/utils/request'

// 查询调度日志列表
export function listJobLog(query) {
 return request({
   url: '/monitor/jobLog/list',
   method: 'get',
   params: query
 })
}

// 删除调度日志
export function delJobLog(jobLogId) {
 return request({
   url: '/monitor/jobLog/' + jobLogId,
   method: 'delete'
 })
}

// 清空调度日志
export function cleanJobLog() {
 return request({
   url: '/monitor/jobLog/clean',
   method: 'delete'
 })
}

复制代码
<template>
 <div class="app-container">
   <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
     <el-form-item label="任务名称" prop="jobName">
       <el-input
         v-model="queryParams.jobName"
         placeholder="请输入任务名称"
         clearable
         @keyup.enter.native="handleQuery"
       />
     </el-form-item>
     <el-form-item label="任务组名" prop="jobGroup">
       <el-select v-model="queryParams.jobGroup" placeholder="请选择任务组名" clearable>
         <el-option
           v-for="dict in dict.type.sys_job_group"
           :key="dict.value"
           :label="dict.label"
           :value="dict.value"
         />
       </el-select>
     </el-form-item>
     <el-form-item label="任务状态" prop="status">
       <el-select v-model="queryParams.status" placeholder="请选择任务状态" clearable>
         <el-option
           v-for="dict in dict.type.sys_job_status"
           :key="dict.value"
           :label="dict.label"
           :value="dict.value"
         />
       </el-select>
     </el-form-item>
     <el-form-item>
       <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
       <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
     </el-form-item>
   </el-form>

   <el-row :gutter="10" class="mb8">
     <el-col :span="1.5">
       <el-button
         type="primary"
         plain
         icon="el-icon-plus"
         size="mini"
         @click="handleAdd"
         v-hasPermi="['monitor:job:add']"
       >新增</el-button>
     </el-col>
     <el-col :span="1.5">
       <el-button
         type="success"
         plain
         icon="el-icon-edit"
         size="mini"
         :disabled="single"
         @click="handleUpdate"
         v-hasPermi="['monitor:job:edit']"
       >修改</el-button>
     </el-col>
     <el-col :span="1.5">
       <el-button
         type="danger"
         plain
         icon="el-icon-delete"
         size="mini"
         :disabled="multiple"
         @click="handleDelete"
         v-hasPermi="['monitor:job:remove']"
       >删除</el-button>
     </el-col>
     <el-col :span="1.5">
       <el-button
         type="warning"
         plain
         icon="el-icon-download"
         size="mini"
         @click="handleExport"
         v-hasPermi="['monitor:job:export']"
       >导出</el-button>
     </el-col>
     <el-col :span="1.5">
       <el-button
         type="info"
         plain
         icon="el-icon-s-operation"
         size="mini"
         @click="handleJobLog"
         v-hasPermi="['monitor:job:query']"
       >日志</el-button>
     </el-col>
     <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
   </el-row>

   <el-table v-loading="loading" :data="jobList" @selection-change="handleSelectionChange">
     <el-table-column type="selection" width="55" align="center" />
     <el-table-column label="任务编号" width="100" align="center" prop="jobId" />
     <el-table-column label="任务名称" align="center" prop="jobName" :show-overflow-tooltip="true" />
     <el-table-column label="任务组名" align="center" prop="jobGroup">
       <template slot-scope="scope">
         <dict-tag :options="dict.type.sys_job_group" :value="scope.row.jobGroup"/>
       </template>
     </el-table-column>
     <el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
     <el-table-column label="cron执行表达式" align="center" prop="cronExpression" :show-overflow-tooltip="true" />
     <el-table-column label="状态" align="center">
       <template slot-scope="scope">
         <el-switch
           v-model="scope.row.status"
           active-value="0"
           inactive-value="1"
           @change="handleStatusChange(scope.row)"
         ></el-switch>
       </template>
     </el-table-column>
     <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
       <template slot-scope="scope">
         <el-button
           size="mini"
           type="text"
           icon="el-icon-edit"
           @click="handleUpdate(scope.row)"
           v-hasPermi="['monitor:job:edit']"
         >修改</el-button>
         <el-button
           size="mini"
           type="text"
           icon="el-icon-delete"
           @click="handleDelete(scope.row)"
           v-hasPermi="['monitor:job:remove']"
         >删除</el-button>
         <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['monitor:job:changeStatus', 'monitor:job:query']">
           <el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
           <el-dropdown-menu slot="dropdown">
             <el-dropdown-item command="handleRun" icon="el-icon-caret-right"
               v-hasPermi="['monitor:job:changeStatus']">执行一次</el-dropdown-item>
             <el-dropdown-item command="handleView" icon="el-icon-view"
               v-hasPermi="['monitor:job:query']">任务详细</el-dropdown-item>
             <el-dropdown-item command="handleJobLog" icon="el-icon-s-operation"
               v-hasPermi="['monitor:job:query']">调度日志</el-dropdown-item>
           </el-dropdown-menu>
         </el-dropdown>
       </template>
     </el-table-column>
   </el-table>

   <pagination
     v-show="total>0"
     :total="total"
     :page.sync="queryParams.pageNum"
     :limit.sync="queryParams.pageSize"
     @pagination="getList"
   />

   <!-- 添加或修改定时任务对话框 -->
   <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
     <el-form ref="form" :model="form" :rules="rules" label-width="120px">
       <el-row>
         <el-col :span="12">
           <el-form-item label="任务名称" prop="jobName">
             <el-input v-model="form.jobName" placeholder="请输入任务名称" />
           </el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="任务分组" prop="jobGroup">
             <el-select v-model="form.jobGroup" placeholder="请选择任务分组">
               <el-option
                 v-for="dict in dict.type.sys_job_group"
                 :key="dict.value"
                 :label="dict.label"
                 :value="dict.value"
               ></el-option>
             </el-select>
           </el-form-item>
         </el-col>
         <el-col :span="24">
           <el-form-item prop="invokeTarget">
             <span slot="label">
               调用方法
               <el-tooltip placement="top">
                 <div slot="content">
                   Bean调用示例:ryTask.ryParams('ry')
                   <br />Class类调用示例:com.ruoyi.quartz.task.RyTask.ryParams('ry')
                   <br />参数说明:支持字符串,布尔类型,长整型,浮点型,整型
                 </div>
                 <i class="el-icon-question"></i>
               </el-tooltip>
             </span>
             <el-input v-model="form.invokeTarget" placeholder="请输入调用目标字符串" />
           </el-form-item>
         </el-col>
         <el-col :span="24">
           <el-form-item label="cron表达式" prop="cronExpression">
             <el-input v-model="form.cronExpression" placeholder="请输入cron执行表达式">
               <template slot="append">
                 <el-button type="primary" @click="handleShowCron">
                   生成表达式
                   <i class="el-icon-time el-icon--right"></i>
                 </el-button>
               </template>
             </el-input>
           </el-form-item>
         </el-col>
         <el-col :span="24">
           <el-form-item label="执行策略" prop="misfirePolicy">
             <el-radio-group v-model="form.misfirePolicy" size="small">
               <el-radio-button label="1">立即执行</el-radio-button>
               <el-radio-button label="2">执行一次</el-radio-button>
               <el-radio-button label="3">放弃执行</el-radio-button>
             </el-radio-group>
           </el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="是否并发" prop="concurrent">
             <el-radio-group v-model="form.concurrent" size="small">
               <el-radio-button label="0">允许</el-radio-button>
               <el-radio-button label="1">禁止</el-radio-button>
             </el-radio-group>
           </el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="状态">
             <el-radio-group v-model="form.status">
               <el-radio
                 v-for="dict in dict.type.sys_job_status"
                 :key="dict.value"
                 :label="dict.value"
               >{{dict.label}}</el-radio>
             </el-radio-group>
           </el-form-item>
         </el-col>
       </el-row>
     </el-form>
     <div slot="footer" class="dialog-footer">
       <el-button type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="cancel">取 消</el-button>
     </div>
   </el-dialog>

   <el-dialog title="Cron表达式生成器" :visible.sync="openCron" append-to-body destroy-on-close class="scrollbar">
     <crontab @hide="openCron=false" @fill="crontabFill" :expression="expression"></crontab>
   </el-dialog>

   <!-- 任务日志详细 -->
   <el-dialog title="任务详细" :visible.sync="openView" width="700px" append-to-body>
     <el-form ref="form" :model="form" label-width="120px" size="mini">
       <el-row>
         <el-col :span="12">
           <el-form-item label="任务编号:">{{ form.jobId }}</el-form-item>
           <el-form-item label="任务名称:">{{ form.jobName }}</el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="任务分组:">{{ jobGroupFormat(form) }}</el-form-item>
           <el-form-item label="创建时间:">{{ form.createTime }}</el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="cron表达式:">{{ form.cronExpression }}</el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="下次执行时间:">{{ parseTime(form.nextValidTime) }}</el-form-item>
         </el-col>
         <el-col :span="24">
           <el-form-item label="调用目标方法:">{{ form.invokeTarget }}</el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="任务状态:">
             <div v-if="form.status == 0">正常</div>
             <div v-else-if="form.status == 1">失败</div>
           </el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="是否并发:">
             <div v-if="form.concurrent == 0">允许</div>
             <div v-else-if="form.concurrent == 1">禁止</div>
           </el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="执行策略:">
             <div v-if="form.misfirePolicy == 0">默认策略</div>
             <div v-else-if="form.misfirePolicy == 1">立即执行</div>
             <div v-else-if="form.misfirePolicy == 2">执行一次</div>
             <div v-else-if="form.misfirePolicy == 3">放弃执行</div>
           </el-form-item>
         </el-col>
       </el-row>
     </el-form>
     <div slot="footer" class="dialog-footer">
       <el-button @click="openView = false">关 闭</el-button>
     </div>
   </el-dialog>
 </div>
</template>

<script>
import { listJob, getJob, delJob, addJob, updateJob, runJob, changeJobStatus } from "@/api/monitor/job";
import Crontab from '@/components/Crontab'

export default {
 components: { Crontab },
 name: "Job",
 dicts: ['sys_job_group', 'sys_job_status'],
 data() {
   return {
     // 遮罩层
     loading: true,
     // 选中数组
     ids: [],
     // 非单个禁用
     single: true,
     // 非多个禁用
     multiple: true,
     // 显示搜索条件
     showSearch: true,
     // 总条数
     total: 0,
     // 定时任务表格数据
     jobList: [],
     // 弹出层标题
     title: "",
     // 是否显示弹出层
     open: false,
     // 是否显示详细弹出层
     openView: false,
     // 是否显示Cron表达式弹出层
     openCron: false,
     // 传入的表达式
     expression: "",
     // 查询参数
     queryParams: {
       pageNum: 1,
       pageSize: 10,
       jobName: undefined,
       jobGroup: undefined,
       status: undefined
     },
     // 表单参数
     form: {},
     // 表单校验
     rules: {
       jobName: [
         { required: true, message: "任务名称不能为空", trigger: "blur" }
       ],
       invokeTarget: [
         { required: true, message: "调用目标字符串不能为空", trigger: "blur" }
       ],
       cronExpression: [
         { required: true, message: "cron执行表达式不能为空", trigger: "blur" }
       ]
     }
   };
 },
 created() {
   this.getList();
 },
 methods: {
   /** 查询定时任务列表 */
   getList() {
     this.loading = true;
     listJob(this.queryParams).then(response => {
       this.jobList = response.rows;
       this.total = response.total;
       this.loading = false;
     });
   },
   // 任务组名字典翻译
   jobGroupFormat(row, column) {
     return this.selectDictLabel(this.dict.type.sys_job_group, row.jobGroup);
   },
   // 取消按钮
   cancel() {
     this.open = false;
     this.reset();
   },
   // 表单重置
   reset() {
     this.form = {
       jobId: undefined,
       jobName: undefined,
       jobGroup: undefined,
       invokeTarget: undefined,
       cronExpression: undefined,
       misfirePolicy: 1,
       concurrent: 1,
       status: "0"
     };
     this.resetForm("form");
   },
   /** 搜索按钮操作 */
   handleQuery() {
     this.queryParams.pageNum = 1;
     this.getList();
   },
   /** 重置按钮操作 */
   resetQuery() {
     this.resetForm("queryForm");
     this.handleQuery();
   },
   // 多选框选中数据
   handleSelectionChange(selection) {
     this.ids = selection.map(item => item.jobId);
     this.single = selection.length != 1;
     this.multiple = !selection.length;
   },
   // 更多操作触发
   handleCommand(command, row) {
     switch (command) {
       case "handleRun":
         this.handleRun(row);
         break;
       case "handleView":
         this.handleView(row);
         break;
       case "handleJobLog":
         this.handleJobLog(row);
         break;
       default:
         break;
     }
   },
   // 任务状态修改
   handleStatusChange(row) {
     let text = row.status === "0" ? "启用" : "停用";
     this.$modal.confirm('确认要"' + text + '""' + row.jobName + '"任务吗?').then(function() {
       return changeJobStatus(row.jobId, row.status);
     }).then(() => {
       this.$modal.msgSuccess(text + "成功");
     }).catch(function() {
       row.status = row.status === "0" ? "1" : "0";
     });
   },
   /* 立即执行一次 */
   handleRun(row) {
     this.$modal.confirm('确认要立即执行一次"' + row.jobName + '"任务吗?').then(function() {
       return runJob(row.jobId, row.jobGroup);
     }).then(() => {
       this.$modal.msgSuccess("执行成功");
     }).catch(() => {});
   },
   /** 任务详细信息 */
   handleView(row) {
     getJob(row.jobId).then(response => {
       this.form = response.data;
       this.openView = true;
     });
   },
   /** cron表达式按钮操作 */
   handleShowCron() {
     this.expression = this.form.cronExpression;
     this.openCron = true;
   },
   /** 确定后回传值 */
   crontabFill(value) {
     this.form.cronExpression = value;
   },
   /** 任务日志列表查询 */
   handleJobLog(row) {
     const jobId = row.jobId || 0;
     this.$router.push({ path: '/monitor/job-log/index', query: { jobId: jobId } })
   },
   /** 新增按钮操作 */
   handleAdd() {
     this.reset();
     this.open = true;
     this.title = "添加任务";
   },
   /** 修改按钮操作 */
   handleUpdate(row) {
     this.reset();
     const jobId = row.jobId || this.ids;
     getJob(jobId).then(response => {
       this.form = response.data;
       this.open = true;
       this.title = "修改任务";
     });
   },
   /** 提交按钮 */
   submitForm: function() {
     this.$refs["form"].validate(valid => {
       if (valid) {
         if (this.form.jobId != undefined) {
           updateJob(this.form).then(response => {
             this.$modal.msgSuccess("修改成功");
             this.open = false;
             this.getList();
           });
         } else {
           addJob(this.form).then(response => {
             this.$modal.msgSuccess("新增成功");
             this.open = false;
             this.getList();
           });
         }
       }
     });
   },
   /** 删除按钮操作 */
   handleDelete(row) {
     const jobIds = row.jobId || this.ids;
     this.$modal.confirm('是否确认删除定时任务编号为"' + jobIds + '"的数据项?').then(function() {
       return delJob(jobIds);
     }).then(() => {
       this.getList();
       this.$modal.msgSuccess("删除成功");
     }).catch(() => {});
   },
   /** 导出按钮操作 */
   handleExport() {
     this.download('monitor/job/export', {
       ...this.queryParams
     }, `job_${new Date().getTime()}.xlsx`)
   }
 }
};
</script>
复制代码
<template>
 <div class="app-container">
   <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
     <el-form-item label="任务名称" prop="jobName">
       <el-input
         v-model="queryParams.jobName"
         placeholder="请输入任务名称"
         clearable
         style="width: 240px"
         @keyup.enter.native="handleQuery"
       />
     </el-form-item>
     <el-form-item label="任务组名" prop="jobGroup">
       <el-select
         v-model="queryParams.jobGroup"
         placeholder="请选择任务组名"
         clearable
         style="width: 240px"
       >
         <el-option
           v-for="dict in dict.type.sys_job_group"
           :key="dict.value"
           :label="dict.label"
           :value="dict.value"
         />
       </el-select>
     </el-form-item>
     <el-form-item label="执行状态" prop="status">
       <el-select
         v-model="queryParams.status"
         placeholder="请选择执行状态"
         clearable
         style="width: 240px"
       >
         <el-option
           v-for="dict in dict.type.sys_common_status"
           :key="dict.value"
           :label="dict.label"
           :value="dict.value"
         />
       </el-select>
     </el-form-item>
     <el-form-item label="执行时间">
       <el-date-picker
         v-model="dateRange"
         style="width: 240px"
         value-format="yyyy-MM-dd"
         type="daterange"
         range-separator="-"
         start-placeholder="开始日期"
         end-placeholder="结束日期"
       ></el-date-picker>
     </el-form-item>
     <el-form-item>
       <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
       <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
     </el-form-item>
   </el-form>

   <el-row :gutter="10" class="mb8">
     <el-col :span="1.5">
       <el-button
         type="danger"
         plain
         icon="el-icon-delete"
         size="mini"
         :disabled="multiple"
         @click="handleDelete"
         v-hasPermi="['monitor:job:remove']"
       >删除</el-button>
     </el-col>
     <el-col :span="1.5">
       <el-button
         type="danger"
         plain
         icon="el-icon-delete"
         size="mini"
         @click="handleClean"
         v-hasPermi="['monitor:job:remove']"
       >清空</el-button>
     </el-col>
     <el-col :span="1.5">
       <el-button
         type="warning"
         plain
         icon="el-icon-download"
         size="mini"
         @click="handleExport"
         v-hasPermi="['monitor:job:export']"
       >导出</el-button>
     </el-col>
     <el-col :span="1.5">
       <el-button
         type="warning"
         plain
         icon="el-icon-close"
         size="mini"
         @click="handleClose"
       >关闭</el-button>
     </el-col>
     <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
   </el-row>

   <el-table v-loading="loading" :data="jobLogList" @selection-change="handleSelectionChange">
     <el-table-column type="selection" width="55" align="center" />
     <el-table-column label="日志编号" width="80" align="center" prop="jobLogId" />
     <el-table-column label="任务名称" align="center" prop="jobName" :show-overflow-tooltip="true" />
     <el-table-column label="任务组名" align="center" prop="jobGroup" :show-overflow-tooltip="true">
       <template slot-scope="scope">
         <dict-tag :options="dict.type.sys_job_group" :value="scope.row.jobGroup"/>
       </template>
     </el-table-column>
     <el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
     <el-table-column label="日志信息" align="center" prop="jobMessage" :show-overflow-tooltip="true" />
     <el-table-column label="执行状态" align="center" prop="status">
       <template slot-scope="scope">
         <dict-tag :options="dict.type.sys_common_status" :value="scope.row.status"/>
       </template>
     </el-table-column>
     <el-table-column label="执行时间" align="center" prop="createTime" width="180">
       <template slot-scope="scope">
         <span>{{ parseTime(scope.row.createTime) }}</span>
       </template>
     </el-table-column>
     <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
       <template slot-scope="scope">
         <el-button
           size="mini"
           type="text"
           icon="el-icon-view"
           @click="handleView(scope.row)"
           v-hasPermi="['monitor:job:query']"
         >详细</el-button>
       </template>
     </el-table-column>
   </el-table>

   <pagination
     v-show="total>0"
     :total="total"
     :page.sync="queryParams.pageNum"
     :limit.sync="queryParams.pageSize"
     @pagination="getList"
   />

   <!-- 调度日志详细 -->
   <el-dialog title="调度日志详细" :visible.sync="open" width="700px" append-to-body>
     <el-form ref="form" :model="form" label-width="100px" size="mini">
       <el-row>
         <el-col :span="12">
           <el-form-item label="日志序号:">{{ form.jobLogId }}</el-form-item>
           <el-form-item label="任务名称:">{{ form.jobName }}</el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="任务分组:">{{ form.jobGroup }}</el-form-item>
           <el-form-item label="执行时间:">{{ form.createTime }}</el-form-item>
         </el-col>
         <el-col :span="24">
           <el-form-item label="调用方法:">{{ form.invokeTarget }}</el-form-item>
         </el-col>
         <el-col :span="24">
           <el-form-item label="日志信息:">{{ form.jobMessage }}</el-form-item>
         </el-col>
         <el-col :span="24">
           <el-form-item label="执行状态:">
             <div v-if="form.status == 0">正常</div>
             <div v-else-if="form.status == 1">失败</div>
           </el-form-item>
         </el-col>
         <el-col :span="24">
           <el-form-item label="异常信息:" v-if="form.status == 1">{{ form.exceptionInfo }}</el-form-item>
         </el-col>
       </el-row>
     </el-form>
     <div slot="footer" class="dialog-footer">
       <el-button @click="open = false">关 闭</el-button>
     </div>
   </el-dialog>
 </div>
</template>

<script>
import { getJob} from "@/api/monitor/job";
import { listJobLog, delJobLog, cleanJobLog } from "@/api/monitor/jobLog";

export default {
 name: "JobLog",
 dicts: ['sys_common_status', 'sys_job_group'],
 data() {
   return {
     // 遮罩层
     loading: true,
     // 选中数组
     ids: [],
     // 非多个禁用
     multiple: true,
     // 显示搜索条件
     showSearch: true,
     // 总条数
     total: 0,
     // 调度日志表格数据
     jobLogList: [],
     // 是否显示弹出层
     open: false,
     // 日期范围
     dateRange: [],
     // 表单参数
     form: {},
     // 查询参数
     queryParams: {
       pageNum: 1,
       pageSize: 10,
       jobName: undefined,
       jobGroup: undefined,
       status: undefined
     }
   };
 },
 created() {
   const jobId = this.$route.query.jobId;
   if (jobId !== undefined && jobId != 0) {
     getJob(jobId).then(response => {
       this.queryParams.jobName = response.data.jobName;
       this.queryParams.jobGroup = response.data.jobGroup;
       this.getList();
     });
   } else {
     this.getList();
   }
 },
 methods: {
   /** 查询调度日志列表 */
   getList() {
     this.loading = true;
     listJobLog(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
         this.jobLogList = response.rows;
         this.total = response.total;
         this.loading = false;
       }
     );
   },
   // 返回按钮
   handleClose() {
     const obj = { path: "/monitor/job" };
     this.$tab.closeOpenPage(obj);
   },
   /** 搜索按钮操作 */
   handleQuery() {
     this.queryParams.pageNum = 1;
     this.getList();
   },
   /** 重置按钮操作 */
   resetQuery() {
     this.dateRange = [];
     this.resetForm("queryForm");
     this.handleQuery();
   },
   // 多选框选中数据
   handleSelectionChange(selection) {
     this.ids = selection.map(item => item.jobLogId);
     this.multiple = !selection.length;
   },
   /** 详细按钮操作 */
   handleView(row) {
     this.open = true;
     this.form = row;
   },
   /** 删除按钮操作 */
   handleDelete(row) {
     const jobLogIds = this.ids;
     this.$modal.confirm('是否确认删除调度日志编号为"' + jobLogIds + '"的数据项?').then(function() {
       return delJobLog(jobLogIds);
     }).then(() => {
       this.getList();
       this.$modal.msgSuccess("删除成功");
     }).catch(() => {});
   },
   /** 清空按钮操作 */
   handleClean() {
     this.$modal.confirm('是否确认清空所有调度日志数据项?').then(function() {
       return cleanJobLog();
     }).then(() => {
       this.getList();
       this.$modal.msgSuccess("清空成功");
     }).catch(() => {});
   },
   /** 导出按钮操作 */
   handleExport() {
     this.download('/monitor/jobLog/export', {
       ...this.queryParams
     }, `log_${new Date().getTime()}.xlsx`)
   }
 }
};
</script>

来源:https://juejin.cn/post/7181670480712040505

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com