Pārlūkot izejas kodu

feat: Initialize item

Nobita 9 mēneši atpakaļ
vecāks
revīzija
8e402f9bc1
29 mainītis faili ar 2094 papildinājumiem un 27 dzēšanām
  1. 0 13
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/HimeeterQuartzApplication.java
  2. 65 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/config/ScheduleConfig.java
  3. 157 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/controller/SysJobController.java
  4. 91 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/controller/SysJobLogController.java
  5. 178 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/domain/SysJob.java
  6. 164 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/domain/SysJobLog.java
  7. 74 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/mapper/SysJobLogMapper.java
  8. 76 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/mapper/SysJobMapper.java
  9. 65 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/service/SysJobLogService.java
  10. 112 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/service/SysJobService.java
  11. 96 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/service/impl/SysJobLogServiceImpl.java
  12. 245 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/service/impl/SysJobServiceImpl.java
  13. 33 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/task/HimeeterTask.java
  14. 108 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/util/AbstractQuartzJob.java
  15. 63 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/util/CronUtils.java
  16. 168 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/util/JobInvokeUtil.java
  17. 27 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/util/QuartzDisallowConcurrentExecution.java
  18. 26 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/util/QuartzJobExecution.java
  19. 128 0
      himeeter-quartz/src/main/java/com/lij/himeeter/quartz/util/ScheduleUtils.java
  20. 0 1
      himeeter-quartz/src/main/resources/application.properties
  21. 94 0
      himeeter-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml
  22. 111 0
      himeeter-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml
  23. 2 2
      himeeter-ui/himeeter-ui-system/.env.development
  24. 2 2
      himeeter-ui/himeeter-ui-system/.env.production
  25. 2 2
      himeeter-ui/himeeter-ui-system/.env.staging
  26. 1 1
      himeeter-ui/himeeter-ui-system/index.html
  27. 4 4
      himeeter-ui/himeeter-ui-system/package.json
  28. 1 1
      himeeter-ui/himeeter-ui-system/src/views/login.vue
  29. 1 1
      himeeter-ui/himeeter-ui-system/src/views/register.vue

+ 0 - 13
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/HimeeterQuartzApplication.java

@@ -1,13 +0,0 @@
-package com.lij.himeeter.quartz;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-@SpringBootApplication
-public class HimeeterQuartzApplication {
-
-    public static void main(String[] args) {
-        SpringApplication.run(HimeeterQuartzApplication.class, args);
-    }
-
-}

+ 65 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/config/ScheduleConfig.java

@@ -0,0 +1,65 @@
+//package com.lij.himeeter.quartz.config;
+//
+//import org.springframework.context.annotation.Bean;
+//import org.springframework.context.annotation.Configuration;
+//import org.springframework.scheduling.quartz.SchedulerFactoryBean;
+//
+//import javax.sql.DataSource;
+//import java.util.Properties;
+//
+///**
+// * <pre>
+// *
+// * 文件名 :  ScheduleConfig
+// * 创建时间 : 2025年02月12日 15:49
+// *
+// * 文件描述 : 定时任务配置(单机部署建议删除此类和qrtz数据库表,默认走内存会最高效)
+// *
+// * </pre>
+// *
+// * @author Nobita
+// * @version 1.0.0
+// */
+//@Configuration
+//public class ScheduleConfig {
+//
+//    @Bean
+//    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) {
+//        SchedulerFactoryBean factory = new SchedulerFactoryBean();
+//        factory.setDataSource(dataSource);
+//
+//        // quartz参数
+//        Properties prop = new Properties();
+//        prop.put("org.quartz.scheduler.instanceName", "RuoyiScheduler");
+//        prop.put("org.quartz.scheduler.instanceId", "AUTO");
+//        // 线程池配置
+//        prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
+//        prop.put("org.quartz.threadPool.threadCount", "20");
+//        prop.put("org.quartz.threadPool.threadPriority", "5");
+//        // JobStore配置
+//        prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore");
+//        // 集群配置
+//        prop.put("org.quartz.jobStore.isClustered", "true");
+//        prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
+//        prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "10");
+//        prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");
+//
+//        // sqlserver 启用
+//        // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
+//        prop.put("org.quartz.jobStore.misfireThreshold", "12000");
+//        prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
+//        factory.setQuartzProperties(prop);
+//
+//        factory.setSchedulerName("RuoyiScheduler");
+//        // 延时启动
+//        factory.setStartupDelay(1);
+//        factory.setApplicationContextSchedulerContextKey("applicationContextKey");
+//        // 可选,QuartzScheduler
+//        // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
+//        factory.setOverwriteExistingJobs(true);
+//        // 设置自动启动,默认为true
+//        factory.setAutoStartup(true);
+//
+//        return factory;
+//    }
+//}

+ 157 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/controller/SysJobController.java

