Ver Fonte

Merge branch 'dev' of http://192.168.1.245:11111/jinjilong/onlineEducation-fwd into dev

honorfire há 7 meses atrás
pai
commit
d221c57d32

+ 2 - 0
snowy-plugin/snowy-plugin-dev/snowy-plugin-dev-api/src/main/java/vip/xiaonuo/dev/api/DevJobApi.java

@@ -28,4 +28,6 @@ public interface DevJobApi {
     JSONObject editJob(JSONObject editParam);
 
     JSONObject deleteJob(List<String> ids);
+
+    JSONObject queryEntity(String id);
 }

+ 21 - 1
snowy-plugin/snowy-plugin-dev/snowy-plugin-dev-func/src/main/java/vip/xiaonuo/dev/modular/job/provider/DevJobApiProvider.java

@@ -12,6 +12,7 @@
  */
 package vip.xiaonuo.dev.modular.job.provider;
 
+import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSONObject;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -44,7 +45,7 @@ public class DevJobApiProvider implements DevJobApi {
         try {
             DevJobAddParam devJobAddParam = JSONObject.toJavaObject(addParam, DevJobAddParam.class);
             DevJob devJob = devJobService.add(devJobAddParam);
-            result.put("data", devJob);
+            result.put("data", JSONUtil.parseObj(devJob));
             result.put("code", 200);
             result.put("msg", "任务添加成功");
             return result;
@@ -99,4 +100,23 @@ public class DevJobApiProvider implements DevJobApi {
             return JSONObject.parseObject("{\"code\":500,\"msg\":\"任务删除失败\"}");
         }
     }
+
+    @Override
+    public JSONObject queryEntity(String id) {
+        JSONObject result = new JSONObject();
+        try {
+            DevJob devJob = devJobService.queryEntity(id);
+            if(devJob != null){
+                result.put("code", 200);
+                result.put("msg", "任务查询成功");
+                result.put("data", JSONUtil.parseObj(devJob));
+                return result;
+            }else{
+                return JSONObject.parseObject("{\"code\":500,\"msg\":\"任务查询失败\"}");
+            }
+        } catch (Exception e) {
+            log.error("任务查询", e);
+            return JSONObject.parseObject("{\"code\":500,\"msg\":\"任务查询失败\"}");
+        }
+    }
 }

+ 1 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/controller/admin/TExamController.java

@@ -128,4 +128,5 @@ public class TExamController extends BaseApiController {
         return CommonResult.data(tExamService.detail(tExamIdParam));
     }
 
+
 }

+ 3 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/TExam.java

@@ -81,4 +81,7 @@ public class TExam {
     /** 软删除 */
     @ApiModelProperty(value = "软删除", position = 12)
     private Integer deleted;
+
+    @ApiModelProperty(value = "任务ID", position = 13)
+    private String jobId;
 }

+ 2 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/exam/TExamAddParam.java

@@ -63,4 +63,6 @@ public class TExamAddParam {
     @ApiModelProperty(value = "软删除", position = 12)
     private Integer deleted;
 
+    @ApiModelProperty(value = "任务ID", position = 13)
+    private String jobId;
 }

+ 2 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/exam/TExamEditParam.java

@@ -68,4 +68,6 @@ public class TExamEditParam {
     @ApiModelProperty(value = "软删除", position = 12)
     private Integer deleted;
 
+    @ApiModelProperty(value = "任务ID", position = 13)
+    private String jobId;
 }

+ 3 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/exam/TExamPageParam.java

@@ -76,6 +76,9 @@ public class TExamPageParam {
     @ApiModelProperty(value = "试卷ID")
     private String paperId;
 
+    @ApiModelProperty(value = "任务ID")
+    private String jobId;
+
     /** 学生ID **/
     private String userId;
 }

+ 28 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/job/task/ExamJobTimerTaskRunner.java

