无关风月
2025-06-17 727c924dd3e85aa4f277106dd1bd54a758fc3d22
Merge remote-tracking branch 'origin/master'
7个文件已添加
7个文件已修改
640 ■■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TTemplateController.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/TaskUtil.java 269 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/TTemplateDetail.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/task/base/AbstractJob.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/task/base/QuartzManager.java 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/task/base/TimeJobType.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/task/exceptions/TimeException.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/task/jobs/CreateInspectionJob.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/task/utils/SpringContextsUtil.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TTemplateController.java
@@ -4,6 +4,7 @@
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.ImmutableMap;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.common.core.domain.R;
@@ -16,6 +17,9 @@
import com.ruoyi.system.model.TTemplateDetail;
import com.ruoyi.system.query.TemplateListQuery;
import com.ruoyi.system.service.*;
import com.ruoyi.system.task.base.QuartzManager;
import com.ruoyi.system.task.base.TimeJobType;
import com.ruoyi.system.task.jobs.CreateInspectionJob;
import com.ruoyi.system.vo.system.TemplateDetailVO;
import com.ruoyi.system.vo.system.TemplateListVO;
import io.swagger.annotations.Api;
@@ -23,9 +27,7 @@
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
/**
@@ -71,6 +73,22 @@
            tTemplateDetail.setTemplateId(dto.getId());
        }
        templateDetailService.saveBatch(list);
        // 计算定时任务时间周期
        // 添加定时任务
//        Map<String, ? extends Object> maps =
//                new ImmutableMap.Builder<String, String>().
//                        put("id", dto.getId())
//                        .build();
//        QuartzManager.addJob(
//                CreateInspectionJob.class,
//                (CreateInspectionJob.name+dto.getId()).toUpperCase(),
//                TimeJobType.CREATE_INSPECTION,
//                new Date(new Date().getTime()+48*60*60*1000L),
//                maps
//        );
        return R.ok();
    }
    @Log(title = "编辑任务模板", businessType = BusinessType.UPDATE)
@@ -81,6 +99,23 @@
        templateDetailService.remove(new LambdaQueryWrapper<TTemplateDetail>()
                .eq(TTemplateDetail::getTemplateId,  dto.getId()));
        templateDetailService.saveBatch(dto.getList());
        // 先删除定时任务
//        QuartzManager.removeJob((CreateInspectionJob.name+dto.getId()).toUpperCase(),TimeJobType.CREATE_INSPECTION);
        // 添加定时任务
//        Map<String, ? extends Object> maps =
//                new ImmutableMap.Builder<String, String>().
//                        put("id", dto.getId())
//                        .build();
//        QuartzManager.addJob(
//                CreateInspectionJob.class,
//                (CreateInspectionJob.name+dto.getId()).toUpperCase(),
//                TimeJobType.CREATE_INSPECTION,
//                new Date(new Date().getTime()+48*60*60*1000L),
//                maps
//        );
        return R.ok();
    }
    @Log(title = "批量删除任务模板", businessType = BusinessType.DELETE)
ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/TaskUtil.java
New file
@@ -0,0 +1,269 @@
package com.ruoyi.web.controller.task;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.system.mapper.TCleanerMapper;
import com.ruoyi.system.model.*;
import com.ruoyi.system.service.*;
import javafx.concurrent.Task;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
 * @author xiaochen
 * @date 2025/6/11 18:39
 */