@@ -0,0 +1,157 @@
+package com.lij.himeeter.quartz.controller;
+
+import com.lij.himeeter.common.annotation.Log;
+import com.lij.himeeter.common.constant.Constants;
+import com.lij.himeeter.common.core.controller.BaseController;
+import com.lij.himeeter.common.core.domain.AjaxResult;
+import com.lij.himeeter.common.core.page.TableDataInfo;
+import com.lij.himeeter.common.enums.BusinessType;
+import com.lij.himeeter.common.exception.job.TaskException;
+import com.lij.himeeter.common.utils.StringUtils;
+import com.lij.himeeter.common.utils.poi.ExcelUtil;
+import com.lij.himeeter.quartz.domain.SysJob;
+import com.lij.himeeter.quartz.service.SysJobService;
+import com.lij.himeeter.quartz.util.CronUtils;
+import com.lij.himeeter.quartz.util.ScheduleUtils;
+import jakarta.servlet.http.HttpServletResponse;
+import org.quartz.SchedulerException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysJobController
+ * 创建时间 : 2025年02月12日 15:51
+ *
+ * 文件描述 : 调度任务信息操作处理
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+@RestController
+@RequestMapping("/monitor/job")
+public class SysJobController extends BaseController {
+
+    @Autowired
+    private SysJobService jobService;
+
+    /**
+     * 查询定时任务列表
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysJob sysJob) {
+        startPage();
+        List<SysJob> list = jobService.selectJobList(sysJob);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出定时任务列表
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:export')")
+    @Log(title = "定时任务", businessType = BusinessType.EXPORT)
+    @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, "定时任务");
+    }
+
+    /**
+     * 获取定时任务详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:query')")
+    @GetMapping(value = "/{jobId}")
+    public AjaxResult getInfo(@PathVariable("jobId") Long jobId) {
+        return success(jobService.selectJobById(jobId));
+    }
+
+    /**
+     * 新增定时任务
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:add')")
+    @Log(title = "定时任务", businessType = BusinessType.INSERT)
+    @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));
+    }
+
+    /**
+     * 修改定时任务
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:edit')")
+    @Log(title = "定时任务", businessType = BusinessType.UPDATE)
+    @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));
+    }
+
+    /**
+     * 定时任务状态修改
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')")
+    @Log(title = "定时任务", businessType = BusinessType.UPDATE)
+    @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));
+    }
+
+    /**
+     * 定时任务立即执行一次
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')")
+    @Log(title = "定时任务", businessType = BusinessType.UPDATE)
+    @PutMapping("/run")
+    public AjaxResult run(@RequestBody SysJob job) throws SchedulerException {
+        boolean result = jobService.run(job);
+        return result ? success() : error("任务不存在或已过期!");
+    }
+
+    /**
+     * 删除定时任务
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
+    @Log(title = "定时任务", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{jobIds}")
+    public AjaxResult remove(@PathVariable Long[] jobIds) throws SchedulerException, TaskException {
+        jobService.deleteJobByIds(jobIds);
+        return success();
+    }
+}

+ 91 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/controller/SysJobLogController.java

@@ -0,0 +1,91 @@
+package com.lij.himeeter.quartz.controller;
+
+import com.lij.himeeter.common.annotation.Log;
+import com.lij.himeeter.common.core.controller.BaseController;
+import com.lij.himeeter.common.core.domain.AjaxResult;
+import com.lij.himeeter.common.core.page.TableDataInfo;
+import com.lij.himeeter.common.enums.BusinessType;
+import com.lij.himeeter.common.utils.poi.ExcelUtil;
+import com.lij.himeeter.quartz.domain.SysJobLog;
+import com.lij.himeeter.quartz.service.SysJobLogService;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysJobLogController
+ * 创建时间 : 2025年02月12日 15:52
+ *
+ * 文件描述 : 调度日志操作处理
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+@RestController
+@RequestMapping("/monitor/jobLog")
+public class SysJobLogController extends BaseController {
+
+    @Autowired
+    private SysJobLogService jobLogService;
+
+    /**
+     * 查询定时任务调度日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysJobLog sysJobLog) {
+        startPage();
+        List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出定时任务调度日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:export')")
+    @Log(title = "任务调度日志", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysJobLog sysJobLog) {
+        List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
+        ExcelUtil<SysJobLog> util = new ExcelUtil<SysJobLog>(SysJobLog.class);
+        util.exportExcel(response, list, "调度日志");
+    }
+
+    /**
+     * 根据调度编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:query')")
+    @GetMapping(value = "/{jobLogId}")
+    public AjaxResult getInfo(@PathVariable Long jobLogId) {
+        return success(jobLogService.selectJobLogById(jobLogId));
+    }
+
+
+    /**
+     * 删除定时任务调度日志
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
+    @Log(title = "定时任务调度日志", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{jobLogIds}")
+    public AjaxResult remove(@PathVariable Long[] jobLogIds) {
+        return toAjax(jobLogService.deleteJobLogByIds(jobLogIds));
+    }
+
+    /**
+     * 清空定时任务调度日志
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
+    @Log(title = "调度日志", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/clean")
+    public AjaxResult clean() {
+        jobLogService.cleanJobLog();
+        return success();
+    }
+}

+ 178 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/domain/SysJob.java

@@ -0,0 +1,178 @@
+package com.lij.himeeter.quartz.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.lij.himeeter.common.annotation.Excel;
+import com.lij.himeeter.common.constant.ScheduleConstants;
+import com.lij.himeeter.common.core.domain.BaseEntity;
+import com.lij.himeeter.common.utils.StringUtils;
+import com.lij.himeeter.quartz.util.CronUtils;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.lij.himeeter.common.annotation.Excel.ColumnType;
+
+import java.util.Date;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysJob
+ * 创建时间 : 2025年02月12日 15:53
+ *
+ * 文件描述 : 定时任务调度表 sys_job
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysJob extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 任务ID
+     */
+    @Excel(name = "任务序号", cellType = ColumnType.NUMERIC)
+    private Long jobId;
+
+    /**
+     * 任务名称
+     */
+    @Excel(name = "任务名称")
+    private String jobName;
+
+    /**
+     * 任务组名
+     */
+    @Excel(name = "任务组名")
+    private String jobGroup;
+
+    /**
+     * 调用目标字符串
+     */
+    @Excel(name = "调用目标字符串")
+    private String invokeTarget;
+
+    /**
+     * cron执行表达式
+     */
+    @Excel(name = "执行表达式 ")
+    private String cronExpression;
+
+    /**
+     * cron计划策略
+     */
+    @Excel(name = "计划策略 ", readConverterExp = "0=默认,1=立即触发执行,2=触发一次执行,3=不触发立即执行")
+    private String misfirePolicy = ScheduleConstants.MISFIRE_DEFAULT;
+
+    /**
+     * 是否并发执行(0允许 1禁止)
+     */
+    @Excel(name = "并发执行", readConverterExp = "0=允许,1=禁止")
+    private String concurrent;
+
+    /**
+     * 任务状态(0正常 1暂停)
+     */
+    @Excel(name = "任务状态", readConverterExp = "0=正常,1=暂停")
+    private String status;
+
+    public Long getJobId() {
+        return jobId;
+    }
+
+    public void setJobId(Long jobId) {
+        this.jobId = jobId;
+    }
+
+    @NotBlank(message = "任务名称不能为空")
+    @Size(min = 0, max = 64, message = "任务名称不能超过64个字符")
+    public String getJobName() {
+        return jobName;
+    }
+
+    public void setJobName(String jobName) {
+        this.jobName = jobName;
+    }
+
+    public String getJobGroup() {
+        return jobGroup;
+    }
+
+    public void setJobGroup(String jobGroup) {
+        this.jobGroup = jobGroup;
+    }
+
+    @NotBlank(message = "调用目标字符串不能为空")
+    @Size(min = 0, max = 500, message = "调用目标字符串长度不能超过500个字符")
+    public String getInvokeTarget() {
+        return invokeTarget;
+    }
+
+    public void setInvokeTarget(String invokeTarget) {
+        this.invokeTarget = invokeTarget;
+    }
+
+    @NotBlank(message = "Cron执行表达式不能为空")
+    @Size(min = 0, max = 255, message = "Cron执行表达式不能超过255个字符")
+    public String getCronExpression() {
+        return cronExpression;
+    }
+
+    public void setCronExpression(String cronExpression) {
+        this.cronExpression = cronExpression;
+    }
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    public Date getNextValidTime() {
+        if (StringUtils.isNotEmpty(cronExpression)) {
+            return CronUtils.getNextExecution(cronExpression);
+        }
+        return null;
+    }
+
+    public String getMisfirePolicy() {
+        return misfirePolicy;
+    }
+
+    public void setMisfirePolicy(String misfirePolicy) {
+        this.misfirePolicy = misfirePolicy;
+    }
+
+    public String getConcurrent() {
+        return concurrent;
+    }
+
+    public void setConcurrent(String concurrent) {
+        this.concurrent = concurrent;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("jobId", getJobId())
+                .append("jobName", getJobName())
+                .append("jobGroup", getJobGroup())
+                .append("cronExpression", getCronExpression())
+                .append("nextValidTime", getNextValidTime())
+                .append("misfirePolicy", getMisfirePolicy())
+                .append("concurrent", getConcurrent())
+                .append("status", getStatus())
+                .append("createBy", getCreateBy())
+                .append("createTime", getCreateTime())
+                .append("updateBy", getUpdateBy())
+                .append("updateTime", getUpdateTime())
+                .append("remark", getRemark())
+                .toString();
+    }
+}