@@ -0,0 +1,28 @@
+package vip.xiaonuo.exam.job.task;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import vip.xiaonuo.common.timer.CommonTimerTaskRunner;
+
+/**
+ * @PackageName:vip.xiaonuo.exam.job.task
+ * @ClassName:ExamJobTimerTaskRunner
+ * @Author ZSS
+ * @Date 2025-07-25 10:12
+ * @Note: 考试定时任务执行类
+ **/
+@Slf4j
+@Component
+public class ExamJobTimerTaskRunner implements CommonTimerTaskRunner {
+
+    /**
+     * 任务执行的具体内容
+     *
+     * @author xuyuxiang
+     * @date 2022/8/15 16:09
+     **/
+    @Override
+    public void action() {
+
+    }
+}

+ 84 - 2
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/service/impl/TExamServiceImpl.java

@@ -14,16 +14,23 @@ package vip.xiaonuo.exam.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollStreamUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.aliyun.oss.ServiceException;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import vip.xiaonuo.common.enums.CommonSortOrderEnum;
 import vip.xiaonuo.common.exception.CommonException;
 import vip.xiaonuo.common.page.CommonPageRequest;
+import vip.xiaonuo.dev.api.DevJobApi;
 import vip.xiaonuo.exam.domain.CourseChapterPaper;
 import vip.xiaonuo.exam.domain.ExamPaper;
 import vip.xiaonuo.exam.domain.TExam;
@@ -38,7 +45,7 @@ import vip.xiaonuo.exam.service.ExamPaperService;
 import vip.xiaonuo.exam.service.TExamService;
 import javax.annotation.Resource;
 import java.util.List;
-
+import vip.xiaonuo.exam.utility.DateTimeUtil;
 
 /**
  * 考试表Service接口实现类
@@ -46,6 +53,7 @@ import java.util.List;
  * @author ZSS
  * @date  2025/07/22 10:51
  **/
+@Slf4j
 @Service
 public class TExamServiceImpl extends ServiceImpl<TExamMapper, TExam> implements TExamService {
 
@@ -55,6 +63,9 @@ public class TExamServiceImpl extends ServiceImpl<TExamMapper, TExam> implements
     @Resource
     private CourseChapterPaperMapper courseChapterPaperMapper;
 
+    @Resource
+    private DevJobApi devJobApi;
+
     @Override
     public Page<TExam> page(TExamPageParam tExamPageParam) {
         QueryWrapper<TExam> queryWrapper = new QueryWrapper<>();
@@ -103,6 +114,9 @@ public class TExamServiceImpl extends ServiceImpl<TExamMapper, TExam> implements
             cp.setType("0"); // 章节测验
             courseChapterPaperMapper.add(cp);
         }
+        if(tExamAddParam.getStartTime() != null && tExamAddParam.getEndTime() != null){
+            this.addJob(tExam);
+        }
     }
 
     @Transactional(rollbackFor = Exception.class)
@@ -119,14 +133,58 @@ public class TExamServiceImpl extends ServiceImpl<TExamMapper, TExam> implements
             cp.setPaperId(tExamEditParam.getPaperId());
             courseChapterPaperMapper.add(cp);
         }
-        BeanUtil.copyProperties(tExamEditParam, tExam);
+        boolean updateJob = false;
         if(tExamEditParam.getPaperId() != null && !tExamEditParam.getPaperId().isEmpty()){
             ExamPaper examPaper = examPaperService.selectById(Integer.parseInt(tExamEditParam.getPaperId()));
             if(ExamPaperTypeEnum.TimeLimit.getCode() == examPaper.getPaperType()){
                 tExamEditParam.setStartTime(examPaper.getLimitStartTime());
                 tExamEditParam.setEndTime(examPaper.getLimitEndTime());
+                updateJob = true;
             }
         }