@Component
public class TaskUtil {
    // 项目部权重标识
    private static final String PROJECT_DEPT_WEIGHT = ":PROJECT_DEPT_WEIGHT";
    // 保洁员权重标识
    private static final String CLEANER_WEIGHT = ":CLEANER_WEIGHT";
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private TTemplateService templateService;
    @Autowired
    private TTemplateDetailService templateDetailService;
    @Autowired
    private TProjectDeptService projectDeptService;
    @Autowired
    private TCleanerService cleanerService;
    @Autowired
    private TLocationService locationService;
    @Autowired
    private TLocationTypeService locationTypeService;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private TTaskCleanService taskCleanService;
    @Scheduled(cron = "0 0 0 * * ?")
    public void dayOfCreateInspection() {
        try {
            // 查询任务模板
            List<TTemplate> list = templateService.list();
            if (CollectionUtils.isEmpty(list)) {
                return;
            }
            list.forEach(template -> {
                // 创建任务
                createInspection(template);
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void createInspection(TTemplate template) {
        // 查询所有的模板详情
        List<TTemplateDetail> list = templateDetailService.list(Wrappers.lambdaQuery(TTemplateDetail.class)
                .eq(TTemplateDetail::getTemplateId, template.getId()));
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        // 通过模板id查询员工巡检员
        List<SysUser> sysUsers = sysUserService.selectUserByTempLateId(template.getId());
        // 创建任务
        list.forEach(detail -> {
            // 计算周期
            long cycle = detail.getCycle();
            switch (detail.getCycleType()){
                case 2:
                    cycle = cycle * 7;
                    break;
                case 3:
                    cycle = cycle * 30;
                    break;
                case 4:
                    cycle = cycle * 90;
                    break;
                case 5:
                    cycle = cycle * 365;
                    break;
            }
            // 拿到保洁抽查次数
            int num1 = detail.getNum1();
            // 拿到项目部数
            int num2 = detail.getNum2();
            // 拿到每日重复点位
            int num3 = detail.getNum3();
            // 获取点位类型的占比
            String num4 = detail.getNum4();
            // 获取项目部在该模板详情中的权重
            List<String> projectDeptIds = redisCache.getCacheList(detail.getId() + PROJECT_DEPT_WEIGHT);
            // 获取项目部列表
            List<TProjectDept> projectDeptList;
            if(CollectionUtils.isEmpty(projectDeptIds)){
                projectDeptList = projectDeptService.list(Wrappers.lambdaQuery(TProjectDept.class));
            }else {
                projectDeptList = projectDeptService.list(Wrappers.lambdaQuery(TProjectDept.class)
                        .in(TProjectDept::getId, projectDeptIds));
                // 所过所有的项目部都被抽取了,则重新抽取,并且清空项目部权重
                if(CollectionUtils.isEmpty(projectDeptList)){
                    projectDeptList = projectDeptService.list(Wrappers.lambdaQuery(TProjectDept.class));
                    redisCache.deleteObject(detail.getId() + PROJECT_DEPT_WEIGHT);
                }
            }
            // 如果可抽取的项目部数不足,先抽取余下项目部后,再清空权重,重新抽取
            List<TProjectDept> projectDepts = randomSelection(projectDeptList, num2);
            if(projectDepts.size() < num2){
                List<String> proIds = projectDepts.stream().map(TProjectDept::getId).collect(Collectors.toList());
                List<TProjectDept> projectDeptList1 = projectDeptService.list(Wrappers.lambdaQuery(TProjectDept.class)
                        .notIn(TProjectDept::getId, proIds));
                redisCache.deleteObject(detail.getId() + PROJECT_DEPT_WEIGHT);
                List<TProjectDept> projectDepts1 = randomSelection(projectDeptList1, num2 - projectDepts.size());
                List<String> proIds1 = projectDepts1.stream().map(TProjectDept::getId).collect(Collectors.toList());
                // 将已抽取的项目部id保存到redis中
                redisCache.setCacheList(detail.getId() + PROJECT_DEPT_WEIGHT, proIds1);
                projectDepts.addAll(projectDepts1);
            }else {
                List<String> proIds = projectDepts.stream().map(TProjectDept::getId).collect(Collectors.toList());
                // 将已抽取的项目部id保存到redis中
                redisCache.setCacheList(detail.getId() + PROJECT_DEPT_WEIGHT, proIds);
            }
            List<String> proIds = projectDepts.stream().map(TProjectDept::getId).collect(Collectors.toList());
            // 拿到抽取的项目部下的所有保洁员
            List<TProjectDept> tProjectDeptList = projectDeptService.list(Wrappers.lambdaQuery(TProjectDept.class)
                    .in(TProjectDept::getParentId, proIds));
            // 获取片区id
            List<String> areaIds = tProjectDeptList.stream().map(TProjectDept::getId).collect(Collectors.toList());
            // 计算每天需要抽取多少个保洁员
            long count = cleanerService.count(Wrappers.lambdaQuery(TCleaner.class)
                    .in(TCleaner::getProjectId, areaIds));
            int cleanerSums = num1 * Integer.parseInt(count + "");
            // 获取每天需要抽取的保洁员数,向上取整
            int dayCleanerCount = cleanerSums / detail.getCycle();
            // 获取保洁员权重
            List<String> cleanerIds = redisCache.getCacheList(detail.getId() + CLEANER_WEIGHT);
            // 获取保洁员列表
            List<TCleaner> cleaners;
            if(CollectionUtils.isEmpty(cleanerIds)){
                cleaners = cleanerService.list(Wrappers.lambdaQuery(TCleaner.class)
                        .in(TCleaner::getProjectId, areaIds));
            }else {
                cleaners = cleanerService.list(Wrappers.lambdaQuery(TCleaner.class)
                        .in(TCleaner::getProjectId, areaIds)
                        .notIn(TCleaner::getId, cleanerIds));
                if(CollectionUtils.isEmpty(cleaners)){
                    cleaners = cleanerService.list(Wrappers.lambdaQuery(TCleaner.class)
                            .in(TCleaner::getProjectId, areaIds));
                    redisCache.deleteObject(detail.getId() + CLEANER_WEIGHT);
                }
            }
            // 抽取保洁员
            List<TCleaner> tCleaners = randomSelection(cleaners, dayCleanerCount);
            if(tCleaners.size() < dayCleanerCount){
                List<String> cleanIds = tCleaners.stream().map(TCleaner::getId).collect(Collectors.toList());
                List<TCleaner> cleaners1 = cleanerService.list(Wrappers.lambdaQuery(TCleaner.class)
                        .in(TCleaner::getProjectId, areaIds)
                        .notIn(TCleaner::getId, cleanIds));
                redisCache.deleteObject(detail.getId() + CLEANER_WEIGHT);
                List<TCleaner> tCleaners1 = randomSelection(cleaners1, dayCleanerCount - tCleaners.size());
                List<String> cleanIds1 = tCleaners1.stream().map(TCleaner::getId).collect(Collectors.toList());
                // 将已抽取的项目部id保存到redis中
                redisCache.setCacheList(detail.getId() + CLEANER_WEIGHT, cleanIds1);
                tCleaners.addAll(tCleaners1);
            }else {
                List<String> cleanIds = tCleaners.stream().map(TCleaner::getId).collect(Collectors.toList());
                redisCache.setCacheList(detail.getId() + CLEANER_WEIGHT, cleanIds);
            }
            // 通过保洁员id查询点位
            List<String> cleanersIds = tCleaners.stream().map(TCleaner::getId).collect(Collectors.toList());
            List<TLocation> locationList = locationService.list(Wrappers.lambdaQuery(TLocation.class)
                    .in(TLocation::getLocationCleaner, cleanersIds));
            // 查询点位类型
//            List<TLocationType> locationTypes = locationTypeService.list(Wrappers.lambdaQuery(TLocationType.class)
//                    .orderByDesc(TLocationType::getCreateTime));
            JSONArray jsonArray = JSONObject.parseArray(num4);
            List<TLocation> tLocationList = new ArrayList<>();
            for (Object o : jsonArray) {
                JSONObject jsonObject = JSONObject.parseObject(o.toString());
                String id = jsonObject.getString("id");
                BigDecimal value = jsonObject.getBigDecimal("value");
                List<TLocation> locations = locationList.stream().filter(tLocation -> tLocation.getLocationType().equals(id)).collect(Collectors.toList());
                if(!CollectionUtils.isEmpty(locations)){
                    BigDecimal bigDecimal = new BigDecimal(locations.size()).multiply(value.divide(new BigDecimal(100), 2, BigDecimal.ROUND_DOWN)).setScale(0, BigDecimal.ROUND_UP);
                    int locationCount = bigDecimal.intValue();
                    if(locationCount > 0){
                        List<TLocation> tLocations = randomSelection(locations, locationCount);
                        tLocationList.addAll(tLocations);
                    }
                }
            }
            // TODO 抽取重复点位
            // 创建任务
            List<TTask> tasks = new ArrayList<>();
            for (TLocation tLocation : tLocationList) {
                TTask task = new TTask();
                // 获取保洁员
                tCleaners.stream().filter(tCleaner -> tCleaner.getId().equals(tLocation.getLocationCleaner())).findFirst().ifPresent(tCleaner -> {
                    task.setProjectId(tCleaner.getProjectId());
                    task.setCleanerId(tCleaner.getId());
                });
                // 获取巡检员
                if(!CollectionUtils.isEmpty(sysUsers)){
                    SysUser sysUser = sysUsers.get(0);
                    task.setPatrolInspector(sysUser.getUserId().toString());
                    task.setPatrolInspectorDept(sysUser.getDeptId());
                }
                task.setStatus(1);
                task.setLocationId(tLocation.getId());
                task.setImplementTime(LocalDateTime.now().plusDays(1));
                task.setTaskType(1);
                tasks.add(task);
            }
            taskCleanService.saveBatch(tasks);
        });
    }
    /**
     * 从集合中随机抽取数量
     * @param list
     * @param size
     * @return
     * @param <T>
     */
    private static <T> List<T> randomSelection(List<T> list, int size) {
        List<T> selected = new ArrayList<>();
        int length = list.size();
        for (int i = 0; i < size; i++) {
            Collections.shuffle(list);
            // 如果需求的大小超过了集合的长度,则只能取到集合的全部元素
            int subListSize = Math.min(size - selected.size(), length);
            selected.addAll(list.subList(0, subListSize));
        }
        return selected;
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
@@ -33,7 +33,8 @@
    /** 部门ID */
    //@Excel(name = "部门编号", type = Type.IMPORT)
    @ApiModelProperty(value = "部门id")
    private Long deptId;
    @TableField("deptId")
    private String deptId;
    /** 用户账号 */
    //@Excel(name = "登录名称")
@@ -191,12 +192,12 @@
        return userId != null && 1L == userId;
    }
    public Long getDeptId()
    public String getDeptId()
    {
        return deptId;
    }
    public void setDeptId(Long deptId)
    public void setDeptId(String deptId)
    {
        this.deptId = deptId;
    }
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
@@ -176,4 +176,6 @@
    void updatePassword(@Param("id") Long id,@Param("s") String s);
    long selectIdByPhone(@Param("phonenumber") String phonenumber);
    List<SysUser> selectUserByTempLateId(@Param("templateId")String templateId);
}
ruoyi-system/src/main/java/com/ruoyi/system/model/TTemplateDetail.java
@@ -29,9 +29,13 @@
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private String id;
    @ApiModelProperty(value = "周期 单位天")
    @ApiModelProperty(value = "周期值")
    @TableField("cycle")
    private Integer cycle;
    @ApiModelProperty(value = "周期 单位 1=天 2=周 3=月 4=季度 5=年度")
    @TableField("cycle_type")
    private Integer cycleType;
    @ApiModelProperty(value = "每个保洁员被抽查")
    @TableField("num1")
@@ -48,11 +52,11 @@
    @ApiModelProperty(value = "点位类型覆盖率json {\n" +
            "\t\"num5\": [{\n" +
            "\t\t\"id\": \"18678093453\",\n" +
            "\t\t\"value\": \"18\"\n" +
            "\t\t\"value\": 18\n" +
            "\n" +
            "\t}, {\n" +
            "\t\t\"id\": \"18678093453\",\n" +
            "\t\t\"value\": \"18\"\n" +
            "\t\t\"value\": 18\n" +
            "\t}]\n" +
            "\n" +
            "}")
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java
@@ -261,4 +261,6 @@
    void updatePassword(Long id, String s);
    long selectIdByPhone(String phonenumber);
    List<SysUser> selectUserByTempLateId(String templateId);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
@@ -726,6 +726,11 @@
    }
    @Override
    public List<SysUser> selectUserByTempLateId(String templateId) {
        return userMapper.selectUserByTempLateId(templateId);
    }
    @Override
    public SysUser selectByPhone(String phonenumber) {
        return userMapper.selectByPhone(phonenumber);
    }
ruoyi-system/src/main/java/com/ruoyi/system/task/base/AbstractJob.java
New file
@@ -0,0 +1,33 @@
package com.ruoyi.system.task.base;
import com.aizuda.bpm.mybatisplus.mapper.FlwTaskActorMapper;
import com.aizuda.bpm.mybatisplus.mapper.FlwTaskMapper;
import com.ruoyi.common.utils.SmsUtil;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.task.utils.SpringContextsUtil;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractJob implements Job{
    protected Logger logger = LoggerFactory.getLogger(getClass());
    @Override
    public abstract void execute(JobExecutionContext context) throws JobExecutionException;
    protected FlwTaskMapper flwTaskMapper;
    protected FlwTaskActorMapper flwTaskActorMapper;
    protected SmsUtil smsUtil;
    protected ISysUserService sysUserService;
    public AbstractJob(){
        this.flwTaskMapper = SpringContextsUtil.getBean(FlwTaskMapper.class);
        this.flwTaskActorMapper = SpringContextsUtil.getBean(FlwTaskActorMapper.class);
        this.smsUtil = SpringContextsUtil.getBean(SmsUtil.class);
        this.sysUserService = SpringContextsUtil.getBean(ISysUserService.class);
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/task/base/QuartzManager.java
New file
@@ -0,0 +1,128 @@
package com.ruoyi.system.task.base;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.Date;
import java.util.Map;
public class QuartzManager {
    private static SchedulerFactory factory = new StdSchedulerFactory();
    private static final String TRIGGER_NAME_PREFIX = "TRIGGER_PREFIX_";
    private static final String JOB_NAME_PREFIX = "JOB_PREFIX_";
    /**
     * 添加定时任务:具体某个时间点执行一次的任务,如:在某个2015-06-01 12:00发送一条消息
     *
     * @param jobName
     *            具体的任务名+ID标识唯一
     * @param jobType
     * @param date
     * @param jp
     */
    public synchronized static void addJob(Class<? extends Job> jobClass, String jobName, TimeJobType jobType, Date date,
                                           Map<String,  ? extends Object> jp) {
        //logger.debug("ADD JOB {},jobName={},jobTyep={},jobDate={},",jobClass.getName(),jobName,jobType,date);
        try {
            Scheduler sched = factory.getScheduler();
            JobDetail job = JobBuilder.newJob(jobClass).withIdentity(JOB_NAME_PREFIX + jobName, jobType.getType())
                    .setJobData(new JobDataMap(jp)).build();
            SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
                    .withIdentity(TRIGGER_NAME_PREFIX + jobName, jobType.getType()).startAt(date).build();
            removeJob(jobName, jobType);
            sched.scheduleJob(job, trigger);
            if (!sched.isShutdown()) {
                sched.start();
            }
        } catch (Exception e) {
            //logger.error("ADD JOB exception {},jobName={},jobTyep={},jobDate={},",jobClass.getName(),jobName,jobType,date);
        }
    }
       /**
        * 修改一个任务的触发时间(使用默认的任务组名,触发器名,触发器组名)
        * @param jobName
        * @param time
        */
        public synchronized static void modifyJobTime(String jobName,TimeJobType jobType, Date time) {
             //logger.error("Update JOB exception,jobName={},jobTyep={},jobDate={}," ,jobName,jobType,time);
            try {
                JobKey jobKey = new JobKey(JOB_NAME_PREFIX + jobName, jobType.getType());
                TriggerKey key = new TriggerKey(TRIGGER_NAME_PREFIX + jobName, jobType.getType());
                Scheduler sched = factory.getScheduler();
                SimpleTrigger trigger = (SimpleTrigger) sched.getTrigger(key);
                if(trigger == null) {
                    return;
                }
                Date oldTime = trigger.getStartTime();
                if (oldTime.getTime() != time.getTime()) {
                    JobDetail jobDetail = sched.getJobDetail(jobKey);
                    Class<? extends Job> objJobClass = jobDetail.getJobClass();
                    removeJob(jobName,jobType);
                    Map<String, Object> jp = jobDetail.getJobDataMap();
                    addJob(objJobClass, jobName, jobType, time, jp);
                }
            } catch (Exception e) {
               // logger.error("Update JOB exception,jobName={},jobTyep={},jobDate={}," ,jobName,jobType,time);
            }
        }
    /**
     * 移除一个任务
     *
     * @param jobName
     */
    public synchronized static void removeJob(String jobName, TimeJobType jobType) {
        try {
            JobKey jobKey = new JobKey(JOB_NAME_PREFIX + jobName, jobType.getType());
            TriggerKey key = new TriggerKey(TRIGGER_NAME_PREFIX + jobName, jobType.getType());
            Scheduler sched = factory.getScheduler();
            JobDetail detail = sched.getJobDetail(jobKey);
            if (detail != null) {
                sched.pauseJob(jobKey);
                sched.pauseTrigger(key);// 停止触发器
                sched.unscheduleJob(key);// 移除触发器
                sched.deleteJob(jobKey);// 删除任务
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    /**
     * 启动所有定时任务
     */
    public synchronized static void startJobs() {
        try {
            Scheduler sched = factory.getScheduler();
            sched.start();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    /**
     * 关闭所有定时任务
     */
    public synchronized static void shutdownJobs() {
        try {
            Scheduler sched = factory.getScheduler();
            if (!sched.isShutdown()) {
                sched.shutdown();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/task/base/TimeJobType.java
New file
@@ -0,0 +1,28 @@
package com.ruoyi.system.task.base;
/**
 * @Description 按时间点发布的任务类型
 * @date 2025年2月17日 下午7:22:28
 */
public enum TimeJobType {
    CREATE_INSPECTION("create_inspection","创建巡检任务");
    private String type;
    private String desc;
    private TimeJobType(String type, String desc) {
        this.type = type;
        this.desc = desc;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/task/exceptions/TimeException.java
New file
@@ -0,0 +1,37 @@
package com.ruoyi.system.task.exceptions;
/**
 * @文件说明:定时器任务执行异常
 * @版权所有:成都喜来达
 * @项目名称: fengsheng
 * @创建者: Leeyns
 * @创建日期: 2016年5月18日
 * @最近修改者:Leeyns
 * @最近修改日期:2016年5月18日
 */
public class TimeException extends Exception {
    /**
     *  TODO
     */
    private static final long serialVersionUID = 5703430073981692250L;
    private String message;
    public TimeException() {
        super();
    }
    public TimeException(String message) {
        super(message);
        this.message = message;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/task/jobs/CreateInspectionJob.java
New file
@@ -0,0 +1,33 @@
package com.ruoyi.system.task.jobs;
import com.ruoyi.system.task.base.AbstractJob;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
 * 发票定时任务
 * @author Administrator
 *
 */
public class CreateInspectionJob extends AbstractJob {
    public static final String name = "createInspection_";
    @Override
    public void execute(JobExecutionContext context)
            throws JobExecutionException {
        JobDataMap maps = context.getMergedJobDataMap();
        String templateId = maps.getString("id");
        try {
            // 查询模板
            System.err.println("执行定时任务");
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/task/utils/SpringContextsUtil.java
New file
@@ -0,0 +1,37 @@
package com.ruoyi.system.task.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringContextsUtil implements ApplicationContextAware{
    private static ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringContextsUtil.applicationContext == null) {
            SpringContextsUtil.applicationContext = applicationContext;
        }
    }
    // 获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    // 通过name获取 Bean.
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }
    // 通过class获取Bean.
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }
    // 通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name, Class<T> clazz) {
        System.out.println(getApplicationContext().getBean(name, clazz));
        return getApplicationContext().getBean(name, clazz);
    }
}
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -257,8 +257,14 @@
    <select id="selectIdByPhone" resultType="java.lang.Long">
        select user_id from sys_user where phonenumber = #{phonenumber} and status = 0 and del_flag = 0
    </select>
    <select id="selectUserByTempLateId" resultType="com.ruoyi.common.core.domain.entity.SysUser">
        select u.user_id AS userId, u.dept_id AS deptId, u.user_name AS userName, u.nick_name AS nickName, u.email AS email, u.avatar AS avatar,
               u.phonenumber AS phonenumber, u.sex AS sex, u.status AS status, u.del_flag AS delFlag, u.login_ip AS loginIp,
               u.login_date AS loginDate, u.create_by AS createBy, u.create_time AS createTime, u.remark AS remark,u.templateId
        from sys_user u where u.templateId = #{templateId} and u.status = 0 and u.del_flag = 0
    </select>
    <insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId">
    <insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId">
         insert into sys_user(
             <if test="userId != null and userId != 0">user_id,</if>
             <if test="deptId != null and deptId != 0">dept_id,</if>