+ 164 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/domain/SysJobLog.java

@@ -0,0 +1,164 @@
+package com.lij.himeeter.quartz.domain;
+
+import com.lij.himeeter.common.annotation.Excel;
+import com.lij.himeeter.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.util.Date;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysJobLog
+ * 创建时间 : 2025年02月12日 15:53
+ *
+ * 文件描述 : 定时任务调度日志表 sys_job_log
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class SysJobLog extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * ID
+     */
+    @Excel(name = "日志序号")
+    private Long jobLogId;
+
+    /**
+     * 任务名称
+     */
+    @Excel(name = "任务名称")
+    private String jobName;
+
+    /**
+     * 任务组名
+     */
+    @Excel(name = "任务组名")
+    private String jobGroup;
+
+    /**
+     * 调用目标字符串
+     */
+    @Excel(name = "调用目标字符串")
+    private String invokeTarget;
+
+    /**
+     * 日志信息
+     */
+    @Excel(name = "日志信息")
+    private String jobMessage;
+
+    /**
+     * 执行状态(0正常 1失败)
+     */
+    @Excel(name = "执行状态", readConverterExp = "0=正常,1=失败")
+    private String status;
+
+    /**
+     * 异常信息
+     */
+    @Excel(name = "异常信息")
+    private String exceptionInfo;
+
+    /**
+     * 开始时间
+     */
+    private Date startTime;
+
+    /**
+     * 停止时间
+     */
+    private Date stopTime;
+
+    public Long getJobLogId() {
+        return jobLogId;
+    }
+
+    public void setJobLogId(Long jobLogId) {
+        this.jobLogId = jobLogId;
+    }
+
+    public String getJobName() {
+        return jobName;
+    }
+
+    public void setJobName(String jobName) {
+        this.jobName = jobName;
+    }
+
+    public String getJobGroup() {
+        return jobGroup;
+    }
+
+    public void setJobGroup(String jobGroup) {
+        this.jobGroup = jobGroup;
+    }
+
+    public String getInvokeTarget() {
+        return invokeTarget;
+    }
+
+    public void setInvokeTarget(String invokeTarget) {
+        this.invokeTarget = invokeTarget;
+    }
+
+    public String getJobMessage() {
+        return jobMessage;
+    }
+
+    public void setJobMessage(String jobMessage) {
+        this.jobMessage = jobMessage;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getExceptionInfo() {
+        return exceptionInfo;
+    }
+
+    public void setExceptionInfo(String exceptionInfo) {
+        this.exceptionInfo = exceptionInfo;
+    }
+
+    public Date getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(Date startTime) {
+        this.startTime = startTime;
+    }
+
+    public Date getStopTime() {
+        return stopTime;
+    }
+
+    public void setStopTime(Date stopTime) {
+        this.stopTime = stopTime;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("jobLogId", getJobLogId())
+                .append("jobName", getJobName())
+                .append("jobGroup", getJobGroup())
+                .append("jobMessage", getJobMessage())
+                .append("status", getStatus())
+                .append("exceptionInfo", getExceptionInfo())
+                .append("startTime", getStartTime())
+                .append("stopTime", getStopTime())
+                .toString();
+    }
+}

+ 74 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/mapper/SysJobLogMapper.java

@@ -0,0 +1,74 @@
+package com.lij.himeeter.quartz.mapper;
+
+import com.lij.himeeter.quartz.domain.SysJobLog;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysJobLogMapper
+ * 创建时间 : 2025年02月12日 16:05
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface SysJobLogMapper {
+
+    /**
+     * 获取quartz调度器日志的计划任务
+     *
+     * @param jobLog 调度日志信息
+     * @return 调度任务日志集合
+     */
+    List<SysJobLog> selectJobLogList(SysJobLog jobLog);
+
+    /**
+     * 查询所有调度任务日志
+     *
+     * @return 调度任务日志列表
+     */
+    List<SysJobLog> selectJobLogAll();
+
+    /**
+     * 通过调度任务日志ID查询调度信息
+     *
+     * @param jobLogId 调度任务日志ID
+     * @return 调度任务日志对象信息
+     */
+    SysJobLog selectJobLogById(Long jobLogId);
+
+    /**
+     * 新增任务日志
+     *
+     * @param jobLog 调度日志信息
+     * @return 结果
+     */
+    int insertJobLog(SysJobLog jobLog);
+
+    /**
+     * 批量删除调度日志信息
+     *
+     * @param logIds 需要删除的数据ID
+     * @return 结果
+     */
+    int deleteJobLogByIds(Long[] logIds);
+
+    /**
+     * 删除任务日志
+     *
+     * @param jobId 调度日志ID
+     * @return 结果
+     */
+    int deleteJobLogById(Long jobId);
+
+    /**
+     * 清空任务日志
+     */
+    void cleanJobLog();
+}