+        if(tExamEditParam.getStartTime() !=null || tExamEditParam.getEndTime() !=null){
+            updateJob = true;
+        }
+        if(updateJob){
+            // 修改定时任务
+            JSONObject jobQuery = devJobApi.queryEntity(tExamEditParam.getJobId());
+            if(jobQuery != null && jobQuery.getInteger("code") == 200){
+                JSONObject jobEntity = jobQuery.getJSONObject("data");
+                if(jobEntity != null && jobEntity.getString("jobStatus") != null && jobEntity.getString("jobStatus").equals("STOPPED")){
+                    // 查的到任务已经结束了,删掉历史建新的
+                    List<String> jobIds = CollectionUtil.newArrayList(tExam.getJobId());
+                    JSONObject deleteJobResult = devJobApi.deleteJob(jobIds);
+                    if(deleteJobResult != null && deleteJobResult.getInteger("code") == 200){
+                        tExam = this.addJob(tExam);
+                    }else{
+                        log.error("任务修改失败,删除过期任务异常。{}",deleteJobResult);
+                        throw new CommonException("任务修改失败,删除过期任务异常。");
+                    }
+                }else{
+                    if(jobEntity == null || jobEntity.getString("jobStatus") == null){
+                        tExam = this.addJob(tExam);
+                    }else{
+                        // 查的到任务未结束,修改任务
+                        jobEntity.put("id", tExam.getJobId());
+                        jobEntity.put("name", tExam.getId()+"-"+tExam.getExamName()+"-"+tExam.getPaperId());
+                        String cronExpression = DateTimeUtil.generateCronExpression(tExam.getStartTime());
+                        jobEntity.put("cronExpression", cronExpression);
+                        jobEntity.put("sortCode", 99);
+                        jobEntity.put("extJson", JSONObject.toJSONString(tExam));
+                        JSONObject editJobResult = devJobApi.editJob(jobEntity);
+                        if(editJobResult != null && editJobResult.getInteger("code") == 200){
+                            tExam.setJobId(jobEntity.getString("id"));
+                        }else{
+                            throw new CommonException("任务修改失败");
+                        }
+                    }
+                }
+            }else{
+                // 任务不存在,创建任务
+                tExam = this.addJob(tExam);
+            }
+        }
+        BeanUtil.copyProperties(tExamEditParam, tExam);
         this.updateById(tExam);
     }
 
@@ -151,4 +209,28 @@ public class TExamServiceImpl extends ServiceImpl<TExamMapper, TExam> implements
         return tExam;
     }
 
+
+    public TExam addJob(TExam tExam){
+        JSONObject jobParam = new JSONObject();
+        jobParam.put("name", tExam.getId()+"-"+tExam.getExamName()+"-"+tExam.getPaperId());
+        jobParam.put("category", "exam");
+        jobParam.put("actionClass", "vip.xiaonuo.exam.job.task.ExamJobTimerTaskRunner");
+        String cronExpression = DateTimeUtil.generateCronExpression(tExam.getStartTime());
+        jobParam.put("cronExpression", cronExpression);
+        jobParam.put("sortCode", 99);
+        jobParam.put("extJson", JSONObject.toJSONString(tExam));
+        JSONObject addJobResult = devJobApi.addJob(jobParam);
+        if(addJobResult != null && addJobResult.getInteger("code") != null && addJobResult.getIntValue("code") == 200){
+            tExam.setJobId(addJobResult.getString("data"));
+            this.save(tExam);
+            return tExam;
+        }else{
+            String msg = "";
+            if(addJobResult != null && addJobResult.getString("msg") != null){
+                msg = addJobResult.getString("msg");
+            }
+            log.error("任务添加失败,{}",msg);
+            throw new CommonException("任务添加失败");
+        }
+    }
 }

+ 19 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/utility/DateTimeUtil.java

@@ -153,4 +153,23 @@ public class DateTimeUtil {
         }
         return list;
     }
+
+    /**
+     * 根据考试结束时间生成cron表达式
+     * @param endTime 考试结束时间
+     * @return cron表达式
+     */
+    public static String generateCronExpression(Date endTime) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(endTime);
+
+        int minute = calendar.get(Calendar.MINUTE);
+        int hour = calendar.get(Calendar.HOUR_OF_DAY);
+        int day = calendar.get(Calendar.DAY_OF_MONTH);
+        int month = calendar.get(Calendar.MONTH) + 1; // Calendar.MONTH是从0开始的
+        int year = calendar.get(Calendar.YEAR);
+
+        // 生成类似 "0 minute hour day month ? year" 的cron表达式
+        return String.format("0 %d %d %d %d ? %d", minute, hour, day, month, year);
+    }
 }