+ 76 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/mapper/SysJobMapper.java

@@ -0,0 +1,76 @@
+package com.lij.himeeter.quartz.mapper;
+
+import com.lij.himeeter.quartz.domain.SysJob;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysJobMapper
+ * 创建时间 : 2025年02月12日 16:06
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface SysJobMapper {
+    /**
+     * 查询调度任务日志集合
+     *
+     * @param job 调度信息
+     * @return 操作日志集合
+     */
+    List<SysJob> selectJobList(SysJob job);
+
+    /**
+     * 查询所有调度任务
+     *
+     * @return 调度任务列表
+     */
+    List<SysJob> selectJobAll();
+
+    /**
+     * 通过调度ID查询调度任务信息
+     *
+     * @param jobId 调度ID
+     * @return 角色对象信息
+     */
+    SysJob selectJobById(Long jobId);
+
+    /**
+     * 通过调度ID删除调度任务信息
+     *
+     * @param jobId 调度ID
+     * @return 结果
+     */
+    int deleteJobById(Long jobId);
+
+    /**
+     * 批量删除调度任务信息
+     *
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    int deleteJobByIds(Long[] ids);
+
+    /**
+     * 修改调度任务信息
+     *
+     * @param job 调度任务信息
+     * @return 结果
+     */
+    int updateJob(SysJob job);
+
+    /**
+     * 新增调度任务信息
+     *
+     * @param job 调度任务信息
+     * @return 结果
+     */
+    int insertJob(SysJob job);
+}

+ 65 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/service/SysJobLogService.java

@@ -0,0 +1,65 @@
+package com.lij.himeeter.quartz.service;
+
+import com.lij.himeeter.quartz.domain.SysJobLog;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysJobLogService
+ * 创建时间 : 2025年02月12日 16:07
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface SysJobLogService {
+    /**
+     * 获取quartz调度器日志的计划任务
+     *
+     * @param jobLog 调度日志信息
+     * @return 调度任务日志集合
+     */
+    List<SysJobLog> selectJobLogList(SysJobLog jobLog);
+
+    /**
+     * 通过调度任务日志ID查询调度信息
+     *
+     * @param jobLogId 调度任务日志ID
+     * @return 调度任务日志对象信息
+     */
+    SysJobLog selectJobLogById(Long jobLogId);
+
+    /**
+     * 新增任务日志
+     *
+     * @param jobLog 调度日志信息
+     */
+    void addJobLog(SysJobLog jobLog);
+
+    /**
+     * 批量删除调度日志信息
+     *
+     * @param logIds 需要删除的日志ID
+     * @return 结果
+     */
+    int deleteJobLogByIds(Long[] logIds);
+
+    /**
+     * 删除任务日志
+     *
+     * @param jobId 调度日志ID
+     * @return 结果
+     */
+    int deleteJobLogById(Long jobId);
+
+    /**
+     * 清空任务日志
+     */
+    void cleanJobLog();
+}

+ 112 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/service/SysJobService.java

@@ -0,0 +1,112 @@
+package com.lij.himeeter.quartz.service;
+
+import com.lij.himeeter.common.exception.job.TaskException;
+import com.lij.himeeter.quartz.domain.SysJob;
+import org.quartz.SchedulerException;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysJobService
+ * 创建时间 : 2025年02月12日 16:05
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public interface SysJobService {
+    /**
+     * 获取quartz调度器的计划任务
+     *
+     * @param job 调度信息
+     * @return 调度任务集合
+     */
+    List<SysJob> selectJobList(SysJob job);
+
+    /**
+     * 通过调度任务ID查询调度信息
+     *
+     * @param jobId 调度任务ID
+     * @return 调度任务对象信息
+     */
+    SysJob selectJobById(Long jobId);
+
+    /**
+     * 暂停任务
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int pauseJob(SysJob job) throws SchedulerException;
+
+    /**
+     * 恢复任务
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int resumeJob(SysJob job) throws SchedulerException;
+
+    /**
+     * 删除任务后,所对应的trigger也将被删除
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int deleteJob(SysJob job) throws SchedulerException;
+
+    /**
+     * 批量删除调度信息
+     *
+     * @param jobIds 需要删除的任务ID
+     * @return 结果
+     */
+    void deleteJobByIds(Long[] jobIds) throws SchedulerException;
+
+    /**
+     * 任务调度状态修改
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int changeStatus(SysJob job) throws SchedulerException;
+
+    /**
+     * 立即运行任务
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    boolean run(SysJob job) throws SchedulerException;
+
+    /**
+     * 新增任务
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int insertJob(SysJob job) throws SchedulerException, TaskException;
+
+    /**
+     * 更新任务
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int updateJob(SysJob job) throws SchedulerException, TaskException;
+
+    /**
+     * 校验cron表达式是否有效
+     *
+     * @param cronExpression 表达式
+     * @return 结果
+     */
+    boolean checkCronExpressionIsValid(String cronExpression);
+
+}

+ 96 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/service/impl/SysJobLogServiceImpl.java

@@ -0,0 +1,96 @@
+package com.lij.himeeter.quartz.service.impl;
+
+import com.lij.himeeter.quartz.domain.SysJobLog;
+import com.lij.himeeter.quartz.mapper.SysJobLogMapper;
+import com.lij.himeeter.quartz.service.SysJobLogService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysJobLogServiceImpl
+ * 创建时间 : 2025年02月12日 16:08
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+@Service
+public class SysJobLogServiceImpl implements SysJobLogService {
+
+    @Autowired
+    private SysJobLogMapper jobLogMapper;
+
+    /**
+     * 获取quartz调度器日志的计划任务
+     *
+     * @param jobLog 调度日志信息
+     * @return 调度任务日志集合
+     */
+    @Override
+    public List<SysJobLog> selectJobLogList(SysJobLog jobLog)
+    {
+        return jobLogMapper.selectJobLogList(jobLog);
+    }
+
+    /**
+     * 通过调度任务日志ID查询调度信息
+     *
+     * @param jobLogId 调度任务日志ID
+     * @return 调度任务日志对象信息
+     */
+    @Override
+    public SysJobLog selectJobLogById(Long jobLogId)
+    {
+        return jobLogMapper.selectJobLogById(jobLogId);
+    }
+
+    /**
+     * 新增任务日志
+     *
+     * @param jobLog 调度日志信息
+     */
+    @Override
+    public void addJobLog(SysJobLog jobLog)
+    {
+        jobLogMapper.insertJobLog(jobLog);
+    }
+
+    /**
+     * 批量删除调度日志信息
+     *
+     * @param logIds 需要删除的数据ID
+     * @return 结果
+     */
+    @Override
+    public int deleteJobLogByIds(Long[] logIds)
+    {
+        return jobLogMapper.deleteJobLogByIds(logIds);
+    }
+
+    /**
+     * 删除任务日志
+     *
+     * @param jobId 调度日志ID
+     */
+    @Override
+    public int deleteJobLogById(Long jobId)
+    {
+        return jobLogMapper.deleteJobLogById(jobId);
+    }
+
+    /**
+     * 清空任务日志
+     */
+    @Override
+    public void cleanJobLog()
+    {
+        jobLogMapper.cleanJobLog();
+    }
+}

+ 245 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/service/impl/SysJobServiceImpl.java

@@ -0,0 +1,245 @@
+package com.lij.himeeter.quartz.service.impl;
+
+import com.lij.himeeter.common.constant.ScheduleConstants;
+import com.lij.himeeter.common.exception.job.TaskException;
+import com.lij.himeeter.quartz.domain.SysJob;
+import com.lij.himeeter.quartz.mapper.SysJobMapper;
+import com.lij.himeeter.quartz.service.SysJobService;
+import com.lij.himeeter.quartz.util.CronUtils;
+import com.lij.himeeter.quartz.util.ScheduleUtils;
+import jakarta.annotation.PostConstruct;
+import org.quartz.JobDataMap;
+import org.quartz.JobKey;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  SysJobServiceImpl
+ * 创建时间 : 2025年02月12日 16:08
+ *
+ * 文件描述 : 无
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+@Service
+public class SysJobServiceImpl implements SysJobService {
+    @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);
+    }
+
+}

+ 33 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/task/HimeeterTask.java

@@ -0,0 +1,33 @@
+package com.lij.himeeter.quartz.task;
+
+import com.lij.himeeter.common.utils.StringUtils;
+import org.springframework.stereotype.Component;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  HimeeterTask
+ * 创建时间 : 2025年02月12日 16:11
+ *
+ * 文件描述 : 定时任务调度测试
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+@Component("himeeterTask")
+public class HimeeterTask {
+
+    public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i) {
+        System.out.println(StringUtils.format("执行多参方法: 字符串类型{},布尔类型{},长整型{},浮点型{},整形{}", s, b, l, d, i));
+    }
+
+    public void ryParams(String params) {
+        System.out.println("执行有参方法:" + params);
+    }
+
+    public void ryNoParams() {
+        System.out.println("执行无参方法");
+    }
+}

+ 108 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/util/AbstractQuartzJob.java

@@ -0,0 +1,108 @@
+package com.lij.himeeter.quartz.util;
+
+import com.lij.himeeter.common.constant.Constants;
+import com.lij.himeeter.common.constant.ScheduleConstants;
+import com.lij.himeeter.common.utils.ExceptionUtil;
+import com.lij.himeeter.common.utils.StringUtils;
+import com.lij.himeeter.common.utils.bean.BeanUtils;
+import com.lij.himeeter.common.utils.spring.SpringUtils;
+import com.lij.himeeter.quartz.domain.SysJob;
+import com.lij.himeeter.quartz.domain.SysJobLog;
+import com.lij.himeeter.quartz.service.SysJobLogService;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  AbstractQuartzJob
+ * 创建时间 : 2025年02月12日 16:12
+ *
+ * 文件描述 : 抽象quartz调用
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public abstract class AbstractQuartzJob implements Job {
+
+    private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);
+
+    /**
+     * 线程本地变量
+     */
+    private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();
+
+    @Override
+    public void execute(JobExecutionContext context) throws JobExecutionException {
+        SysJob sysJob = new SysJob();
+        BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));
+        try {
+            before(context, sysJob);
+            if (sysJob != null) {
+                doExecute(context, sysJob);
+            }
+            after(context, sysJob, null);
+        } catch (Exception e) {
+            log.error("任务执行异常  - :", e);
+            after(context, sysJob, e);
+        }
+    }
+
+    /**
+     * 执行前
+     *
+     * @param context 工作执行上下文对象
+     * @param sysJob  系统计划任务
+     */
+    protected void before(JobExecutionContext context, SysJob sysJob) {
+        threadLocal.set(new Date());
+    }
+
+    /**
+     * 执行后
+     *
+     * @param context 工作执行上下文对象
+     * @param sysJob  系统计划任务
+     */
+    protected void after(JobExecutionContext context, SysJob sysJob, Exception e) {
+        Date startTime = threadLocal.get();
+        threadLocal.remove();
+
+        final SysJobLog sysJobLog = new SysJobLog();
+        sysJobLog.setJobName(sysJob.getJobName());
+        sysJobLog.setJobGroup(sysJob.getJobGroup());
+        sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());
+        sysJobLog.setStartTime(startTime);
+        sysJobLog.setStopTime(new Date());
+        long runMs = sysJobLog.getStopTime().getTime() - sysJobLog.getStartTime().getTime();
+        sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒");
+        if (e != null) {
+            sysJobLog.setStatus(Constants.FAIL);
+            String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000);
+            sysJobLog.setExceptionInfo(errorMsg);
+        } else {
+            sysJobLog.setStatus(Constants.SUCCESS);
+        }
+
+        // 写入数据库当中
+        SpringUtils.getBean(SysJobLogService.class).addJobLog(sysJobLog);
+    }
+
+    /**
+     * 执行方法,由子类重载
+     *
+     * @param context 工作执行上下文对象
+     * @param sysJob  系统计划任务
+     * @throws Exception 执行过程中的异常
+     */
+    protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;
+
+}

+ 63 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/util/CronUtils.java

@@ -0,0 +1,63 @@
+package com.lij.himeeter.quartz.util;
+
+import org.quartz.CronExpression;
+
+import java.text.ParseException;
+import java.util.Date;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  CronUtils
+ * 创建时间 : 2025年02月12日 15:56
+ *
+ * 文件描述 : cron表达式工具类
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class CronUtils {
+
+    /**
+     * 返回一个布尔值代表一个给定的Cron表达式的有效性
+     *
+     * @param cronExpression Cron表达式
+     * @return boolean 表达式是否有效
+     */
+    public static boolean isValid(String cronExpression) {
+        return CronExpression.isValidExpression(cronExpression);
+    }
+
+    /**
+     * 返回一个字符串值,表示该消息无效Cron表达式给出有效性
+     *
+     * @param cronExpression Cron表达式
+     * @return String 无效时返回表达式错误描述,如果有效返回null
+     */
+    public static String getInvalidMessage(String cronExpression) {
+        try {
+            new CronExpression(cronExpression);
+            return null;
+        } catch (ParseException pe) {
+            return pe.getMessage();
+        }
+    }
+
+    /**
+     * 返回下一个执行时间根据给定的Cron表达式
+     *
+     * @param cronExpression Cron表达式
+     * @return Date 下次Cron表达式执行时间
+     */
+    public static Date getNextExecution(String cronExpression) {
+        try {
+            CronExpression cron = new CronExpression(cronExpression);
+            return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));
+        } catch (ParseException e) {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+    }
+}

+ 168 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/util/JobInvokeUtil.java

@@ -0,0 +1,168 @@
+package com.lij.himeeter.quartz.util;
+
+import com.lij.himeeter.common.utils.StringUtils;
+import com.lij.himeeter.common.utils.spring.SpringUtils;
+import com.lij.himeeter.quartz.domain.SysJob;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  JobInvokeUtil
+ * 创建时间 : 2025年02月12日 16:13
+ *
+ * 文件描述 : 任务执行工具
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class JobInvokeUtil {
+    /**
+     * 执行方法
+     *
+     * @param sysJob 系统任务
+     */
+    public static void invokeMethod(SysJob sysJob) throws Exception {
+        String invokeTarget = sysJob.getInvokeTarget();
+        String beanName = getBeanName(invokeTarget);
+        String methodName = getMethodName(invokeTarget);
+        List<Object[]> methodParams = getMethodParams(invokeTarget);
+
+        if (!isValidClassName(beanName)) {
+            Object bean = SpringUtils.getBean(beanName);
+            invokeMethod(bean, methodName, methodParams);
+        } else {
+            Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance();
+            invokeMethod(bean, methodName, methodParams);
+        }
+    }
+
+    /**
+     * 调用任务方法
+     *
+     * @param bean         目标对象
+     * @param methodName   方法名称
+     * @param methodParams 方法参数
+     */
+    private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)
+            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
+            InvocationTargetException {
+        if (StringUtils.isNotNull(methodParams) && methodParams.size() > 0) {
+            Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams));
+            method.invoke(bean, getMethodParamsValue(methodParams));
+        } else {
+            Method method = bean.getClass().getMethod(methodName);
+            method.invoke(bean);
+        }
+    }
+
+    /**
+     * 校验是否为为class包名
+     *
+     * @param invokeTarget 名称
+     * @return true是 false否
+     */
+    public static boolean isValidClassName(String invokeTarget) {
+        return StringUtils.countMatches(invokeTarget, ".") > 1;
+    }
+
+    /**
+     * 获取bean名称
+     *
+     * @param invokeTarget 目标字符串
+     * @return bean名称
+     */
+    public static String getBeanName(String invokeTarget) {
+        String beanName = StringUtils.substringBefore(invokeTarget, "(");
+        return StringUtils.substringBeforeLast(beanName, ".");
+    }
+
+    /**
+     * 获取bean方法
+     *
+     * @param invokeTarget 目标字符串
+     * @return method方法
+     */
+    public static String getMethodName(String invokeTarget) {
+        String methodName = StringUtils.substringBefore(invokeTarget, "(");
+        return StringUtils.substringAfterLast(methodName, ".");
+    }
+
+    /**
+     * 获取method方法参数相关列表
+     *
+     * @param invokeTarget 目标字符串
+     * @return method方法相关参数列表
+     */
+    public static List<Object[]> getMethodParams(String invokeTarget) {
+        String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")");
+        if (StringUtils.isEmpty(methodStr)) {
+            return null;
+        }
+        String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)");
+        List<Object[]> classs = new LinkedList<>();
+        for (int i = 0; i < methodParams.length; i++) {
+            String str = StringUtils.trimToEmpty(methodParams[i]);
+            // String字符串类型,以'或"开头
+            if (StringUtils.startsWithAny(str, "'", "\"")) {
+                classs.add(new Object[]{StringUtils.substring(str, 1, str.length() - 1), String.class});
+            }
+            // boolean布尔类型,等于true或者false
+            else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str)) {
+                classs.add(new Object[]{Boolean.valueOf(str), Boolean.class});
+            }
+            // long长整形,以L结尾
+            else if (StringUtils.endsWith(str, "L")) {
+                classs.add(new Object[]{Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class});
+            }
+            // double浮点类型,以D结尾
+            else if (StringUtils.endsWith(str, "D")) {
+                classs.add(new Object[]{Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class});
+            }
+            // 其他类型归类为整形
+            else {
+                classs.add(new Object[]{Integer.valueOf(str), Integer.class});
+            }
+        }
+        return classs;
+    }
+
+    /**
+     * 获取参数类型
+     *
+     * @param methodParams 参数相关列表
+     * @return 参数类型列表
+     */
+    public static Class<?>[] getMethodParamsType(List<Object[]> methodParams) {
+        Class<?>[] classs = new Class<?>[methodParams.size()];
+        int index = 0;
+        for (Object[] os : methodParams) {
+            classs[index] = (Class<?>) os[1];
+            index++;
+        }
+        return classs;
+    }
+
+    /**
+     * 获取参数值
+     *
+     * @param methodParams 参数相关列表
+     * @return 参数值列表
+     */
+    public static Object[] getMethodParamsValue(List<Object[]> methodParams) {
+        Object[] classs = new Object[methodParams.size()];
+        int index = 0;
+        for (Object[] os : methodParams) {
+            classs[index] = (Object) os[0];
+            index++;
+        }
+        return classs;
+    }
+}

+ 27 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/util/QuartzDisallowConcurrentExecution.java

@@ -0,0 +1,27 @@
+package com.lij.himeeter.quartz.util;
+
+import com.lij.himeeter.quartz.domain.SysJob;
+import org.quartz.DisallowConcurrentExecution;
+import org.quartz.JobExecutionContext;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  QuartzDisallowConcurrentExecution
+ * 创建时间 : 2025年02月12日 16:14
+ *
+ * 文件描述 : 定时任务处理(禁止并发执行)
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+@DisallowConcurrentExecution
+public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob {
+
+    @Override
+    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception {
+        JobInvokeUtil.invokeMethod(sysJob);
+    }
+}

+ 26 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/util/QuartzJobExecution.java

@@ -0,0 +1,26 @@
+package com.lij.himeeter.quartz.util;
+
+import com.lij.himeeter.quartz.domain.SysJob;
+import org.quartz.JobExecutionContext;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  QuartzJobExecution
+ * 创建时间 : 2025年02月12日 16:15
+ *
+ * 文件描述 : 定时任务处理(允许并发执行)
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class QuartzJobExecution extends AbstractQuartzJob {
+
+    @Override
+    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception {
+        JobInvokeUtil.invokeMethod(sysJob);
+    }
+}

+ 128 - 0
himeeter-quartz/src/main/java/com/lij/himeeter/quartz/util/ScheduleUtils.java

@@ -0,0 +1,128 @@
+package com.lij.himeeter.quartz.util;
+
+import com.lij.himeeter.common.constant.Constants;
+import com.lij.himeeter.common.constant.ScheduleConstants;
+import com.lij.himeeter.common.exception.job.TaskException;
+import com.lij.himeeter.common.utils.StringUtils;
+import com.lij.himeeter.common.utils.spring.SpringUtils;
+import com.lij.himeeter.quartz.domain.SysJob;
+import org.quartz.*;
+
+/**
+ * <pre>
+ *
+ * 文件名 :  ScheduleUtils
+ * 创建时间 : 2025年02月12日 16:16
+ *
+ * 文件描述 : 定时任务工具类
+ *
+ * </pre>
+ *
+ * @author Nobita
+ * @version 1.0.0
+ */
+
+public class ScheduleUtils {
+
+    /**
+     * 得到quartz任务类
+     *
+     * @param sysJob 执行计划
+     * @return 具体执行任务类
+     */
+    private static Class<? extends Job> getQuartzJobClass(SysJob sysJob) {
+        boolean isConcurrent = "0".equals(sysJob.getConcurrent());
+        return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;
+    }
+
+    /**
+     * 构建任务触发对象
+     */
+    public static TriggerKey getTriggerKey(Long jobId, String jobGroup) {
+        return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
+    }
+
+    /**
+     * 构建任务键对象
+     */
+    public static JobKey getJobKey(Long jobId, String jobGroup) {
+        return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
+    }
+
+    /**
+     * 创建定时任务
+     */
+    public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException {
+        Class<? extends Job> jobClass = getQuartzJobClass(job);
+        // 构建job信息
+        Long jobId = job.getJobId();
+        String jobGroup = job.getJobGroup();
+        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build();
+
+        // 表达式调度构建器
+        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
+        cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);
+
+        // 按新的cronExpression表达式构建一个新的trigger
+        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup))
+                .withSchedule(cronScheduleBuilder).build();
+
+        // 放入参数,运行时的方法可以获取
+        jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);
+
+        // 判断是否存在
+        if (scheduler.checkExists(getJobKey(jobId, jobGroup))) {
+            // 防止创建时存在数据问题 先移除,然后在执行创建操作
+            scheduler.deleteJob(getJobKey(jobId, jobGroup));
+        }
+
+        // 判断任务是否过期
+        if (StringUtils.isNotNull(CronUtils.getNextExecution(job.getCronExpression()))) {
+            // 执行调度任务
+            scheduler.scheduleJob(jobDetail, trigger);
+        }
+
+        // 暂停任务
+        if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) {
+            scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
+        }
+    }
+
+    /**
+     * 设置定时任务策略
+     */
+    public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb)
+            throws TaskException {
+        switch (job.getMisfirePolicy()) {
+            case ScheduleConstants.MISFIRE_DEFAULT:
+                return cb;
+            case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
+                return cb.withMisfireHandlingInstructionIgnoreMisfires();
+            case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
+                return cb.withMisfireHandlingInstructionFireAndProceed();
+            case ScheduleConstants.MISFIRE_DO_NOTHING:
+                return cb.withMisfireHandlingInstructionDoNothing();
+            default:
+                throw new TaskException("The task misfire policy '" + job.getMisfirePolicy()
+                        + "' cannot be used in cron schedule tasks", TaskException.Code.CONFIG_ERROR);
+        }
+    }
+
+    /**
+     * 检查包名是否为白名单配置
+     *
+     * @param invokeTarget 目标字符串
+     * @return 结果
+     */
+    public static boolean whiteList(String invokeTarget) {
+        String packageName = StringUtils.substringBefore(invokeTarget, "(");
+        int count = StringUtils.countMatches(packageName, ".");
+        if (count > 1) {
+            return StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR);
+        }
+        Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]);
+        String beanPackageName = obj.getClass().getPackage().getName();
+        return StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_WHITELIST_STR)
+                && !StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_ERROR_STR);
+    }
+}

+ 0 - 1
himeeter-quartz/src/main/resources/application.properties

@@ -1 +0,0 @@
-spring.application.name=himeeter-quartz

+ 94 - 0
himeeter-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml

@@ -0,0 +1,94 @@
+<?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.lij.himeeter.quartz.mapper.SysJobLogMapper">
+
+	<resultMap type="SysJobLog" id="SysJobLogResult">
+		<id     property="jobLogId"       column="job_log_id"      />
+		<result property="jobName"        column="job_name"        />
+		<result property="jobGroup"       column="job_group"       />
+		<result property="invokeTarget"   column="invoke_target"   />
+		<result property="jobMessage"     column="job_message"     />
+		<result property="status"         column="status"          />
+		<result property="exceptionInfo"  column="exception_info"  />
+		<result property="createTime"     column="create_time"     />
+	</resultMap>
+	
+	<sql id="selectJobLogVo">
+        select job_log_id, job_name, job_group, invoke_target, job_message, status, exception_info, create_time 
+		from sys_job_log
+    </sql>
+	
+	<select id="selectJobLogList" parameterType="SysJobLog" resultMap="SysJobLogResult">
+		<include refid="selectJobLogVo"/>
+		<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>
+			<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
+				and date_format(create_time,'%Y%m%d') &gt;= date_format(#{params.beginTime},'%Y%m%d')
+			</if>
+			<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
+				and date_format(create_time,'%Y%m%d') &lt;= date_format(#{params.endTime},'%Y%m%d')
+			</if>
+		</where>
+		order by create_time desc
+	</select>
+	
+	<select id="selectJobLogAll" resultMap="SysJobLogResult">
+		<include refid="selectJobLogVo"/>
+	</select>
+	
+	<select id="selectJobLogById" parameterType="Long" resultMap="SysJobLogResult">
+		<include refid="selectJobLogVo"/>
+		where job_log_id = #{jobLogId}
+	</select>
+	
+	<delete id="deleteJobLogById" parameterType="Long">
+ 		delete from sys_job_log where job_log_id = #{jobLogId}
+ 	</delete>
+ 	
+ 	<delete id="deleteJobLogByIds" parameterType="Long">
+ 		delete from sys_job_log where job_log_id in
+ 		<foreach collection="array" item="jobLogId" open="(" separator="," close=")">
+ 			#{jobLogId}
+        </foreach> 
+ 	</delete>
+ 	
+ 	<update id="cleanJobLog">
+        truncate table sys_job_log
+    </update>
+ 	
+ 	<insert id="insertJobLog" parameterType="SysJobLog">
+ 		insert into sys_job_log(
+ 			<if test="jobLogId != null and jobLogId != 0">job_log_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="jobMessage != null and jobMessage != ''">job_message,</if>
+ 			<if test="status != null and status != ''">status,</if>
+ 			<if test="exceptionInfo != null and exceptionInfo != ''">exception_info,</if>
+ 			create_time
+ 		)values(
+ 			<if test="jobLogId != null and jobLogId != 0">#{jobLogId},</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="jobMessage != null and jobMessage != ''">#{jobMessage},</if>
+ 			<if test="status != null and status != ''">#{status},</if>
+ 			<if test="exceptionInfo != null and exceptionInfo != ''">#{exceptionInfo},</if>
+ 			sysdate()
+ 		)
+	</insert>
+
+</mapper> 

+ 111 - 0
himeeter-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml

@@ -0,0 +1,111 @@
+<?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.lij.himeeter.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> 

+ 2 - 2
himeeter-ui/himeeter-ui-system/.env.development

@@ -1,8 +1,8 @@
 # 页面标题
-VITE_APP_TITLE = 若依管理系统
+VITE_APP_TITLE = Himeeter管理系统
 
 # 开发环境配置
 VITE_APP_ENV = 'development'
 
-# 若依管理系统/开发环境
+# Himeeter管理系统/开发环境
 VITE_APP_BASE_API = '/dev-api'

+ 2 - 2
himeeter-ui/himeeter-ui-system/.env.production

@@ -1,10 +1,10 @@
 # 页面标题
-VITE_APP_TITLE = 若依管理系统
+VITE_APP_TITLE = Himeeter管理系统
 
 # 生产环境配置
 VITE_APP_ENV = 'production'
 
-# 若依管理系统/生产环境
+# Himeeter管理系统/生产环境
 VITE_APP_BASE_API = '/prod-api'
 
 # 是否在打包时开启压缩,支持 gzip 和 brotli

+ 2 - 2
himeeter-ui/himeeter-ui-system/.env.staging

@@ -1,10 +1,10 @@
 # 页面标题
-VITE_APP_TITLE = 若依管理系统
+VITE_APP_TITLE = Himeeter管理系统
 
 # 生产环境配置
 VITE_APP_ENV = 'staging'
 
-# 若依管理系统/生产环境
+# Himeeter管理系统/生产环境
 VITE_APP_BASE_API = '/stage-api'
 
 # 是否在打包时开启压缩,支持 gzip 和 brotli

+ 1 - 1
himeeter-ui/himeeter-ui-system/index.html

@@ -7,7 +7,7 @@
   <meta name="renderer" content="webkit">
   <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
   <link rel="icon" href="/favicon.ico">
-  <title>若依管理系统</title>
+  <title>Himeeter管理系统</title>
   <!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
   <style>
     html,

+ 4 - 4
himeeter-ui/himeeter-ui-system/package.json

@@ -1,8 +1,8 @@
 {
-  "name": "ruoyi",
-  "version": "3.8.8",
-  "description": "若依管理系统",
-  "author": "若依",
+  "name": "Himeeter",
+  "version": "1.0.0",
+  "description": "Himeeter管理系统",
+  "author": "Himeeter",
   "license": "MIT",
   "type": "module",
   "scripts": {

+ 1 - 1
himeeter-ui/himeeter-ui-system/src/views/login.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="login">
     <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
-      <h3 class="title">若依后台管理系统</h3>
+      <h3 class="title">Himeeter后台管理系统</h3>
       <el-form-item prop="username">
         <el-input
           v-model="loginForm.username"

+ 1 - 1
himeeter-ui/himeeter-ui-system/src/views/register.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="register">
     <el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form">
-      <h3 class="title">若依后台管理系统</h3>
+      <h3 class="title">Himeeter后台管理系统</h3>
       <el-form-item prop="username">
         <el-input 
           v-model="registerForm.username"