Commit 3959aadae2bec0eecaf4e31fe0c018d5cfe869db

Authored by YunaiV
1 parent a4a13efa

1. 优化 JobHandlerInvoker 的实现,增加重试机制

2. 去除作业异常,自动暂时作业的机制。
Showing 30 changed files with 1019 additions and 1017 deletions
ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java deleted
1 -package com.ruoyi.common.constant;  
2 -  
3 -/**  
4 - * 任务调度通用常量  
5 - *  
6 - * @author ruoyi  
7 - */  
8 -public class ScheduleConstants {  
9 - public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";  
10 -  
11 - /**  
12 - * 执行目标key  
13 - */  
14 - public static final String TASK_PROPERTIES = "TASK_PROPERTIES";  
15 -  
16 - /**  
17 - * 默认  
18 - */  
19 - public static final String MISFIRE_DEFAULT = "0";  
20 -  
21 - /**  
22 - * 立即触发执行  
23 - */  
24 - public static final String MISFIRE_IGNORE_MISFIRES = "1";  
25 -  
26 - /**  
27 - * 触发一次执行  
28 - */  
29 - public static final String MISFIRE_FIRE_AND_PROCEED = "2";  
30 -  
31 - /**  
32 - * 不触发立即执行  
33 - */  
34 - public static final String MISFIRE_DO_NOTHING = "3";  
35 -  
36 - public enum Status {  
37 - /**  
38 - * 正常  
39 - */  
40 - NORMAL("0"),  
41 - /**  
42 - * 暂停  
43 - */  
44 - PAUSE("1");  
45 -  
46 - private String value;  
47 -  
48 - private Status(String value) {  
49 - this.value = value;  
50 - }  
51 -  
52 - public String getValue() {  
53 - return value;  
54 - }  
55 - }  
56 -}  
ruoyi-common/src/main/java/com/ruoyi/quartz/service/impl/SysJobLogServiceImpl.java deleted
1 -package com.ruoyi.quartz.service.impl;  
2 -  
3 -import java.util.List;  
4 -  
5 -import org.springframework.beans.factory.annotation.Autowired;  
6 -import org.springframework.stereotype.Service;  
7 -import com.ruoyi.quartz.domain.SysJobLog;  
8 -import com.ruoyi.quartz.mapper.SysJobLogMapper;  
9 -import com.ruoyi.quartz.service.ISysJobLogService;  
10 -  
11 -/**  
12 - * 定时任务调度日志信息 服务层  
13 - *  
14 - * @author ruoyi  
15 - */  
16 -@Service  
17 -public class SysJobLogServiceImpl implements ISysJobLogService {  
18 -  
19 - @Autowired  
20 - private SysJobLogMapper jobLogMapper;  
21 -  
22 - /**  
23 - * 获取quartz调度器日志的计划任务  
24 - *  
25 - * @param jobLog 调度日志信息  
26 - * @return 调度任务日志集合  
27 - */  
28 - @Override  
29 - public List<SysJobLog> selectJobLogList(SysJobLog jobLog) {  
30 - return jobLogMapper.selectJobLogList(jobLog);  
31 - }  
32 -  
33 - /**  
34 - * 通过调度任务日志ID查询调度信息  
35 - *  
36 - * @param jobLogId 调度任务日志ID  
37 - * @return 调度任务日志对象信息  
38 - */  
39 - @Override  
40 - public SysJobLog selectJobLogById(Long jobLogId) {  
41 - return jobLogMapper.selectJobLogById(jobLogId);  
42 - }  
43 -  
44 - /**  
45 - * 新增任务日志  
46 - *  
47 - * @param jobLog 调度日志信息  
48 - */  
49 - @Override  
50 - public void addJobLog(SysJobLog jobLog) {  
51 - jobLogMapper.insertJobLog(jobLog);  
52 - }  
53 -  
54 -}  
ruoyi-common/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java deleted
1 -package com.ruoyi.quartz.util;  
2 -  
3 -import java.util.Date;  
4 -  
5 -import org.quartz.Job;  
6 -import org.quartz.JobExecutionContext;  
7 -import org.quartz.JobExecutionException;  
8 -import org.slf4j.Logger;  
9 -import org.slf4j.LoggerFactory;  
10 -import com.ruoyi.common.constant.Constants;  
11 -import com.ruoyi.common.constant.ScheduleConstants;  
12 -import com.ruoyi.common.utils.ExceptionUtil;  
13 -import com.ruoyi.common.utils.StringUtils;  
14 -import com.ruoyi.common.utils.bean.BeanUtils;  
15 -import com.ruoyi.common.utils.spring.SpringUtils;  
16 -import com.ruoyi.quartz.domain.SysJob;  
17 -import com.ruoyi.quartz.domain.SysJobLog;  
18 -import com.ruoyi.quartz.service.ISysJobLogService;  
19 -  
20 -/**  
21 - * 抽象quartz调用  
22 - *  
23 - * @author ruoyi  
24 - */  
25 -public abstract class AbstractQuartzJob implements Job {  
26 - private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);  
27 -  
28 - /**  
29 - * 线程本地变量  
30 - */  
31 - private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();  
32 -  
33 - @Override  
34 - public void execute(JobExecutionContext context) throws JobExecutionException {  
35 - SysJob sysJob = new SysJob();  
36 - BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));  
37 - try {  
38 - before(context, sysJob);  
39 - if (sysJob != null) {  
40 - doExecute(context, sysJob);  
41 - }  
42 - after(context, sysJob, null);  
43 - } catch (Exception e) {  
44 - log.error("任务执行异常 - :", e);  
45 - after(context, sysJob, e);  
46 - }  
47 - }  
48 -  
49 - /**  
50 - * 执行前  
51 - *  
52 - * @param context 工作执行上下文对象  
53 - * @param sysJob 系统计划任务  
54 - */  
55 - protected void before(JobExecutionContext context, SysJob sysJob) {  
56 - threadLocal.set(new Date());  
57 - }  
58 -  
59 - /**  
60 - * 执行后  
61 - *  
62 - * @param context 工作执行上下文对象  
63 - * @param sysJob 系统计划任务  
64 - */  
65 - protected void after(JobExecutionContext context, SysJob sysJob, Exception e) {  
66 - Date startTime = threadLocal.get();  
67 - threadLocal.remove();  
68 -  
69 - final SysJobLog sysJobLog = new SysJobLog();  
70 - sysJobLog.setJobName(sysJob.getJobName());  
71 - sysJobLog.setJobGroup(sysJob.getJobGroup());  
72 - sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());  
73 - sysJobLog.setStartTime(startTime);  
74 - sysJobLog.setStopTime(new Date());  
75 - long runMs = sysJobLog.getStopTime().getTime() - sysJobLog.getStartTime().getTime();  
76 - sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒");  
77 - if (e != null) {  
78 - sysJobLog.setStatus(Constants.FAIL);  
79 - String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000);  
80 - sysJobLog.setExceptionInfo(errorMsg);  
81 - } else {  
82 - sysJobLog.setStatus(Constants.SUCCESS);  
83 - }  
84 -  
85 - // 写入数据库当中  
86 - SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog);  
87 - }  
88 -  
89 - /**  
90 - * 执行方法,由子类重载  
91 - *  
92 - * @param context 工作执行上下文对象  
93 - * @param sysJob 系统计划任务  
94 - * @throws Exception 执行过程中的异常  
95 - */  
96 - protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;  
97 -}  
ruoyi-common/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java deleted
1 -package com.ruoyi.quartz.util;  
2 -  
3 -import org.quartz.CronScheduleBuilder;  
4 -import org.quartz.CronTrigger;  
5 -import org.quartz.Job;  
6 -import org.quartz.JobBuilder;  
7 -import org.quartz.JobDetail;  
8 -import org.quartz.JobKey;  
9 -import org.quartz.Scheduler;  
10 -import org.quartz.SchedulerException;  
11 -import org.quartz.TriggerBuilder;  
12 -import org.quartz.TriggerKey;  
13 -import com.ruoyi.common.constant.ScheduleConstants;  
14 -import com.ruoyi.common.exception.job.TaskException;  
15 -import com.ruoyi.common.exception.job.TaskException.Code;  
16 -import com.ruoyi.quartz.domain.SysJob;  
17 -  
18 -/**  
19 - * 定时任务工具类  
20 - *  
21 - * @author ruoyi  
22 - */  
23 -public class ScheduleUtils {  
24 -  
25 - /**  
26 - * 设置定时任务策略  
27 - */  
28 - public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb)  
29 - throws TaskException {  
30 - switch (job.getMisfirePolicy()) {  
31 - case ScheduleConstants.MISFIRE_DEFAULT:  
32 - return cb;  
33 - case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:  
34 - return cb.withMisfireHandlingInstructionIgnoreMisfires();  
35 - case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:  
36 - return cb.withMisfireHandlingInstructionFireAndProceed();  
37 - case ScheduleConstants.MISFIRE_DO_NOTHING:  
38 - return cb.withMisfireHandlingInstructionDoNothing();  
39 - default:  
40 - throw new TaskException("The task misfire policy '" + job.getMisfirePolicy()  
41 - + "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR);  
42 - }  
43 - }  
44 -}  
ruoyi-ui/src/utils/constants.js
@@ -54,7 +54,6 @@ export const ToolCodegenTemplateTypeEnum = { @@ -54,7 +54,6 @@ export const ToolCodegenTemplateTypeEnum = {
54 */ 54 */
55 export const InfJobStatusEnum = { 55 export const InfJobStatusEnum = {
56 INIT: 0, // 初始化中 56 INIT: 0, // 初始化中
57 - NORMAL: 1, // 开启运行  
58 - EXCEPTION: 2, // 异常运行  
59 - STOP: 3, // 暂停运行 57 + NORMAL: 1, // 运行中
  58 + STOP: 2, // 暂停运行
60 } 59 }
ruoyi-ui/src/views/index.vue
1 -<template>  
2 - <div class="app-container home">  
3 - <el-row :gutter="20">  
4 - <el-col :sm="24" :lg="24">  
5 - <blockquote class="text-warning" style="font-size: 14px">  
6 - 领取阿里云通用云产品1888优惠券  
7 - <br />  
8 - <el-link  
9 - href="https://www.aliyun.com/minisite/goods?userCode=brki8iof"  
10 - type="primary"  
11 - target="_blank"  
12 - >https://www.aliyun.com/minisite/goods?userCode=brki8iof</el-link  
13 - >  
14 - <br />  
15 - 领取腾讯云通用云产品2860优惠券  
16 - <br />  
17 - <el-link  
18 - href="https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console"  
19 - type="primary"  
20 - target="_blank"  
21 - >https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console</el-link  
22 - >  
23 - <br />  
24 - 阿里云服务器折扣区  
25 - <el-link href="http://aly.ruoyi.vip" type="primary" target="_blank"  
26 - >>☛☛点我进入☚☚</el-link  
27 - >  
28 - &nbsp;&nbsp;&nbsp; 腾讯云服务器秒杀区  
29 - <el-link href="http://txy.ruoyi.vip" type="primary" target="_blank"  
30 - >>☛☛点我进入☚☚</el-link  
31 - ><br />  
32 - <h4 class="text-danger">  
33 - 云产品通用红包,可叠加官网常规优惠使用。(仅限新用户)  
34 - </h4>  
35 - </blockquote>  
36 -  
37 - <hr />  
38 - </el-col>  
39 - </el-row>  
40 - <el-row :gutter="20">  
41 - <el-col :sm="24" :lg="12" style="padding-left: 20px">  
42 - <h2>芋道后台管理框架</h2>  
43 - <p>  
44 - 一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适自己的。于是利用空闲休息时间开始自己写一套后台系统。如此有了芋道管理系统。,她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA等等,当然,您也可以对她进行深度定制,以做出更强系统。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。  
45 - </p>  
46 - <p>  
47 - <b>当前版本:</b> <span>v{{ version }}</span>  
48 - </p>  
49 - <p>  
50 - <el-tag type="danger">&yen;免费开源</el-tag>  
51 - </p>  
52 - <p>  
53 - <el-button  
54 - type="primary"  
55 - size="mini"  
56 - icon="el-icon-cloudy"  
57 - plain  
58 - @click="goTarget('https://gitee.com/y_project/RuoYi-Vue')"  
59 - >访问码云</el-button  
60 - >  
61 - <el-button  
62 - size="mini"  
63 - icon="el-icon-s-home"  
64 - plain  
65 - @click="goTarget('http://ruoyi.vip')"  
66 - >访问主页</el-button  
67 - >  
68 - </p>  
69 - </el-col>  
70 -  
71 - <el-col :sm="24" :lg="12" style="padding-left: 50px">  
72 - <el-row>  
73 - <el-col :span="12">  
74 - <h2>技术选型</h2>  
75 - </el-col>  
76 - </el-row>  
77 - <el-row>  
78 - <el-col :span="6">  
79 - <h4>后端技术</h4>  
80 - <ul>  
81 - <li>SpringBoot</li>  
82 - <li>Spring Security</li>  
83 - <li>JWT</li>  
84 - <li>MyBatis</li>  
85 - <li>Druid</li>  
86 - <li>Fastjson</li>  
87 - <li>...</li>  
88 - </ul>  
89 - </el-col>  
90 - <el-col :span="6">  
91 - <h4>前端技术</h4>  
92 - <ul>  
93 - <li>Vue</li>  
94 - <li>Vuex</li>  
95 - <li>Element-ui</li>  
96 - <li>Axios</li>  
97 - <li>Sass</li>  
98 - <li>Quill</li>  
99 - <li>...</li>  
100 - </ul>  
101 - </el-col>  
102 - </el-row>  
103 - </el-col>  
104 - </el-row>  
105 - <el-divider />  
106 - <el-row :gutter="20">  
107 - <el-col :xs="24" :sm="24" :md="12" :lg="8">  
108 - <el-card class="update-log">  
109 - <div slot="header" class="clearfix">  
110 - <span>联系信息</span>  
111 - </div>  
112 - <div class="body">  
113 - <p>  
114 - <i class="el-icon-s-promotion"></i> 官网:<el-link  
115 - href="http://www.ruoyi.vip"  
116 - target="_blank"  
117 - >http://www.ruoyi.vip</el-link  
118 - >  
119 - </p>  
120 - <p>  
121 - <i class="el-icon-user-solid"></i> QQ群:<s>满937441</s>  
122 - <s>满887144332</s> <s>满180251782</s>  
123 - <a href="https://jq.qq.com/?_wv=1027&k=4WWwqNxN" target="_blank"  
124 - > 104180207</a  
125 - >  
126 - </p>  
127 - <p>  
128 - <i class="el-icon-chat-dot-round"></i> 微信:<a  
129 - href="javascript:;"  
130 - >/ *芋道</a  
131 - >  
132 - </p>  
133 - <p>  
134 - <i class="el-icon-money"></i> 支付宝:<a  
135 - href="javascript:;"  
136 - class="支付宝信息"  
137 - >/ *芋道</a  
138 - >  
139 - </p>  
140 - </div>  
141 - </el-card>  
142 - </el-col>  
143 - <el-col :xs="24" :sm="24" :md="12" :lg="8">  
144 - <el-card class="update-log">  
145 - <div slot="header" class="clearfix">  
146 - <span>更新日志</span>  
147 - </div>  
148 - <el-collapse accordion>  
149 - <el-collapse-item title="v3.3.0 - 2020-12-14">  
150 - <ol>  
151 - <li>新增缓存监控功能</li>  
152 - <li>支持主题风格配置</li>  
153 - <li>修复多级菜单之间切换无法缓存的问题</li>  
154 - <li>多级菜单自动配置组件</li>  
155 - <li>代码生成预览支持高亮显示</li>  
156 - <li>支持Get请求映射Params参数</li>  
157 - <li>删除用户和角色解绑关联</li>  
158 - <li>去除用户手机邮箱部门必填验证</li>  
159 - <li>Excel支持注解align对齐方式</li>  
160 - <li>Excel支持导入Boolean型数据</li>  
161 - <li>优化头像样式,鼠标移入悬停遮罩</li>  
162 - <li>代码生成预览提供滚动机制</li>  
163 - <li>代码生成删除多余的数字float类型</li>  
164 - <li>修正转换字符串的目标字符集属性</li>  
165 - <li>回显数据字典防止空值报错</li>  
166 - <li>日志记录增加过滤多文件场景</li>  
167 - <li>修改缓存Set方法可能导致嵌套的问题</li>  
168 - <li>移除前端一些多余的依赖</li>  
169 - <li>防止安全扫描YUI出现的风险提示</li>  
170 - <li>修改node-sass为dart-sass</li>  
171 - <li>升级SpringBoot到最新版本2.1.18</li>  
172 - <li>升级poi到最新版本4.1.2</li>  
173 - <li>升级oshi到最新版本v5.3.6</li>  
174 - <li>升级bitwalker到最新版本1.21</li>  
175 - <li>升级axios到最新版本0.21.0</li>  
176 - <li>升级element-ui到最新版本2.14.1</li>  
177 - <li>升级vue到最新版本2.6.12</li>  
178 - <li>升级vuex到最新版本3.6.0</li>  
179 - <li>升级vue-cli到版本4.5.9</li>  
180 - <li>升级vue-router到最新版本3.4.9</li>  
181 - <li>升级vue-cli到最新版本4.4.6</li>  
182 - <li>升级vue-cropper到最新版本0.5.5</li>  
183 - <li>升级clipboard到最新版本2.0.6</li>  
184 - <li>升级core-js到最新版本3.8.1</li>  
185 - <li>升级echarts到最新版本4.9.0</li>  
186 - <li>升级file-saver到最新版本2.0.4</li>  
187 - <li>升级fuse.js到最新版本6.4.3</li>  
188 - <li>升级js-beautify到最新版本1.13.0</li>  
189 - <li>升级js-cookie到最新版本2.2.1</li>  
190 - <li>升级path-to-regexp到最新版本6.2.0</li>  
191 - <li>升级quill到最新版本1.3.7</li>  
192 - <li>升级screenfull到最新版本5.0.2</li>  
193 - <li>升级sortablejs到最新版本1.10.2</li>  
194 - <li>升级vuedraggable到最新版本2.24.3</li>  
195 - <li>升级chalk到最新版本4.1.0</li>  
196 - <li>升级eslint到最新版本7.15.0</li>  
197 - <li>升级eslint-plugin-vue到最新版本7.2.0</li>  
198 - <li>升级lint-staged到最新版本10.5.3</li>  
199 - <li>升级runjs到最新版本4.4.2</li>  
200 - <li>升级sass-loader到最新版本10.1.0</li>  
201 - <li>升级script-ext-html-webpack-plugin到最新版本2.1.5</li>  
202 - <li>升级svg-sprite-loader到最新版本5.1.1</li>  
203 - <li>升级vue-template-compiler到最新版本2.6.12</li>  
204 - <li>其他细节优化</li>  
205 - </ol>  
206 - </el-collapse-item>  
207 - <el-collapse-item title="v3.2.1 - 2020-11-18">  
208 - <ol>  
209 - <li>阻止任意文件下载漏洞</li>  
210 - <li>代码生成支持上传控件</li>  
211 - <li>新增图片上传组件</li>  
212 - <li>调整默认首页</li>  
213 - <li>升级druid到最新版本v1.2.2</li>  
214 - <li>mapperLocations配置支持分隔符</li>  
215 - <li>权限信息调整</li>  
216 - <li>调整sql默认时间</li>  
217 - <li>解决代码生成没有bit类型的问题</li>  
218 - <li>升级pagehelper到最新版1.3.0</li>  
219 - </ol>  
220 - </el-collapse-item>  
221 - <el-collapse-item title="v3.2.0 - 2020-10-10">  
222 - <ol>  
223 - <li>升级springboot版本到2.1.17 提升安全性</li>  
224 - <li>升级oshi到最新版本v5.2.5</li>  
225 - <li>升级druid到最新版本v1.2.1</li>  
226 - <li>升级jjwt到版本0.9.1</li>  
227 - <li>升级fastjson到最新版1.2.74</li>  
228 - <li>修改sass为node-sass,避免el-icon图标乱码</li>  
229 - <li>代码生成支持同步数据库</li>  
230 - <li>代码生成支持富文本控件</li>  
231 - <li>代码生成页面时不忽略remark属性</li>  
232 - <li>代码生成添加select必填选项</li>  
233 - <li>Excel导出类型NUMERIC支持精度浮点类型</li>  
234 - <li>Excel导出targetAttr优化获取值,防止get方法不规范</li>  
235 - <li>Excel注解支持自动统计数据总和</li>  
236 - <li>Excel注解支持设置BigDecimal精度&舍入规则</li>  
237 - <li>菜单&数据权限新增(展开/折叠 全选/全不选 父子联动)</li>  
238 - <li>允许用户分配到部门父节点</li>  
239 - <li>菜单新增是否缓存keep-alive</li>  
240 - <li>表格操作列间距调整</li>  
241 - <li>限制系统内置参数不允许删除</li>  
242 - <li>富文本组件优化,支持自定义高度&图片冲突问题</li>  
243 - <li>富文本工具栏样式对齐</li>  
244 - <li>导入excel整形值校验优化</li>  
245 - <li>修复页签关闭所有时固定标签路由不刷新问题</li>  
246 - <li>表单构建布局型组件新增按钮</li>  
247 - <li>左侧菜单文字过长显示省略号</li>  
248 - <li>修正根节点为子部门时,树状结构显示问题</li>  
249 - <li>修正调用目标字符串最大长度</li>  
250 - <li>修正菜单提示信息错误</li>  
251 - <li>修正定时任务执行一次权限标识</li>  
252 - <li>修正数据库字符串类型nvarchar</li>  
253 - <li>优化递归子节点</li>  
254 - <li>优化数据权限判断</li>  
255 - <li>其他细节优化</li>  
256 - </ol>  
257 - </el-collapse-item>  
258 -  
259 - <el-collapse-item title="v3.1.0 - 2020-08-13">  
260 - <ol>  
261 - <li>表格工具栏右侧添加刷新&显隐查询组件</li>  
262 - <li>后端支持CORS跨域请求</li>  
263 - <li>代码生成支持选择上级菜单</li>  
264 - <li>代码生成支持自定义路径</li>  
265 - <li>代码生成支持复选框</li>  
266 - <li>Excel导出导入支持dictType字典类型</li>  
267 - <li>Excel支持分割字符串组内容</li>  
268 - <li>验证码类型支持(数组计算、字符验证)</li>  
269 - <li>升级vue-cli版本到4.4.4</li>  
270 - <li>修改 node-sass 为 dart-sass</li>  
271 - <li>表单类型为Integer/Long设置整形默认值</li>  
272 - <li>代码生成器默认mapper路径与默认mapperScan路径不一致</li>  
273 - <li>优化防重复提交拦截器</li>  
274 - <li>优化上级菜单不能选择自己</li>  
275 - <li>修复角色的权限分配后,未实时生效问题</li>  
276 - <li>修复在线用户日志记录类型</li>  
277 - <li>修复富文本空格和缩进保存后不生效问题</li>  
278 - <li>修复在线用户判断逻辑</li>  
279 - <li>唯一限制条件只返回单条数据</li>  
280 - <li>添加获取当前的环境配置方法</li>  
281 - <li>超时登录后页面跳转到首页</li>  
282 - <li>全局异常状态汉化拦截处理</li>  
283 - <li>HTML过滤器改为将html转义</li>  
284 - <li>检查字符支持小数点&降级改成异常提醒</li>  
285 - <li>其他细节优化</li>  
286 - </ol>  
287 - </el-collapse-item>  
288 -  
289 - <el-collapse-item title="v3.0.0 - 2020-07-20">  
290 - <ol>  
291 - <li>单应用调整为多模块项目</li>  
292 - <li>升级element-ui版本到2.13.2</li>  
293 - <li>删除babel,提高编译速度。</li>  
294 - <li>新增菜单默认主类目</li>  
295 - <li>编码文件名修改为uuid方式</li>  
296 - <li>定时任务cron表达式验证</li>  
297 - <li>角色权限修改时已有权限未自动勾选异常修复</li>  
298 - <li>防止切换权限用户后登录出现404</li>  
299 - <li>Excel支持sort导出排序</li>  
300 - <li>创建用户不允许选择超级管理员角色</li>  
301 - <li>修复代码生成导入表结构出现异常页面不提醒问题</li>  
302 - <li>修复代码生成点击多次表修改数据不变化的问题</li>  
303 - <li>修复头像上传成功二次打开无法改变裁剪框大小和位置问题</li>  
304 - <li>修复布局为small者mini用户表单显示错位问题</li>  
305 - <li>修复热部署导致的强换异常问题</li>  
306 - <li>修改用户管理复选框宽度,防止部分浏览器出现省略号</li>  
307 - <li>IpUtils工具,清除Xss特殊字符,防止Xff注入攻击</li>  
308 - <li>生成domain 如果是浮点型 统一用BigDecimal</li>  
309 - <li>定时任务调整label-width,防止部署出现错位</li>  
310 - <li>调整表头固定列默认样式</li>  
311 - <li>代码生成模板调整,字段为String并且必填则加空串条件</li>  
312 - <li>代码生成字典Integer/Long使用parseInt</li>  
313 - <li>  
314 - 修复dict_sort不可update为0的问题&查询返回增加dict_sort升序排序  
315 - </li>  
316 - <li>修正岗位导出权限注解</li>  
317 - <li>禁止加密密文返回前端</li>  
318 - <li>修复代码生成页面中的查询条件创建时间未生效的问题</li>  
319 - <li>修复首页搜索菜单外链无法点击跳转问题</li>  
320 - <li>修复菜单管理选择图标,backspace删除时不过滤数据</li>  
321 - <li>用户管理部门分支节点不可检查&显示计数</li>  
322 - <li>数据范围过滤属性调整</li>  
323 - <li>其他细节优化</li>  
324 - </ol>  
325 - </el-collapse-item>  
326 -  
327 - <el-collapse-item title="v2.3.0 - 2020-06-01">  
328 - <ol>  
329 - <li>升级fastjson到最新版1.2.70 修复高危安全漏洞</li>  
330 - <li>dev启动默认打开浏览器</li>  
331 - <li>vue-cli使用默认source-map</li>  
332 - <li>slidebar eslint报错优化</li>  
333 - <li>当tags-view滚动关闭右键菜单</li>  
334 - <li>字典管理添加缓存读取</li>  
335 - <li>参数管理支持缓存操作</li>  
336 - <li>支持一级菜单(和主页同级)在main区域显示</li>  
337 - <li>限制外链地址必须以http(s)开头</li>  
338 - <li>tagview & sidebar 主题颜色与element ui(全局)同步</li>  
339 - <li>修改数据源类型优先级,先根据方法,再根据类</li>  
340 - <li>支持是否需要设置token属性,自定义返回码消息。</li>  
341 - <li>swagger请求前缀加入配置。</li>  
342 - <li>登录地点设置内容过长则隐藏显示</li>  
343 - <li>修复定时任务执行一次按钮后不提示消息问题</li>  
344 - <li>修改上级部门(选择项排除本身和下级)</li>  
345 - <li>通用http发送方法增加参数 contentType 编码类型</li>  
346 - <li>更换IP地址查询接口</li>  
347 - <li>修复页签变量undefined</li>  
348 - <li>添加校验部门包含未停用的子部门</li>  
349 - <li>修改定时任务详情下次执行时间日期显示错误</li>  
350 - <li>角色管理查询设置默认排序字段</li>  
351 - <li>swagger添加enable参数控制是否启用</li>  
352 - <li>只对json类型请求构建可重复读取inputStream的request</li>  
353 - <li>修改代码生成字典字段int类型没有自动选中问题</li>  
354 - <li>vuex用户名取值修正</li>  
355 - <li>表格树模板去掉多余的)</li>  
356 - <li>代码生成序号修正</li>  
357 - <li>全屏情况下不调整上外边距</li>  
358 - <li>代码生成Date字段添加默认格式</li>  
359 - <li>用户管理角色选择权限控制</li>  
360 - <li>修复路由懒加载报错问题</li>  
361 - <li>模板sql.vm添加菜单状态</li>  
362 - <li>设置用户名称不能修改</li>  
363 - <li>dialog添加append-to-body属性,防止ie遮罩</li>  
364 - <li>菜单区分状态和显示隐藏功能</li>  
365 - <li>升级fastjson到最新版1.2.68 修复安全加固</li>  
366 - <li>修复代码生成如果选择字典类型缺失逗号问题</li>  
367 - <li>登录请求params更换为data,防止暴露url</li>  
368 - <li>日志返回时间格式处理</li>  
369 - <li>添加handle控制允许拖动的元素</li>  
370 - <li>布局设置点击扩大范围</li>  
371 - <li>代码生成列属性排序查询</li>  
372 - <li>代码生成列支持拖动排序</li>  
373 - <li>修复时间格式不支持ios问题</li>  
374 - <li>表单构建添加父级class,防止冲突</li>  
375 - <li>定时任务并发属性修正</li>  
376 - <li>角色禁用&菜单隐藏不查询权限</li>  
377 - <li>其他细节优化</li>  
378 - </ol>  
379 - </el-collapse-item>  
380 -  
381 - <el-collapse-item title="v2.2.0 - 2020-03-18">  
382 - <ol>  
383 - <li>系统监控新增定时任务功能</li>  
384 - <li>添加一个打包Web工程bat</li>  
385 - <li>修复页签鼠标滚轮按下的时候,可以关闭不可关闭的tag</li>  
386 - <li>修复点击退出登录有时会无提示问题</li>  
387 - <li>修复防重复提交注解无效问题</li>  
388 - <li>修复通知公告批量删除异常问题</li>  
389 - <li>添加菜单时路由地址必填限制</li>  
390 - <li>代码生成字段描述可编辑</li>  
391 - <li>修复用户修改个人信息导致缓存不过期问题</li>  
392 - <li>个人信息创建时间获取正确属性值</li>  
393 - <li>操作日志详细显示正确类型</li>  
394 - <li>导入表单击行数据时选中对应的复选框</li>  
395 - <li>批量替换表前缀逻辑调整</li>  
396 - <li>固定重定向路径表达式</li>  
397 - <li>升级element-ui版本到2.13.0</li>  
398 - <li>操作日志排序调整</li>  
399 - <li>修复charts切换侧边栏或者缩放窗口显示bug</li>  
400 - <li>其他细节优化</li>  
401 - </ol>  
402 - </el-collapse-item>  
403 -  
404 - <el-collapse-item title="v2.1.0 - 2020-02-24">  
405 - <ol>  
406 - <li>新增表单构建</li>  
407 - <li>代码生成支持树表结构</li>  
408 - <li>新增用户导入</li>  
409 - <li>修复动态加载路由页面刷新问题</li>  
410 - <li>修复地址开关无效问题</li>  
411 - <li>汉化错误提示页面</li>  
412 - <li>代码生成已知问题修改</li>  
413 - <li>修复多数据源下配置关闭出现异常处理</li>  
414 - <li>添加HTML过滤器,用于去除XSS漏洞隐患</li>  
415 - <li>修复上传头像控制台出现异常</li>  
416 - <li>修改用户管理分页不正确的问题</li>  
417 - <li>修复验证码记录提示错误</li>  
418 - <li>修复request.js缺少Message引用</li>  
419 - <li>修复表格时间为空出现的异常</li>  
420 - <li>添加Jackson日期反序列化时区配置</li>  
421 - <li>调整根据用户权限加载菜单数据树形结构</li>  
422 - <li>调整成功登陆不恢复按钮,防止多次点击</li>  
423 - <li>修改用户个人资料同步缓存信息</li>  
424 - <li>修复页面同时出现el-upload和Editor不显示处理</li>  
425 - <li>修复在角色管理页修改菜单权限偶尔未选中问题</li>  
426 - <li>配置文件新增redis密码属性</li>  
427 - <li>设置mybatis全局的配置文件</li>  
428 - <li>其他细节优化</li>  
429 - </ol>  
430 - </el-collapse-item>  
431 -  
432 - <el-collapse-item title="v2.0.0 - 2019-12-02">  
433 - <ol>  
434 - <li>新增代码生成</li>  
435 - <li>新增@RepeatSubmit注解,防止重复提交</li>  
436 - <li>新增菜单主目录添加/删除操作</li>  
437 - <li>日志记录过滤特殊对象,防止转换异常</li>  
438 - <li>修改代码生成路由脚本错误</li>  
439 - <li>用户上传头像实时同步缓存,无需重新登录</li>  
440 - <li>调整切换页签后不重新加载数据</li>  
441 - <li>添加jsencrypt实现参数的前端加密</li>  
442 - <li>系统退出删除用户缓存记录</li>  
443 - <li>其他细节优化</li>  
444 - </ol>  
445 - </el-collapse-item>  
446 - <el-collapse-item title="v1.1.0 - 2019-11-11">  
447 - <ol>  
448 - <li>新增在线用户管理</li>  
449 - <li>新增按钮组功能实现(批量删除、导出、清空)</li>  
450 - <li>新增查询条件重置按钮</li>  
451 - <li>新增Swagger全局Token配置</li>  
452 - <li>新增后端参数校验</li>  
453 - <li>修复字典管理页面的日期查询异常</li>  
454 - <li>修改时间函数命名防止冲突</li>  
455 - <li>去除菜单上级校验,默认为顶级</li>  
456 - <li>修复用户密码无法修改问题</li>  
457 - <li>修复菜单类型为按钮时不显示权限标识</li>  
458 - <li>其他细节优化</li>  
459 - </ol>  
460 - </el-collapse-item>  
461 - <el-collapse-item title="v1.0.0 - 2019-10-08">  
462 - <ol>  
463 - <li>芋道前后端分离系统正式发布</li>  
464 - </ol>  
465 - </el-collapse-item>  
466 - </el-collapse>  
467 - </el-card>  
468 - </el-col>  
469 - <el-col :xs="24" :sm="24" :md="12" :lg="8">  
470 - <el-card class="update-log">  
471 - <div slot="header" class="clearfix">  
472 - <span>捐赠支持</span>  
473 - </div>  
474 - <div class="body">  
475 - <img  
476 - src="https://oscimg.oschina.net/oscnet/up-d6695f82666e5018f715c41cb7ee60d3b73.png"  
477 - alt="donate"  
478 - width="100%"  
479 - />  
480 - <span style="display: inline-block; height: 30px; line-height: 30px"  
481 - >你可以请作者喝杯咖啡表示鼓励</span  
482 - >  
483 - </div>  
484 - </el-card>  
485 - </el-col>  
486 - </el-row>  
487 - </div>  
488 -</template>  
489 -  
490 -<script>  
491 -export default {  
492 - name: "index",  
493 - data() {  
494 - return {  
495 - // 版本号  
496 - version: "3.3.0",  
497 - };  
498 - },  
499 - methods: {  
500 - goTarget(href) {  
501 - window.open(href, "_blank");  
502 - },  
503 - },  
504 -};  
505 -</script>  
506 -  
507 -<style scoped lang="scss">  
508 -.home {  
509 - blockquote {  
510 - padding: 10px 20px;  
511 - margin: 0 0 20px;  
512 - font-size: 17.5px;  
513 - border-left: 5px solid #eee;  
514 - }  
515 - hr {  
516 - margin-top: 20px;  
517 - margin-bottom: 20px;  
518 - border: 0;  
519 - border-top: 1px solid #eee;  
520 - }  
521 - .col-item {  
522 - margin-bottom: 20px;  
523 - }  
524 -  
525 - ul {  
526 - padding: 0;  
527 - margin: 0;  
528 - }  
529 -  
530 - font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;  
531 - font-size: 13px;  
532 - color: #676a6c;  
533 - overflow-x: hidden;  
534 -  
535 - ul {  
536 - list-style-type: none;  
537 - }  
538 -  
539 - h4 {  
540 - margin-top: 0px;  
541 - }  
542 -  
543 - h2 {  
544 - margin-top: 10px;  
545 - font-size: 26px;  
546 - font-weight: 100;  
547 - }  
548 -  
549 - p {  
550 - margin-top: 10px;  
551 -  
552 - b {  
553 - font-weight: 700;  
554 - }  
555 - }  
556 -  
557 - .update-log {  
558 - ol {  
559 - display: block;  
560 - list-style-type: decimal;  
561 - margin-block-start: 1em;  
562 - margin-block-end: 1em;  
563 - margin-inline-start: 0;  
564 - margin-inline-end: 0;  
565 - padding-inline-start: 40px;  
566 - }  
567 - }  
568 -}  
569 -</style>  
570 - 1 +<template>
  2 + <div class="dashboard-editor-container">
  3 +
  4 + <panel-group @handleSetLineChartData="handleSetLineChartData" />
  5 +
  6 + <el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
  7 + <line-chart :chart-data="lineChartData" />
  8 + </el-row>
  9 +
  10 + <el-row :gutter="32">
  11 + <el-col :xs="24" :sm="24" :lg="8">
  12 + <div class="chart-wrapper">
  13 + <raddar-chart />
  14 + </div>
  15 + </el-col>
  16 + <el-col :xs="24" :sm="24" :lg="8">
  17 + <div class="chart-wrapper">
  18 + <pie-chart />
  19 + </div>
  20 + </el-col>
  21 + <el-col :xs="24" :sm="24" :lg="8">
  22 + <div class="chart-wrapper">
  23 + <bar-chart />
  24 + </div>
  25 + </el-col>
  26 + </el-row>
  27 +
  28 +
  29 + </div>
  30 +</template>
  31 +
  32 +<script>
  33 +import PanelGroup from './dashboard/PanelGroup'
  34 +import LineChart from './dashboard/LineChart'
  35 +import RaddarChart from './dashboard/RaddarChart'
  36 +import PieChart from './dashboard/PieChart'
  37 +import BarChart from './dashboard/BarChart'
  38 +
  39 +const lineChartData = {
  40 + newVisitis: {
  41 + expectedData: [100, 120, 161, 134, 105, 160, 165],
  42 + actualData: [120, 82, 91, 154, 162, 140, 145]
  43 + },
  44 + messages: {
  45 + expectedData: [200, 192, 120, 144, 160, 130, 140],
  46 + actualData: [180, 160, 151, 106, 145, 150, 130]
  47 + },
  48 + purchases: {
  49 + expectedData: [80, 100, 121, 104, 105, 90, 100],
  50 + actualData: [120, 90, 100, 138, 142, 130, 130]
  51 + },
  52 + shoppings: {
  53 + expectedData: [130, 140, 141, 142, 145, 150, 160],
  54 + actualData: [120, 82, 91, 154, 162, 140, 130]
  55 + }
  56 +}
  57 +
  58 +export default {
  59 + name: 'Index',
  60 + components: {
  61 + PanelGroup,
  62 + LineChart,
  63 + RaddarChart,
  64 + PieChart,
  65 + BarChart
  66 + },
  67 + data() {
  68 + return {
  69 + lineChartData: lineChartData.newVisitis
  70 + }
  71 + },
  72 + methods: {
  73 + handleSetLineChartData(type) {
  74 + this.lineChartData = lineChartData[type]
  75 + }
  76 + }
  77 +}
  78 +</script>
  79 +
  80 +<style lang="scss" scoped>
  81 +.dashboard-editor-container {
  82 + padding: 32px;
  83 + background-color: rgb(240, 242, 245);
  84 + position: relative;
  85 +
  86 + .chart-wrapper {
  87 + background: #fff;
  88 + padding: 16px 16px 0;
  89 + margin-bottom: 32px;
  90 + }
  91 +}
  92 +
  93 +@media (max-width:1024px) {
  94 + .chart-wrapper {
  95 + padding: 8px;
  96 + }
  97 +}
  98 +</style>
ruoyi-ui/src/views/index_old.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container home">
  3 + <el-row :gutter="20">
  4 + <el-col :sm="24" :lg="24">
  5 + <blockquote class="text-warning" style="font-size: 14px">
  6 + 领取阿里云通用云产品1888优惠券
  7 + <br />
  8 + <el-link
  9 + href="https://www.aliyun.com/minisite/goods?userCode=brki8iof"
  10 + type="primary"
  11 + target="_blank"
  12 + >https://www.aliyun.com/minisite/goods?userCode=brki8iof</el-link
  13 + >
  14 + <br />
  15 + 领取腾讯云通用云产品2860优惠券
  16 + <br />
  17 + <el-link
  18 + href="https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console"
  19 + type="primary"
  20 + target="_blank"
  21 + >https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console</el-link
  22 + >
  23 + <br />
  24 + 阿里云服务器折扣区
  25 + <el-link href="http://aly.ruoyi.vip" type="primary" target="_blank"
  26 + >>☛☛点我进入☚☚</el-link
  27 + >
  28 + &nbsp;&nbsp;&nbsp; 腾讯云服务器秒杀区
  29 + <el-link href="http://txy.ruoyi.vip" type="primary" target="_blank"
  30 + >>☛☛点我进入☚☚</el-link
  31 + ><br />
  32 + <h4 class="text-danger">
  33 + 云产品通用红包,可叠加官网常规优惠使用。(仅限新用户)
  34 + </h4>
  35 + </blockquote>
  36 +
  37 + <hr />
  38 + </el-col>
  39 + </el-row>
  40 + <el-row :gutter="20">
  41 + <el-col :sm="24" :lg="12" style="padding-left: 20px">
  42 + <h2>芋道后台管理框架</h2>
  43 + <p>
  44 + 一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适自己的。于是利用空闲休息时间开始自己写一套后台系统。如此有了芋道管理系统。,她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA等等,当然,您也可以对她进行深度定制,以做出更强系统。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。
  45 + </p>
  46 + <p>
  47 + <b>当前版本:</b> <span>v{{ version }}</span>
  48 + </p>
  49 + <p>
  50 + <el-tag type="danger">&yen;免费开源</el-tag>
  51 + </p>
  52 + <p>
  53 + <el-button
  54 + type="primary"
  55 + size="mini"
  56 + icon="el-icon-cloudy"
  57 + plain
  58 + @click="goTarget('https://gitee.com/y_project/RuoYi-Vue')"
  59 + >访问码云</el-button
  60 + >
  61 + <el-button
  62 + size="mini"
  63 + icon="el-icon-s-home"
  64 + plain
  65 + @click="goTarget('http://ruoyi.vip')"
  66 + >访问主页</el-button
  67 + >
  68 + </p>
  69 + </el-col>
  70 +
  71 + <el-col :sm="24" :lg="12" style="padding-left: 50px">
  72 + <el-row>
  73 + <el-col :span="12">
  74 + <h2>技术选型</h2>
  75 + </el-col>
  76 + </el-row>
  77 + <el-row>
  78 + <el-col :span="6">
  79 + <h4>后端技术</h4>
  80 + <ul>
  81 + <li>SpringBoot</li>
  82 + <li>Spring Security</li>
  83 + <li>JWT</li>
  84 + <li>MyBatis</li>
  85 + <li>Druid</li>
  86 + <li>Fastjson</li>
  87 + <li>...</li>
  88 + </ul>
  89 + </el-col>
  90 + <el-col :span="6">
  91 + <h4>前端技术</h4>
  92 + <ul>
  93 + <li>Vue</li>
  94 + <li>Vuex</li>
  95 + <li>Element-ui</li>
  96 + <li>Axios</li>
  97 + <li>Sass</li>
  98 + <li>Quill</li>
  99 + <li>...</li>
  100 + </ul>
  101 + </el-col>
  102 + </el-row>
  103 + </el-col>
  104 + </el-row>
  105 + <el-divider />
  106 + <el-row :gutter="20">
  107 + <el-col :xs="24" :sm="24" :md="12" :lg="8">
  108 + <el-card class="update-log">
  109 + <div slot="header" class="clearfix">
  110 + <span>联系信息</span>
  111 + </div>
  112 + <div class="body">
  113 + <p>
  114 + <i class="el-icon-s-promotion"></i> 官网:<el-link
  115 + href="http://www.ruoyi.vip"
  116 + target="_blank"
  117 + >http://www.ruoyi.vip</el-link
  118 + >
  119 + </p>
  120 + <p>
  121 + <i class="el-icon-user-solid"></i> QQ群:<s>满937441</s>
  122 + <s>满887144332</s> <s>满180251782</s>
  123 + <a href="https://jq.qq.com/?_wv=1027&k=4WWwqNxN" target="_blank"
  124 + > 104180207</a
  125 + >
  126 + </p>
  127 + <p>
  128 + <i class="el-icon-chat-dot-round"></i> 微信:<a
  129 + href="javascript:;"
  130 + >/ *芋道</a
  131 + >
  132 + </p>
  133 + <p>
  134 + <i class="el-icon-money"></i> 支付宝:<a
  135 + href="javascript:;"
  136 + class="支付宝信息"
  137 + >/ *芋道</a
  138 + >
  139 + </p>
  140 + </div>
  141 + </el-card>
  142 + </el-col>
  143 + <el-col :xs="24" :sm="24" :md="12" :lg="8">
  144 + <el-card class="update-log">
  145 + <div slot="header" class="clearfix">
  146 + <span>更新日志</span>
  147 + </div>
  148 + <el-collapse accordion>
  149 + <el-collapse-item title="v3.3.0 - 2020-12-14">
  150 + <ol>
  151 + <li>新增缓存监控功能</li>
  152 + <li>支持主题风格配置</li>
  153 + <li>修复多级菜单之间切换无法缓存的问题</li>
  154 + <li>多级菜单自动配置组件</li>
  155 + <li>代码生成预览支持高亮显示</li>
  156 + <li>支持Get请求映射Params参数</li>
  157 + <li>删除用户和角色解绑关联</li>
  158 + <li>去除用户手机邮箱部门必填验证</li>
  159 + <li>Excel支持注解align对齐方式</li>
  160 + <li>Excel支持导入Boolean型数据</li>
  161 + <li>优化头像样式,鼠标移入悬停遮罩</li>
  162 + <li>代码生成预览提供滚动机制</li>
  163 + <li>代码生成删除多余的数字float类型</li>
  164 + <li>修正转换字符串的目标字符集属性</li>
  165 + <li>回显数据字典防止空值报错</li>
  166 + <li>日志记录增加过滤多文件场景</li>
  167 + <li>修改缓存Set方法可能导致嵌套的问题</li>
  168 + <li>移除前端一些多余的依赖</li>
  169 + <li>防止安全扫描YUI出现的风险提示</li>
  170 + <li>修改node-sass为dart-sass</li>
  171 + <li>升级SpringBoot到最新版本2.1.18</li>
  172 + <li>升级poi到最新版本4.1.2</li>
  173 + <li>升级oshi到最新版本v5.3.6</li>
  174 + <li>升级bitwalker到最新版本1.21</li>
  175 + <li>升级axios到最新版本0.21.0</li>
  176 + <li>升级element-ui到最新版本2.14.1</li>
  177 + <li>升级vue到最新版本2.6.12</li>
  178 + <li>升级vuex到最新版本3.6.0</li>
  179 + <li>升级vue-cli到版本4.5.9</li>
  180 + <li>升级vue-router到最新版本3.4.9</li>
  181 + <li>升级vue-cli到最新版本4.4.6</li>
  182 + <li>升级vue-cropper到最新版本0.5.5</li>
  183 + <li>升级clipboard到最新版本2.0.6</li>
  184 + <li>升级core-js到最新版本3.8.1</li>
  185 + <li>升级echarts到最新版本4.9.0</li>
  186 + <li>升级file-saver到最新版本2.0.4</li>
  187 + <li>升级fuse.js到最新版本6.4.3</li>
  188 + <li>升级js-beautify到最新版本1.13.0</li>
  189 + <li>升级js-cookie到最新版本2.2.1</li>
  190 + <li>升级path-to-regexp到最新版本6.2.0</li>
  191 + <li>升级quill到最新版本1.3.7</li>
  192 + <li>升级screenfull到最新版本5.0.2</li>
  193 + <li>升级sortablejs到最新版本1.10.2</li>
  194 + <li>升级vuedraggable到最新版本2.24.3</li>
  195 + <li>升级chalk到最新版本4.1.0</li>
  196 + <li>升级eslint到最新版本7.15.0</li>
  197 + <li>升级eslint-plugin-vue到最新版本7.2.0</li>
  198 + <li>升级lint-staged到最新版本10.5.3</li>
  199 + <li>升级runjs到最新版本4.4.2</li>
  200 + <li>升级sass-loader到最新版本10.1.0</li>
  201 + <li>升级script-ext-html-webpack-plugin到最新版本2.1.5</li>
  202 + <li>升级svg-sprite-loader到最新版本5.1.1</li>
  203 + <li>升级vue-template-compiler到最新版本2.6.12</li>
  204 + <li>其他细节优化</li>
  205 + </ol>
  206 + </el-collapse-item>
  207 + <el-collapse-item title="v3.2.1 - 2020-11-18">
  208 + <ol>
  209 + <li>阻止任意文件下载漏洞</li>
  210 + <li>代码生成支持上传控件</li>
  211 + <li>新增图片上传组件</li>
  212 + <li>调整默认首页</li>
  213 + <li>升级druid到最新版本v1.2.2</li>
  214 + <li>mapperLocations配置支持分隔符</li>
  215 + <li>权限信息调整</li>
  216 + <li>调整sql默认时间</li>
  217 + <li>解决代码生成没有bit类型的问题</li>
  218 + <li>升级pagehelper到最新版1.3.0</li>
  219 + </ol>
  220 + </el-collapse-item>
  221 + <el-collapse-item title="v3.2.0 - 2020-10-10">
  222 + <ol>
  223 + <li>升级springboot版本到2.1.17 提升安全性</li>
  224 + <li>升级oshi到最新版本v5.2.5</li>
  225 + <li>升级druid到最新版本v1.2.1</li>
  226 + <li>升级jjwt到版本0.9.1</li>
  227 + <li>升级fastjson到最新版1.2.74</li>
  228 + <li>修改sass为node-sass,避免el-icon图标乱码</li>
  229 + <li>代码生成支持同步数据库</li>
  230 + <li>代码生成支持富文本控件</li>
  231 + <li>代码生成页面时不忽略remark属性</li>
  232 + <li>代码生成添加select必填选项</li>
  233 + <li>Excel导出类型NUMERIC支持精度浮点类型</li>
  234 + <li>Excel导出targetAttr优化获取值,防止get方法不规范</li>
  235 + <li>Excel注解支持自动统计数据总和</li>
  236 + <li>Excel注解支持设置BigDecimal精度&舍入规则</li>
  237 + <li>菜单&数据权限新增(展开/折叠 全选/全不选 父子联动)</li>
  238 + <li>允许用户分配到部门父节点</li>
  239 + <li>菜单新增是否缓存keep-alive</li>
  240 + <li>表格操作列间距调整</li>
  241 + <li>限制系统内置参数不允许删除</li>
  242 + <li>富文本组件优化,支持自定义高度&图片冲突问题</li>
  243 + <li>富文本工具栏样式对齐</li>
  244 + <li>导入excel整形值校验优化</li>
  245 + <li>修复页签关闭所有时固定标签路由不刷新问题</li>
  246 + <li>表单构建布局型组件新增按钮</li>
  247 + <li>左侧菜单文字过长显示省略号</li>
  248 + <li>修正根节点为子部门时,树状结构显示问题</li>
  249 + <li>修正调用目标字符串最大长度</li>
  250 + <li>修正菜单提示信息错误</li>
  251 + <li>修正定时任务执行一次权限标识</li>
  252 + <li>修正数据库字符串类型nvarchar</li>
  253 + <li>优化递归子节点</li>
  254 + <li>优化数据权限判断</li>
  255 + <li>其他细节优化</li>
  256 + </ol>
  257 + </el-collapse-item>
  258 +
  259 + <el-collapse-item title="v3.1.0 - 2020-08-13">
  260 + <ol>
  261 + <li>表格工具栏右侧添加刷新&显隐查询组件</li>
  262 + <li>后端支持CORS跨域请求</li>
  263 + <li>代码生成支持选择上级菜单</li>
  264 + <li>代码生成支持自定义路径</li>
  265 + <li>代码生成支持复选框</li>
  266 + <li>Excel导出导入支持dictType字典类型</li>
  267 + <li>Excel支持分割字符串组内容</li>
  268 + <li>验证码类型支持(数组计算、字符验证)</li>
  269 + <li>升级vue-cli版本到4.4.4</li>
  270 + <li>修改 node-sass 为 dart-sass</li>
  271 + <li>表单类型为Integer/Long设置整形默认值</li>
  272 + <li>代码生成器默认mapper路径与默认mapperScan路径不一致</li>
  273 + <li>优化防重复提交拦截器</li>
  274 + <li>优化上级菜单不能选择自己</li>
  275 + <li>修复角色的权限分配后,未实时生效问题</li>
  276 + <li>修复在线用户日志记录类型</li>
  277 + <li>修复富文本空格和缩进保存后不生效问题</li>
  278 + <li>修复在线用户判断逻辑</li>
  279 + <li>唯一限制条件只返回单条数据</li>
  280 + <li>添加获取当前的环境配置方法</li>
  281 + <li>超时登录后页面跳转到首页</li>
  282 + <li>全局异常状态汉化拦截处理</li>
  283 + <li>HTML过滤器改为将html转义</li>
  284 + <li>检查字符支持小数点&降级改成异常提醒</li>
  285 + <li>其他细节优化</li>
  286 + </ol>
  287 + </el-collapse-item>
  288 +
  289 + <el-collapse-item title="v3.0.0 - 2020-07-20">
  290 + <ol>
  291 + <li>单应用调整为多模块项目</li>
  292 + <li>升级element-ui版本到2.13.2</li>
  293 + <li>删除babel,提高编译速度。</li>
  294 + <li>新增菜单默认主类目</li>
  295 + <li>编码文件名修改为uuid方式</li>
  296 + <li>定时任务cron表达式验证</li>
  297 + <li>角色权限修改时已有权限未自动勾选异常修复</li>
  298 + <li>防止切换权限用户后登录出现404</li>
  299 + <li>Excel支持sort导出排序</li>
  300 + <li>创建用户不允许选择超级管理员角色</li>
  301 + <li>修复代码生成导入表结构出现异常页面不提醒问题</li>
  302 + <li>修复代码生成点击多次表修改数据不变化的问题</li>
  303 + <li>修复头像上传成功二次打开无法改变裁剪框大小和位置问题</li>
  304 + <li>修复布局为small者mini用户表单显示错位问题</li>
  305 + <li>修复热部署导致的强换异常问题</li>
  306 + <li>修改用户管理复选框宽度,防止部分浏览器出现省略号</li>
  307 + <li>IpUtils工具,清除Xss特殊字符,防止Xff注入攻击</li>
  308 + <li>生成domain 如果是浮点型 统一用BigDecimal</li>
  309 + <li>定时任务调整label-width,防止部署出现错位</li>
  310 + <li>调整表头固定列默认样式</li>
  311 + <li>代码生成模板调整,字段为String并且必填则加空串条件</li>
  312 + <li>代码生成字典Integer/Long使用parseInt</li>
  313 + <li>
  314 + 修复dict_sort不可update为0的问题&查询返回增加dict_sort升序排序
  315 + </li>
  316 + <li>修正岗位导出权限注解</li>
  317 + <li>禁止加密密文返回前端</li>
  318 + <li>修复代码生成页面中的查询条件创建时间未生效的问题</li>
  319 + <li>修复首页搜索菜单外链无法点击跳转问题</li>
  320 + <li>修复菜单管理选择图标,backspace删除时不过滤数据</li>
  321 + <li>用户管理部门分支节点不可检查&显示计数</li>
  322 + <li>数据范围过滤属性调整</li>
  323 + <li>其他细节优化</li>
  324 + </ol>
  325 + </el-collapse-item>
  326 +
  327 + <el-collapse-item title="v2.3.0 - 2020-06-01">
  328 + <ol>
  329 + <li>升级fastjson到最新版1.2.70 修复高危安全漏洞</li>
  330 + <li>dev启动默认打开浏览器</li>
  331 + <li>vue-cli使用默认source-map</li>
  332 + <li>slidebar eslint报错优化</li>
  333 + <li>当tags-view滚动关闭右键菜单</li>
  334 + <li>字典管理添加缓存读取</li>
  335 + <li>参数管理支持缓存操作</li>
  336 + <li>支持一级菜单(和主页同级)在main区域显示</li>
  337 + <li>限制外链地址必须以http(s)开头</li>
  338 + <li>tagview & sidebar 主题颜色与element ui(全局)同步</li>
  339 + <li>修改数据源类型优先级,先根据方法,再根据类</li>
  340 + <li>支持是否需要设置token属性,自定义返回码消息。</li>
  341 + <li>swagger请求前缀加入配置。</li>
  342 + <li>登录地点设置内容过长则隐藏显示</li>
  343 + <li>修复定时任务执行一次按钮后不提示消息问题</li>
  344 + <li>修改上级部门(选择项排除本身和下级)</li>
  345 + <li>通用http发送方法增加参数 contentType 编码类型</li>
  346 + <li>更换IP地址查询接口</li>
  347 + <li>修复页签变量undefined</li>
  348 + <li>添加校验部门包含未停用的子部门</li>
  349 + <li>修改定时任务详情下次执行时间日期显示错误</li>
  350 + <li>角色管理查询设置默认排序字段</li>
  351 + <li>swagger添加enable参数控制是否启用</li>
  352 + <li>只对json类型请求构建可重复读取inputStream的request</li>
  353 + <li>修改代码生成字典字段int类型没有自动选中问题</li>
  354 + <li>vuex用户名取值修正</li>
  355 + <li>表格树模板去掉多余的)</li>
  356 + <li>代码生成序号修正</li>
  357 + <li>全屏情况下不调整上外边距</li>
  358 + <li>代码生成Date字段添加默认格式</li>
  359 + <li>用户管理角色选择权限控制</li>
  360 + <li>修复路由懒加载报错问题</li>
  361 + <li>模板sql.vm添加菜单状态</li>
  362 + <li>设置用户名称不能修改</li>
  363 + <li>dialog添加append-to-body属性,防止ie遮罩</li>
  364 + <li>菜单区分状态和显示隐藏功能</li>
  365 + <li>升级fastjson到最新版1.2.68 修复安全加固</li>
  366 + <li>修复代码生成如果选择字典类型缺失逗号问题</li>
  367 + <li>登录请求params更换为data,防止暴露url</li>
  368 + <li>日志返回时间格式处理</li>
  369 + <li>添加handle控制允许拖动的元素</li>
  370 + <li>布局设置点击扩大范围</li>
  371 + <li>代码生成列属性排序查询</li>
  372 + <li>代码生成列支持拖动排序</li>
  373 + <li>修复时间格式不支持ios问题</li>
  374 + <li>表单构建添加父级class,防止冲突</li>
  375 + <li>定时任务并发属性修正</li>
  376 + <li>角色禁用&菜单隐藏不查询权限</li>
  377 + <li>其他细节优化</li>
  378 + </ol>
  379 + </el-collapse-item>
  380 +
  381 + <el-collapse-item title="v2.2.0 - 2020-03-18">
  382 + <ol>
  383 + <li>系统监控新增定时任务功能</li>
  384 + <li>添加一个打包Web工程bat</li>
  385 + <li>修复页签鼠标滚轮按下的时候,可以关闭不可关闭的tag</li>
  386 + <li>修复点击退出登录有时会无提示问题</li>
  387 + <li>修复防重复提交注解无效问题</li>
  388 + <li>修复通知公告批量删除异常问题</li>
  389 + <li>添加菜单时路由地址必填限制</li>
  390 + <li>代码生成字段描述可编辑</li>
  391 + <li>修复用户修改个人信息导致缓存不过期问题</li>
  392 + <li>个人信息创建时间获取正确属性值</li>
  393 + <li>操作日志详细显示正确类型</li>
  394 + <li>导入表单击行数据时选中对应的复选框</li>
  395 + <li>批量替换表前缀逻辑调整</li>
  396 + <li>固定重定向路径表达式</li>
  397 + <li>升级element-ui版本到2.13.0</li>
  398 + <li>操作日志排序调整</li>
  399 + <li>修复charts切换侧边栏或者缩放窗口显示bug</li>
  400 + <li>其他细节优化</li>
  401 + </ol>
  402 + </el-collapse-item>
  403 +
  404 + <el-collapse-item title="v2.1.0 - 2020-02-24">
  405 + <ol>
  406 + <li>新增表单构建</li>
  407 + <li>代码生成支持树表结构</li>
  408 + <li>新增用户导入</li>
  409 + <li>修复动态加载路由页面刷新问题</li>
  410 + <li>修复地址开关无效问题</li>
  411 + <li>汉化错误提示页面</li>
  412 + <li>代码生成已知问题修改</li>
  413 + <li>修复多数据源下配置关闭出现异常处理</li>
  414 + <li>添加HTML过滤器,用于去除XSS漏洞隐患</li>
  415 + <li>修复上传头像控制台出现异常</li>
  416 + <li>修改用户管理分页不正确的问题</li>
  417 + <li>修复验证码记录提示错误</li>
  418 + <li>修复request.js缺少Message引用</li>
  419 + <li>修复表格时间为空出现的异常</li>
  420 + <li>添加Jackson日期反序列化时区配置</li>
  421 + <li>调整根据用户权限加载菜单数据树形结构</li>
  422 + <li>调整成功登陆不恢复按钮,防止多次点击</li>
  423 + <li>修改用户个人资料同步缓存信息</li>
  424 + <li>修复页面同时出现el-upload和Editor不显示处理</li>
  425 + <li>修复在角色管理页修改菜单权限偶尔未选中问题</li>
  426 + <li>配置文件新增redis密码属性</li>
  427 + <li>设置mybatis全局的配置文件</li>
  428 + <li>其他细节优化</li>
  429 + </ol>
  430 + </el-collapse-item>
  431 +
  432 + <el-collapse-item title="v2.0.0 - 2019-12-02">
  433 + <ol>
  434 + <li>新增代码生成</li>
  435 + <li>新增@RepeatSubmit注解,防止重复提交</li>
  436 + <li>新增菜单主目录添加/删除操作</li>
  437 + <li>日志记录过滤特殊对象,防止转换异常</li>
  438 + <li>修改代码生成路由脚本错误</li>
  439 + <li>用户上传头像实时同步缓存,无需重新登录</li>
  440 + <li>调整切换页签后不重新加载数据</li>
  441 + <li>添加jsencrypt实现参数的前端加密</li>
  442 + <li>系统退出删除用户缓存记录</li>
  443 + <li>其他细节优化</li>
  444 + </ol>
  445 + </el-collapse-item>
  446 + <el-collapse-item title="v1.1.0 - 2019-11-11">
  447 + <ol>
  448 + <li>新增在线用户管理</li>
  449 + <li>新增按钮组功能实现(批量删除、导出、清空)</li>
  450 + <li>新增查询条件重置按钮</li>
  451 + <li>新增Swagger全局Token配置</li>
  452 + <li>新增后端参数校验</li>
  453 + <li>修复字典管理页面的日期查询异常</li>
  454 + <li>修改时间函数命名防止冲突</li>
  455 + <li>去除菜单上级校验,默认为顶级</li>
  456 + <li>修复用户密码无法修改问题</li>
  457 + <li>修复菜单类型为按钮时不显示权限标识</li>
  458 + <li>其他细节优化</li>
  459 + </ol>
  460 + </el-collapse-item>
  461 + <el-collapse-item title="v1.0.0 - 2019-10-08">
  462 + <ol>
  463 + <li>芋道前后端分离系统正式发布</li>
  464 + </ol>
  465 + </el-collapse-item>
  466 + </el-collapse>
  467 + </el-card>
  468 + </el-col>
  469 + <el-col :xs="24" :sm="24" :md="12" :lg="8">
  470 + <el-card class="update-log">
  471 + <div slot="header" class="clearfix">
  472 + <span>捐赠支持</span>
  473 + </div>
  474 + <div class="body">
  475 + <img
  476 + src="https://oscimg.oschina.net/oscnet/up-d6695f82666e5018f715c41cb7ee60d3b73.png"
  477 + alt="donate"
  478 + width="100%"
  479 + />
  480 + <span style="display: inline-block; height: 30px; line-height: 30px"
  481 + >你可以请作者喝杯咖啡表示鼓励</span
  482 + >
  483 + </div>
  484 + </el-card>
  485 + </el-col>
  486 + </el-row>
  487 + </div>
  488 +</template>
  489 +
  490 +<script>
  491 +export default {
  492 + name: "index",
  493 + data() {
  494 + return {
  495 + // 版本号
  496 + version: "3.3.0",
  497 + };
  498 + },
  499 + methods: {
  500 + goTarget(href) {
  501 + window.open(href, "_blank");
  502 + },
  503 + },
  504 +};
  505 +</script>
  506 +
  507 +<style scoped lang="scss">
  508 +.home {
  509 + blockquote {
  510 + padding: 10px 20px;
  511 + margin: 0 0 20px;
  512 + font-size: 17.5px;
  513 + border-left: 5px solid #eee;
  514 + }
  515 + hr {
  516 + margin-top: 20px;
  517 + margin-bottom: 20px;
  518 + border: 0;
  519 + border-top: 1px solid #eee;
  520 + }
  521 + .col-item {
  522 + margin-bottom: 20px;
  523 + }
  524 +
  525 + ul {
  526 + padding: 0;
  527 + margin: 0;
  528 + }
  529 +
  530 + font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  531 + font-size: 13px;
  532 + color: #676a6c;
  533 + overflow-x: hidden;
  534 +
  535 + ul {
  536 + list-style-type: none;
  537 + }
  538 +
  539 + h4 {
  540 + margin-top: 0px;
  541 + }
  542 +
  543 + h2 {
  544 + margin-top: 10px;
  545 + font-size: 26px;
  546 + font-weight: 100;
  547 + }
  548 +
  549 + p {
  550 + margin-top: 10px;
  551 +
  552 + b {
  553 + font-weight: 700;
  554 + }
  555 + }
  556 +
  557 + .update-log {
  558 + ol {
  559 + display: block;
  560 + list-style-type: decimal;
  561 + margin-block-start: 1em;
  562 + margin-block-end: 1em;
  563 + margin-inline-start: 0;
  564 + margin-inline-end: 0;
  565 + padding-inline-start: 40px;
  566 + }
  567 + }
  568 +}
  569 +</style>
  570 +
ruoyi-ui/src/views/index_v1.vue deleted
1 -<template>  
2 - <div class="dashboard-editor-container">  
3 -  
4 - <panel-group @handleSetLineChartData="handleSetLineChartData" />  
5 -  
6 - <el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">  
7 - <line-chart :chart-data="lineChartData" />  
8 - </el-row>  
9 -  
10 - <el-row :gutter="32">  
11 - <el-col :xs="24" :sm="24" :lg="8">  
12 - <div class="chart-wrapper">  
13 - <raddar-chart />  
14 - </div>  
15 - </el-col>  
16 - <el-col :xs="24" :sm="24" :lg="8">  
17 - <div class="chart-wrapper">  
18 - <pie-chart />  
19 - </div>  
20 - </el-col>  
21 - <el-col :xs="24" :sm="24" :lg="8">  
22 - <div class="chart-wrapper">  
23 - <bar-chart />  
24 - </div>  
25 - </el-col>  
26 - </el-row>  
27 -  
28 -  
29 - </div>  
30 -</template>  
31 -  
32 -<script>  
33 -import PanelGroup from './dashboard/PanelGroup'  
34 -import LineChart from './dashboard/LineChart'  
35 -import RaddarChart from './dashboard/RaddarChart'  
36 -import PieChart from './dashboard/PieChart'  
37 -import BarChart from './dashboard/BarChart'  
38 -  
39 -const lineChartData = {  
40 - newVisitis: {  
41 - expectedData: [100, 120, 161, 134, 105, 160, 165],  
42 - actualData: [120, 82, 91, 154, 162, 140, 145]  
43 - },  
44 - messages: {  
45 - expectedData: [200, 192, 120, 144, 160, 130, 140],  
46 - actualData: [180, 160, 151, 106, 145, 150, 130]  
47 - },  
48 - purchases: {  
49 - expectedData: [80, 100, 121, 104, 105, 90, 100],  
50 - actualData: [120, 90, 100, 138, 142, 130, 130]  
51 - },  
52 - shoppings: {  
53 - expectedData: [130, 140, 141, 142, 145, 150, 160],  
54 - actualData: [120, 82, 91, 154, 162, 140, 130]  
55 - }  
56 -}  
57 -  
58 -export default {  
59 - name: 'Index',  
60 - components: {  
61 - PanelGroup,  
62 - LineChart,  
63 - RaddarChart,  
64 - PieChart,  
65 - BarChart  
66 - },  
67 - data() {  
68 - return {  
69 - lineChartData: lineChartData.newVisitis  
70 - }  
71 - },  
72 - methods: {  
73 - handleSetLineChartData(type) {  
74 - this.lineChartData = lineChartData[type]  
75 - }  
76 - }  
77 -}  
78 -</script>  
79 -  
80 -<style lang="scss" scoped>  
81 -.dashboard-editor-container {  
82 - padding: 32px;  
83 - background-color: rgb(240, 242, 245);  
84 - position: relative;  
85 -  
86 - .chart-wrapper {  
87 - background: #fff;  
88 - padding: 16px 16px 0;  
89 - margin-bottom: 32px;  
90 - }  
91 -}  
92 -  
93 -@media (max-width:1024px) {  
94 - .chart-wrapper {  
95 - padding: 8px;  
96 - }  
97 -}  
98 -</style>  
ruoyi-ui/src/views/infra/job/index.vue
@@ -30,7 +30,7 @@ @@ -30,7 +30,7 @@
30 </el-col> 30 </el-col>
31 <el-col :span="1.5"> 31 <el-col :span="1.5">
32 <el-button type="info" icon="el-icon-s-operation" size="mini" @click="handleJobLog" 32 <el-button type="info" icon="el-icon-s-operation" size="mini" @click="handleJobLog"
33 - v-hasPermi="['monitor:job:query']">日志</el-button> 33 + v-hasPermi="['infra:job:query']">日志</el-button>
34 </el-col> 34 </el-col>
35 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> 35 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
36 </el-row> 36 </el-row>
@@ -53,9 +53,9 @@ @@ -53,9 +53,9 @@
53 <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" 53 <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
54 v-hasPermi="['infra:job:update']">修改</el-button> 54 v-hasPermi="['infra:job:update']">修改</el-button>
55 <el-button size="mini" type="text" icon="el-icon-check" @click="handleChangeStatus(scope.row, true)" 55 <el-button size="mini" type="text" icon="el-icon-check" @click="handleChangeStatus(scope.row, true)"
56 - v-hasPermi="['infra:job:update']">开启</el-button> 56 + v-if="scope.row.status === InfJobStatusEnum.STOP" v-hasPermi="['infra:job:update']">开启</el-button>
57 <el-button size="mini" type="text" icon="el-icon-close" @click="handleChangeStatus(scope.row, false)" 57 <el-button size="mini" type="text" icon="el-icon-close" @click="handleChangeStatus(scope.row, false)"
58 - v-hasPermi="['infra:job:update']">暂停</el-button> 58 + v-if="scope.row.status === InfJobStatusEnum.NORMAL" v-hasPermi="['infra:job:update']">暂停</el-button>
59 <el-button size="mini" type="text" icon="el-icon-caret-right" @click="handleRun(scope.row)" 59 <el-button size="mini" type="text" icon="el-icon-caret-right" @click="handleRun(scope.row)"
60 v-hasPermi="['infra:job:trigger']">执行一次</el-button> 60 v-hasPermi="['infra:job:trigger']">执行一次</el-button>
61 <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" 61 <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
@@ -82,6 +82,12 @@ @@ -82,6 +82,12 @@
82 <el-form-item label="CRON 表达式" prop="cronExpression"> 82 <el-form-item label="CRON 表达式" prop="cronExpression">
83 <el-input v-model="form.cronExpression" placeholder="请输入CRON 表达式" /> 83 <el-input v-model="form.cronExpression" placeholder="请输入CRON 表达式" />
84 </el-form-item> 84 </el-form-item>
  85 + <el-form-item label="重试次数" prop="retryCount">
  86 + <el-input v-model="form.retryCount" placeholder="请输入重试次数。设置为 0 时,不进行重试" />
  87 + </el-form-item>
  88 + <el-form-item label="重试间隔" prop="retryInterval">
  89 + <el-input v-model="form.retryInterval" placeholder="请输入重试间隔,单位:毫秒。设置为 0 时,无需间隔" />
  90 + </el-form-item>
85 <el-form-item label="监控超时时间" prop="monitorTimeout"> 91 <el-form-item label="监控超时时间" prop="monitorTimeout">
86 <el-input v-model="form.monitorTimeout" placeholder="请输入监控超时时间,单位:毫秒" /> 92 <el-input v-model="form.monitorTimeout" placeholder="请输入监控超时时间,单位:毫秒" />
87 </el-form-item> 93 </el-form-item>
@@ -107,6 +113,8 @@ @@ -107,6 +113,8 @@
107 <el-form-item label="最后一次执行的开始时间:">{{ parseTime(form.executeEndTime) }}</el-form-item> 113 <el-form-item label="最后一次执行的开始时间:">{{ parseTime(form.executeEndTime) }}</el-form-item>
108 <el-form-item label="上一次触发时间:">{{ parseTime(form.firePrevTime) }}</el-form-item> 114 <el-form-item label="上一次触发时间:">{{ parseTime(form.firePrevTime) }}</el-form-item>
109 <el-form-item label="下一次触发时间:">{{ parseTime(form.fireNextTime) }}</el-form-item> 115 <el-form-item label="下一次触发时间:">{{ parseTime(form.fireNextTime) }}</el-form-item>
  116 + <el-form-item label="重试次数:">{{ form.retryCount }}</el-form-item>
  117 + <el-form-item label="重试间隔:">{{ form.retryInterval + " 毫秒" }}</el-form-item>
110 <el-form-item label="监控超时时间:">{{ form.monitorTimeout > 0 ? form.monitorTimeout + " 毫秒" : "未开启" }}</el-form-item> 118 <el-form-item label="监控超时时间:">{{ form.monitorTimeout > 0 ? form.monitorTimeout + " 毫秒" : "未开启" }}</el-form-item>
111 </el-col> 119 </el-col>
112 </el-row> 120 </el-row>
@@ -158,7 +166,12 @@ export default { @@ -158,7 +166,12 @@ export default {
158 name: [{ required: true, message: "任务名称不能为空", trigger: "blur" }], 166 name: [{ required: true, message: "任务名称不能为空", trigger: "blur" }],
159 handlerName: [{ required: true, message: "处理器的名字不能为空", trigger: "blur" }], 167 handlerName: [{ required: true, message: "处理器的名字不能为空", trigger: "blur" }],
160 cronExpression: [{ required: true, message: "CRON 表达式不能为空", trigger: "blur" }], 168 cronExpression: [{ required: true, message: "CRON 表达式不能为空", trigger: "blur" }],
161 - } 169 + retryCount: [{ required: true, message: "重试次数不能为空", trigger: "blur" }],
  170 + retryInterval: [{ required: true, message: "重试间隔不能为空", trigger: "blur" }],
  171 + },
  172 +
  173 + // 枚举
  174 + InfJobStatusEnum: InfJobStatusEnum
162 }; 175 };
163 }, 176 },
164 created() { 177 created() {
@@ -187,6 +200,8 @@ export default { @@ -187,6 +200,8 @@ export default {
187 handlerName: undefined, 200 handlerName: undefined,
188 handlerParam: undefined, 201 handlerParam: undefined,
189 cronExpression: undefined, 202 cronExpression: undefined,
  203 + retryCount: undefined,
  204 + retryInterval: undefined,
190 monitorTimeout: undefined, 205 monitorTimeout: undefined,
191 }; 206 };
192 this.resetForm("form"); 207 this.resetForm("form");
src/main/java/cn/iocoder/dashboard/framework/mybatis/core/query/QueryWrapperX.java
@@ -65,6 +65,20 @@ public class QueryWrapperX&lt;T&gt; extends QueryWrapper&lt;T&gt; { @@ -65,6 +65,20 @@ public class QueryWrapperX&lt;T&gt; extends QueryWrapper&lt;T&gt; {
65 return this; 65 return this;
66 } 66 }
67 67
  68 + public QueryWrapperX<T> ltIfPresent(String column, Object val) {
  69 + if (val != null) {
  70 + return (QueryWrapperX<T>) super.lt(column, val);
  71 + }
  72 + return this;
  73 + }
  74 +
  75 + public QueryWrapperX<T> leIfPresent(String column, Object val) {
  76 + if (val != null) {
  77 + return (QueryWrapperX<T>) super.le(column, val);
  78 + }
  79 + return this;
  80 + }
  81 +
68 public QueryWrapperX<T> betweenIfPresent(String column, Object val1, Object val2) { 82 public QueryWrapperX<T> betweenIfPresent(String column, Object val1, Object val2) {
69 if (val1 != null && val2 != null) { 83 if (val1 != null && val2 != null) {
70 return (QueryWrapperX<T>) super.between(column, val1, val2); 84 return (QueryWrapperX<T>) super.between(column, val1, val2);
src/main/java/cn/iocoder/dashboard/framework/quartz/core/enums/JobDataKeyEnum.java
@@ -7,6 +7,8 @@ public enum JobDataKeyEnum { @@ -7,6 +7,8 @@ public enum JobDataKeyEnum {
7 7
8 JOB_ID, 8 JOB_ID,
9 JOB_HANDLER_NAME, 9 JOB_HANDLER_NAME,
10 - JOB_HANDLER_PARAM 10 + JOB_HANDLER_PARAM,
  11 + JOB_RETRY_COUNT, // 最大重试次数
  12 + JOB_RETRY_INTERVAL, // 每次重试间隔
11 13
12 } 14 }
src/main/java/cn/iocoder/dashboard/framework/quartz/core/handler/JobHandlerInvoker.java
1 package cn.iocoder.dashboard.framework.quartz.core.handler; 1 package cn.iocoder.dashboard.framework.quartz.core.handler;
2 2
3 import cn.hutool.core.lang.Assert; 3 import cn.hutool.core.lang.Assert;
4 -import cn.hutool.core.util.StrUtil; 4 +import cn.hutool.core.thread.ThreadUtil;
5 import cn.iocoder.dashboard.framework.quartz.core.enums.JobDataKeyEnum; 5 import cn.iocoder.dashboard.framework.quartz.core.enums.JobDataKeyEnum;
6 import cn.iocoder.dashboard.framework.quartz.core.service.JobLogFrameworkService; 6 import cn.iocoder.dashboard.framework.quartz.core.service.JobLogFrameworkService;
7 import lombok.extern.slf4j.Slf4j; 7 import lombok.extern.slf4j.Slf4j;
@@ -38,8 +38,11 @@ public class JobHandlerInvoker extends QuartzJobBean { @@ -38,8 +38,11 @@ public class JobHandlerInvoker extends QuartzJobBean {
38 protected void executeInternal(JobExecutionContext executionContext) throws JobExecutionException { 38 protected void executeInternal(JobExecutionContext executionContext) throws JobExecutionException {
39 // 第一步,获得 Job 数据 39 // 第一步,获得 Job 数据
40 Long jobId = executionContext.getMergedJobDataMap().getLong(JobDataKeyEnum.JOB_ID.name()); 40 Long jobId = executionContext.getMergedJobDataMap().getLong(JobDataKeyEnum.JOB_ID.name());
41 - String jobHandlerName = getJobHandlerName(executionContext); 41 + String jobHandlerName = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_NAME.name());
42 String jobHandlerParam = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_PARAM.name()); 42 String jobHandlerParam = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_PARAM.name());
  43 + int refireCount = executionContext.getRefireCount();
  44 + int retryCount = (Integer) executionContext.getMergedJobDataMap().getOrDefault(JobDataKeyEnum.JOB_RETRY_COUNT.name(), 0);
  45 + int retryInterval = (Integer) executionContext.getMergedJobDataMap().getOrDefault(JobDataKeyEnum.JOB_RETRY_INTERVAL.name(), 0);
43 46
44 // 第二步,执行任务 47 // 第二步,执行任务
45 Long jobLogId = null; 48 Long jobLogId = null;
@@ -48,7 +51,7 @@ public class JobHandlerInvoker extends QuartzJobBean { @@ -48,7 +51,7 @@ public class JobHandlerInvoker extends QuartzJobBean {
48 Throwable exception = null; 51 Throwable exception = null;
49 try { 52 try {
50 // 记录 Job 日志(初始) 53 // 记录 Job 日志(初始)
51 - jobLogId = jobLogFrameworkService.createJobLog(jobId, startTime, jobHandlerName, jobHandlerParam); 54 + jobLogId = jobLogFrameworkService.createJobLog(jobId, startTime, jobHandlerName, jobHandlerParam, refireCount + 1);
52 // 执行任务 55 // 执行任务
53 data = this.executeInternal(jobHandlerName, jobHandlerParam); 56 data = this.executeInternal(jobHandlerName, jobHandlerParam);
54 } catch (Throwable ex) { 57 } catch (Throwable ex) {
@@ -58,21 +61,8 @@ public class JobHandlerInvoker extends QuartzJobBean { @@ -58,21 +61,8 @@ public class JobHandlerInvoker extends QuartzJobBean {
58 // 第三步,记录执行日志 61 // 第三步,记录执行日志
59 this.updateJobLogResultAsync(jobLogId, startTime, data, exception, executionContext); 62 this.updateJobLogResultAsync(jobLogId, startTime, data, exception, executionContext);
60 63
61 - // 最终还是抛出异常,用于停止任务  
62 - if (exception != null) {  
63 - throw new JobExecutionException(exception);  
64 - }  
65 - }  
66 -  
67 - private static String getJobHandlerName(JobExecutionContext executionContext) {  
68 - String jobHandlerName = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_NAME.name());  
69 - if (StrUtil.isEmpty(jobHandlerName)) {  
70 - log.error("[executeInternal][Job({}) 获取不到正确的 jobHandlerName({})]",  
71 - executionContext.getJobDetail().getKey(), jobHandlerName);  
72 - throw new IllegalStateException(StrUtil.format("Job({}) 获取不到正确的 jobHandlerName({})",  
73 - executionContext.getJobDetail().getKey(), jobHandlerName));  
74 - }  
75 - return jobHandlerName; 64 + // 第四步,处理有异常的情况
  65 + handleException(exception, refireCount, retryCount, retryInterval);
76 } 66 }
77 67
78 private String executeInternal(String jobHandlerName, String jobHandlerParam) throws Exception { 68 private String executeInternal(String jobHandlerName, String jobHandlerParam) throws Exception {
@@ -86,18 +76,38 @@ public class JobHandlerInvoker extends QuartzJobBean { @@ -86,18 +76,38 @@ public class JobHandlerInvoker extends QuartzJobBean {
86 private void updateJobLogResultAsync(Long jobLogId, Date startTime, String data, Throwable exception, 76 private void updateJobLogResultAsync(Long jobLogId, Date startTime, String data, Throwable exception,
87 JobExecutionContext executionContext) { 77 JobExecutionContext executionContext) {
88 Date endTime = new Date(); 78 Date endTime = new Date();
  79 + // 处理是否成功
  80 + boolean success = exception == null;
  81 + if (!success) {
  82 + data = getRootCauseMessage(exception);
  83 + }
  84 + // 更新日志
89 try { 85 try {
90 - if (data != null) { // 成功  
91 - jobLogFrameworkService.updateJobLogSuccessAsync(jobLogId, endTime, (int) diff(endTime, startTime), data);  
92 - } else { // 失败  
93 - jobLogFrameworkService.updateJobLogErrorAsync(jobLogId, endTime, (int) diff(endTime, startTime),  
94 - getRootCauseMessage(exception));  
95 - } 86 + jobLogFrameworkService.updateJobLogResultAsync(jobLogId, endTime, (int) diff(endTime, startTime), success, data);
96 } catch (Exception ex) { 87 } catch (Exception ex) {
97 - log.error("[executeInternal][Job({}) logId({}) 记录执行日志失败({})]",  
98 - executionContext.getJobDetail().getKey(), jobLogId,  
99 - data != null ? data : getRootCauseMessage(exception)); 88 + log.error("[executeInternal][Job({}) logId({}) 记录执行日志失败({}/{})]",
  89 + executionContext.getJobDetail().getKey(), jobLogId, success, data);
  90 + }
  91 + }
  92 +
  93 + private void handleException(Throwable exception,
  94 + int refireCount, int retryCount, int retryInterval) throws JobExecutionException {
  95 + // 如果有异常,则进行重试
  96 + if (exception == null) {
  97 + return;
  98 + }
  99 + // 情况一:如果到达重试上限,则直接抛出异常即可
  100 + if (refireCount >= retryCount) {
  101 + throw new JobExecutionException(exception);
  102 + }
  103 +
  104 + // 情况二:如果未到达重试上限,则 sleep 一定间隔时间,然后重试
  105 + // 这里使用 sleep 来实现,主要还是希望实现比较简单。因为,同一时间,不会存在大量失败的 Job。
  106 + if (retryInterval > 0) {
  107 + ThreadUtil.sleep(retryInterval);
100 } 108 }
  109 + // 第二个参数,refireImmediately = true,表示立即重试
  110 + throw new JobExecutionException(exception, true);
101 } 111 }
102 112
103 } 113 }
src/main/java/cn/iocoder/dashboard/framework/quartz/core/scheduler/SchedulerManager.java
@@ -30,9 +30,12 @@ public class SchedulerManager { @@ -30,9 +30,12 @@ public class SchedulerManager {
30 * @param jobHandlerName 任务处理器的名字 30 * @param jobHandlerName 任务处理器的名字
31 * @param jobHandlerParam 任务处理器的参数 31 * @param jobHandlerParam 任务处理器的参数
32 * @param cronExpression CRON 表达式 32 * @param cronExpression CRON 表达式
  33 + * @param retryCount 重试次数
  34 + * @param retryInterval 重试间隔
33 * @throws SchedulerException 添加异常 35 * @throws SchedulerException 添加异常
34 */ 36 */
35 - public void addJob(Long jobId, String jobHandlerName, String jobHandlerParam, String cronExpression) 37 + public void addJob(Long jobId, String jobHandlerName, String jobHandlerParam, String cronExpression,
  38 + Integer retryCount, Integer retryInterval)
36 throws SchedulerException { 39 throws SchedulerException {
37 // 创建 JobDetail 对象 40 // 创建 JobDetail 对象
38 JobDetail jobDetail = JobBuilder.newJob(JobHandlerInvoker.class) 41 JobDetail jobDetail = JobBuilder.newJob(JobHandlerInvoker.class)
@@ -40,7 +43,7 @@ public class SchedulerManager { @@ -40,7 +43,7 @@ public class SchedulerManager {
40 .usingJobData(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName) 43 .usingJobData(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName)
41 .withIdentity(jobHandlerName).build(); 44 .withIdentity(jobHandlerName).build();
42 // 创建 Trigger 对象 45 // 创建 Trigger 对象
43 - Trigger trigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression); 46 + Trigger trigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval);
44 // 新增调度 47 // 新增调度
45 scheduler.scheduleJob(jobDetail, trigger); 48 scheduler.scheduleJob(jobDetail, trigger);
46 } 49 }
@@ -51,12 +54,15 @@ public class SchedulerManager { @@ -51,12 +54,15 @@ public class SchedulerManager {
51 * @param jobHandlerName 任务处理器的名字 54 * @param jobHandlerName 任务处理器的名字
52 * @param jobHandlerParam 任务处理器的参数 55 * @param jobHandlerParam 任务处理器的参数
53 * @param cronExpression CRON 表达式 56 * @param cronExpression CRON 表达式
  57 + * @param retryCount 重试次数
  58 + * @param retryInterval 重试间隔
54 * @throws SchedulerException 更新异常 59 * @throws SchedulerException 更新异常
55 */ 60 */
56 - public void updateJob(String jobHandlerName, String jobHandlerParam, String cronExpression) 61 + public void updateJob(String jobHandlerName, String jobHandlerParam, String cronExpression,
  62 + Integer retryCount, Integer retryInterval)
57 throws SchedulerException { 63 throws SchedulerException {
58 // 创建新 Trigger 对象 64 // 创建新 Trigger 对象
59 - Trigger newTrigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression); 65 + Trigger newTrigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval);
60 // 修改调度 66 // 修改调度
61 scheduler.rescheduleJob(new TriggerKey(jobHandlerName), newTrigger); 67 scheduler.rescheduleJob(new TriggerKey(jobHandlerName), newTrigger);
62 } 68 }
@@ -102,7 +108,7 @@ public class SchedulerManager { @@ -102,7 +108,7 @@ public class SchedulerManager {
102 */ 108 */
103 public void triggerJob(Long jobId, String jobHandlerName, String jobHandlerParam) 109 public void triggerJob(Long jobId, String jobHandlerName, String jobHandlerParam)
104 throws SchedulerException { 110 throws SchedulerException {
105 - JobDataMap data = new JobDataMap(); 111 + JobDataMap data = new JobDataMap(); // 无需重试,所以不设置 retryCount 和 retryInterval
106 data.put(JobDataKeyEnum.JOB_ID.name(), jobId); 112 data.put(JobDataKeyEnum.JOB_ID.name(), jobId);
107 data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName); 113 data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName);
108 data.put(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam); 114 data.put(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam);
@@ -110,11 +116,14 @@ public class SchedulerManager { @@ -110,11 +116,14 @@ public class SchedulerManager {
110 scheduler.triggerJob(new JobKey(jobHandlerName), data); 116 scheduler.triggerJob(new JobKey(jobHandlerName), data);
111 } 117 }
112 118
113 - private Trigger buildTrigger(String jobHandlerName, String jobHandlerParam, String cronExpression) { 119 + private Trigger buildTrigger(String jobHandlerName, String jobHandlerParam, String cronExpression,
  120 + Integer retryCount, Integer retryInterval) {
114 return TriggerBuilder.newTrigger() 121 return TriggerBuilder.newTrigger()
115 .withIdentity(jobHandlerName) 122 .withIdentity(jobHandlerName)
116 - .usingJobData(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam)  
117 .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) 123 .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
  124 + .usingJobData(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam)
  125 + .usingJobData(JobDataKeyEnum.JOB_RETRY_COUNT.name(), retryCount)
  126 + .usingJobData(JobDataKeyEnum.JOB_RETRY_INTERVAL.name(), retryInterval)
118 .build(); 127 .build();
119 } 128 }
120 129
src/main/java/cn/iocoder/dashboard/framework/quartz/core/service/JobLogFrameworkService.java
@@ -14,41 +14,31 @@ public interface JobLogFrameworkService { @@ -14,41 +14,31 @@ public interface JobLogFrameworkService {
14 /** 14 /**
15 * 创建 Job 日志 15 * 创建 Job 日志
16 * 16 *
17 - * @param jobId 任务编号  
18 - * @param beginTime 开始时间  
19 - * @param jobHandlerName Job 处理器的名字 17 + * @param jobId 任务编号
  18 + * @param beginTime 开始时间
  19 + * @param jobHandlerName Job 处理器的名字
20 * @param jobHandlerParam Job 处理器的参数 20 * @param jobHandlerParam Job 处理器的参数
  21 + * @param executeIndex 第几次执行
21 * @return Job 日志的编号 22 * @return Job 日志的编号
22 */ 23 */
23 Long createJobLog(@NotNull(message = "任务编号不能为空") Long jobId, 24 Long createJobLog(@NotNull(message = "任务编号不能为空") Long jobId,
24 @NotNull(message = "开始时间") Date beginTime, 25 @NotNull(message = "开始时间") Date beginTime,
25 @NotEmpty(message = "Job 处理器的名字不能为空") String jobHandlerName, 26 @NotEmpty(message = "Job 处理器的名字不能为空") String jobHandlerName,
26 - String jobHandlerParam); 27 + String jobHandlerParam,
  28 + @NotNull(message = "第几次执行不能为空") Integer executeIndex);
27 29
28 /** 30 /**
29 - * 更新 Job 日志成功 31 + * 更新 Job 日志的执行结果
30 * 32 *
31 - * @param logId 日志编号  
32 - * @param endTime 结束时间。因为是异步,避免记录时间不准去 33 + * @param logId 日志编号
  34 + * @param endTime 结束时间。因为是异步,避免记录时间不准去
33 * @param duration 运行时长,单位:毫秒 35 * @param duration 运行时长,单位:毫秒
34 - * @param result 成功数据 36 + * @param success 是否成功
  37 + * @param result 成功数据
35 */ 38 */
36 - void updateJobLogSuccessAsync(@NotNull(message = "日志编号不能为空") Long logId,  
37 - @NotNull(message = "结束时间不能为空") Date endTime,  
38 - @NotNull(message = "运行时长不能为空") Integer duration,  
39 - String result);  
40 -  
41 - /**  
42 - * 更新 Job 日志失败  
43 - *  
44 - * @param logId 日志编号  
45 - * @param endTime 结束时间。因为是异步,避免记录时间不准去  
46 - * @param duration 运行时长,单位:毫秒  
47 - * @param result 异常提示  
48 - */  
49 - void updateJobLogErrorAsync(@NotNull(message = "日志编号不能为空") Long logId,  
50 - @NotNull(message = "结束时间不能为空") Date endTime,  
51 - @NotNull(message = "运行时长不能为空") Integer duration,  
52 - String result); 39 + void updateJobLogResultAsync(@NotNull(message = "日志编号不能为空") Long logId,
  40 + @NotNull(message = "结束时间不能为空") Date endTime,
  41 + @NotNull(message = "运行时长不能为空") Integer duration,
  42 + boolean success, String result);
53 43
54 } 44 }
src/main/java/cn/iocoder/dashboard/modules/infra/controller/dbdoc/InfDbDocController.java renamed to src/main/java/cn/iocoder/dashboard/modules/infra/controller/doc/InfDbDocController.java
1 -package cn.iocoder.dashboard.modules.infra.controller.dbdoc; 1 +package cn.iocoder.dashboard.modules.infra.controller.doc;
2 2
3 import cn.hutool.extra.servlet.ServletUtil; 3 import cn.hutool.extra.servlet.ServletUtil;
4 import cn.smallbun.screw.core.Configuration; 4 import cn.smallbun.screw.core.Configuration;
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/job/InfJobBaseVO.java
@@ -23,6 +23,14 @@ public class InfJobBaseVO { @@ -23,6 +23,14 @@ public class InfJobBaseVO {
23 @NotNull(message = "CRON 表达式不能为空") 23 @NotNull(message = "CRON 表达式不能为空")
24 private String cronExpression; 24 private String cronExpression;
25 25
  26 + @ApiModelProperty(value = "重试次数", required = true)
  27 + @NotNull(message = "重试次数不能为空")
  28 + private Integer retryCount;
  29 +
  30 + @ApiModelProperty(value = "重试间隔", required = true)
  31 + @NotNull(message = "重试间隔不能为空")
  32 + private Integer retryInterval;
  33 +
26 @ApiModelProperty(value = "监控超时时间", example = "1000") 34 @ApiModelProperty(value = "监控超时时间", example = "1000")
27 private Integer monitorTimeout; 35 private Integer monitorTimeout;
28 36
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/log/InfJobLogBaseVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.infra.controller.job.vo.log;
  2 +
  3 +import io.swagger.annotations.ApiModelProperty;
  4 +import lombok.Data;
  5 +import org.springframework.format.annotation.DateTimeFormat;
  6 +
  7 +import javax.validation.constraints.NotNull;
  8 +import java.util.Date;
  9 +
  10 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +/**
  13 +* 定时任务日志 Base VO,提供给添加、修改、详细的子 VO 使用
  14 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  15 +*/
  16 +@Data
  17 +public class InfJobLogBaseVO {
  18 +
  19 + @ApiModelProperty(value = "任务编号", required = true)
  20 + @NotNull(message = "任务编号不能为空")
  21 + private Long jobId;
  22 +
  23 + @ApiModelProperty(value = "处理器的名字", required = true)
  24 + @NotNull(message = "处理器的名字不能为空")
  25 + private String handlerName;
  26 +
  27 + @ApiModelProperty(value = "处理器的参数")
  28 + private String handlerParam;
  29 +
  30 + @ApiModelProperty(value = "第几次执行", required = true)
  31 + @NotNull(message = "第几次执行不能为空")
  32 + private Integer executeIndex;
  33 +
  34 + @ApiModelProperty(value = "开始执行时间", required = true)
  35 + @NotNull(message = "开始执行时间不能为空")
  36 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  37 + private Date beginTime;
  38 +
  39 + @ApiModelProperty(value = "结束执行时间")
  40 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  41 + private Date endTime;
  42 +
  43 + @ApiModelProperty(value = "执行时长")
  44 + private Integer duration;
  45 +
  46 + @ApiModelProperty(value = "任务状态", required = true)
  47 + @NotNull(message = "任务状态不能为空")
  48 + private Integer status;
  49 +
  50 + @ApiModelProperty(value = "结果数据")
  51 + private String result;
  52 +
  53 +}
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/log/InfJobLogExcelVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.infra.controller.job.vo.log;
  2 +
  3 +import com.alibaba.excel.annotation.ExcelProperty;
  4 +import lombok.Data;
  5 +
  6 +import java.util.Date;
  7 +
  8 +/**
  9 + * 定时任务 Excel VO
  10 + *
  11 + * @author 芋艿
  12 + */
  13 +@Data
  14 +public class InfJobLogExcelVO {
  15 +
  16 + @ExcelProperty("日志编号")
  17 + private Long id;
  18 +
  19 + @ExcelProperty("任务编号")
  20 + private Long jobId;
  21 +
  22 + @ExcelProperty("处理器的名字")
  23 + private String handlerName;
  24 +
  25 + @ExcelProperty("处理器的参数")
  26 + private String handlerParam;
  27 +
  28 + @ExcelProperty("第几次执行")
  29 + private Integer executeIndex;
  30 +
  31 + @ExcelProperty("开始执行时间")
  32 + private Date beginTime;
  33 +
  34 + @ExcelProperty("结束执行时间")
  35 + private Date endTime;
  36 +
  37 + @ExcelProperty("执行时长")
  38 + private Integer duration;
  39 +
  40 + @ExcelProperty("任务状态")
  41 + private Integer status;
  42 +
  43 + @ExcelProperty("结果数据")
  44 + private String result;
  45 +
  46 + @ExcelProperty("创建时间")
  47 + private Date createTime;
  48 +
  49 +}
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/log/InfJobLogExportReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.infra.controller.job.vo.log;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +
  8 +import java.util.Date;
  9 +
  10 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +@ApiModel(value = "定时任务 Excel 导出 Request VO", description = "参数和 InfJobLogPageReqVO 是一致的")
  13 +@Data
  14 +public class InfJobLogExportReqVO {
  15 +
  16 + @ApiModelProperty(value = "处理器的名字")
  17 + private String handlerName;
  18 +
  19 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  20 + @ApiModelProperty(value = "开始执行时间")
  21 + private Date beginTime;
  22 +
  23 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  24 + @ApiModelProperty(value = "结束执行时间")
  25 + private Date endTime;
  26 +
  27 + @ApiModelProperty(value = "任务状态")
  28 + private Integer status;
  29 +
  30 +}
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/log/InfJobLogPageReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.infra.controller.job.vo.log;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageParam;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
  9 +import org.springframework.format.annotation.DateTimeFormat;
  10 +
  11 +import java.util.Date;
  12 +
  13 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  14 +
  15 +@ApiModel("定时任务日志分页 Request VO")
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@ToString(callSuper = true)
  19 +public class InfJobLogPageReqVO extends PageParam {
  20 +
  21 + @ApiModelProperty(value = "处理器的名字")
  22 + private String handlerName;
  23 +
  24 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  25 + @ApiModelProperty(value = "开始执行时间")
  26 + private Date beginTime;
  27 +
  28 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  29 + @ApiModelProperty(value = "结束执行时间")
  30 + private Date endTime;
  31 +
  32 + @ApiModelProperty(value = "任务状态")
  33 + private Integer status;
  34 +
  35 +}
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/log/InfJobLogRespVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.infra.controller.job.vo.log;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import java.util.Date;
  10 +
  11 +@ApiModel("定时任务日志 Response VO")
  12 +@Data
  13 +@EqualsAndHashCode(callSuper = true)
  14 +@ToString(callSuper = true)
  15 +public class InfJobLogRespVO extends InfJobLogBaseVO {
  16 +
  17 + @ApiModelProperty(value = "日志编号", required = true)
  18 + private Long id;
  19 +
  20 + @ApiModelProperty(value = "创建时间", required = true)
  21 + private Date createTime;
  22 +
  23 +}
src/main/java/cn/iocoder/dashboard/modules/infra/dal/dataobject/job/InfJobDO.java
@@ -75,6 +75,18 @@ public class InfJobDO extends BaseDO { @@ -75,6 +75,18 @@ public class InfJobDO extends BaseDO {
75 */ 75 */
76 private Date fireNextTime; 76 private Date fireNextTime;
77 77
  78 + // ========== 重试相关字段 ==========
  79 + /**
  80 + * 重试次数
  81 + * 如果不重试,则设置为 0
  82 + */
  83 + private Integer retryCount;
  84 + /**
  85 + * 重试间隔,单位:毫秒
  86 + * 如果没有间隔,则设置为 0
  87 + */
  88 + private Integer retryInterval;
  89 +
78 // ========== 监控相关字段 ========== 90 // ========== 监控相关字段 ==========
79 /** 91 /**
80 * 监控超时时间,单位:毫秒 92 * 监控超时时间,单位:毫秒
src/main/java/cn/iocoder/dashboard/modules/infra/dal/dataobject/job/InfJobLogDO.java
@@ -44,6 +44,12 @@ public class InfJobLogDO extends BaseDO { @@ -44,6 +44,12 @@ public class InfJobLogDO extends BaseDO {
44 * 冗余字段 {@link InfJobDO#getHandlerParam()} 44 * 冗余字段 {@link InfJobDO#getHandlerParam()}
45 */ 45 */
46 private String handlerParam; 46 private String handlerParam;
  47 + /**
  48 + * 第几次执行
  49 + *
  50 + * 用于区分是不是重试执行。如果是重试执行,则 index 大于 1
  51 + */
  52 + private Integer executeIndex;
47 53
48 /** 54 /**
49 * 开始执行时间 55 * 开始执行时间
src/main/java/cn/iocoder/dashboard/modules/infra/enums/job/InfJobStatusEnum.java
@@ -23,17 +23,13 @@ public enum InfJobStatusEnum { @@ -23,17 +23,13 @@ public enum InfJobStatusEnum {
23 */ 23 */
24 INIT(0, Collections.emptySet()), 24 INIT(0, Collections.emptySet()),
25 /** 25 /**
26 - * 开启运行 26 + * 开启
27 */ 27 */
28 NORMAL(1, Sets.newHashSet(STATE_WAITING, STATE_ACQUIRED, STATE_BLOCKED)), 28 NORMAL(1, Sets.newHashSet(STATE_WAITING, STATE_ACQUIRED, STATE_BLOCKED)),
29 /** 29 /**
30 - * 异常运行 30 + * 暂停
31 */ 31 */
32 - EXCEPTION(2, Sets.newHashSet(STATE_COMPLETE)),  
33 - /**  
34 - * 暂停运行  
35 - */  
36 - STOP(3, Sets.newHashSet(STATE_PAUSED, STATE_PAUSED_BLOCKED)); 32 + STOP(2, Sets.newHashSet(STATE_PAUSED, STATE_PAUSED_BLOCKED));
37 33
38 /** 34 /**
39 * 状态 35 * 状态
src/main/java/cn/iocoder/dashboard/modules/infra/service/job/impl/InfJobLogServiceImpl.java
@@ -26,8 +26,8 @@ public class InfJobLogServiceImpl implements InfJobLogService { @@ -26,8 +26,8 @@ public class InfJobLogServiceImpl implements InfJobLogService {
26 private InfJobLogMapper jobLogMapper; 26 private InfJobLogMapper jobLogMapper;
27 27
28 @Override 28 @Override
29 - public Long createJobLog(Long jobId, Date beginTime, String jobHandlerName, String jobHandlerParam) {  
30 - InfJobLogDO log = InfJobLogDO.builder().jobId(jobId).handlerName(jobHandlerName).handlerParam(jobHandlerParam) 29 + public Long createJobLog(Long jobId, Date beginTime, String jobHandlerName, String jobHandlerParam, Integer executeIndex) {
  30 + InfJobLogDO log = InfJobLogDO.builder().jobId(jobId).handlerName(jobHandlerName).handlerParam(jobHandlerParam).executeIndex(executeIndex)
31 .beginTime(beginTime).status(InfJobLogStatusEnum.RUNNING.getStatus()).build(); 31 .beginTime(beginTime).status(InfJobLogStatusEnum.RUNNING.getStatus()).build();
32 jobLogMapper.insert(log); 32 jobLogMapper.insert(log);
33 return log.getId(); 33 return log.getId();
@@ -35,24 +35,14 @@ public class InfJobLogServiceImpl implements InfJobLogService { @@ -35,24 +35,14 @@ public class InfJobLogServiceImpl implements InfJobLogService {
35 35
36 @Override 36 @Override
37 @Async 37 @Async
38 - public void updateJobLogSuccessAsync(Long logId, Date endTime, Integer duration, String result) {  
39 - updateJobLogResult(logId, endTime, duration, result, InfJobLogStatusEnum.SUCCESS);  
40 - }  
41 -  
42 - @Override  
43 - @Async  
44 - public void updateJobLogErrorAsync(Long logId, Date endTime, Integer duration, String result) {  
45 - updateJobLogResult(logId, endTime, duration, result, InfJobLogStatusEnum.FAILURE);  
46 - }  
47 -  
48 - private void updateJobLogResult(Long logId, Date endTime, Integer duration, String result, InfJobLogStatusEnum status) { 38 + public void updateJobLogResultAsync(Long logId, Date endTime, Integer duration, boolean success, String result) {
49 try { 39 try {
50 InfJobLogDO updateObj = InfJobLogDO.builder().id(logId).endTime(endTime).duration(duration) 40 InfJobLogDO updateObj = InfJobLogDO.builder().id(logId).endTime(endTime).duration(duration)
51 - .status(status.getStatus()).result(result).build(); 41 + .status(success ? InfJobLogStatusEnum.SUCCESS.getStatus() : InfJobLogStatusEnum.FAILURE.getStatus()).result(result).build();
52 jobLogMapper.updateById(updateObj); 42 jobLogMapper.updateById(updateObj);
53 } catch (Exception ex) { 43 } catch (Exception ex) {
54 - log.error("[updateJobLogResult][logId({}) endTime({}) duration({}) result({}) status({})]",  
55 - logId, endTime, duration, result, status); 44 + log.error("[updateJobLogResultAsync][logId({}) endTime({}) duration({}) success({}) result({})]",
  45 + logId, endTime, duration, success, result);
56 } 46 }
57 } 47 }
58 48
src/main/java/cn/iocoder/dashboard/modules/infra/service/job/impl/InfJobServiceImpl.java
@@ -55,7 +55,8 @@ public class InfJobServiceImpl implements InfJobService { @@ -55,7 +55,8 @@ public class InfJobServiceImpl implements InfJobService {
55 jobMapper.insert(job); 55 jobMapper.insert(job);
56 56
57 // 添加 Job 到 Quartz 中 57 // 添加 Job 到 Quartz 中
58 - schedulerManager.addJob(job.getId(), job.getHandlerName(), job.getHandlerParam(), job.getCronExpression()); 58 + schedulerManager.addJob(job.getId(), job.getHandlerName(), job.getHandlerParam(), job.getCronExpression(),
  59 + createReqVO.getRetryCount(), createReqVO.getRetryInterval());
59 // 更新 60 // 更新
60 InfJobDO updateObj = InfJobDO.builder().id(job.getId()).status(InfJobStatusEnum.NORMAL.getStatus()).build(); 61 InfJobDO updateObj = InfJobDO.builder().id(job.getId()).status(InfJobStatusEnum.NORMAL.getStatus()).build();
61 jobMapper.updateById(updateObj); 62 jobMapper.updateById(updateObj);
@@ -80,7 +81,8 @@ public class InfJobServiceImpl implements InfJobService { @@ -80,7 +81,8 @@ public class InfJobServiceImpl implements InfJobService {
80 jobMapper.updateById(updateObj); 81 jobMapper.updateById(updateObj);
81 82
82 // 更新 Job 到 Quartz 中 83 // 更新 Job 到 Quartz 中
83 - schedulerManager.updateJob(job.getHandlerName(), updateReqVO.getHandlerParam(), updateReqVO.getCronExpression()); 84 + schedulerManager.updateJob(job.getHandlerName(), updateReqVO.getHandlerParam(), updateReqVO.getCronExpression(),
  85 + updateReqVO.getRetryCount(), updateReqVO.getRetryInterval());
84 } 86 }
85 87
86 @Override 88 @Override
@@ -138,7 +140,7 @@ public class InfJobServiceImpl implements InfJobService { @@ -138,7 +140,7 @@ public class InfJobServiceImpl implements InfJobService {
138 } 140 }
139 141
140 private void validateCronExpression(String cronExpression) { 142 private void validateCronExpression(String cronExpression) {
141 - if (CronUtils.isValid(cronExpression)) { 143 + if (!CronUtils.isValid(cronExpression)) {
142 throw exception(JOB_CRON_EXPRESSION_VALID); 144 throw exception(JOB_CRON_EXPRESSION_VALID);
143 } 145 }
144 } 146 }
src/main/java/cn/iocoder/dashboard/modules/system/job/auth/SysUserSessionTimeoutJob.java
@@ -15,6 +15,9 @@ public class SysUserSessionTimeoutJob implements JobHandler { @@ -15,6 +15,9 @@ public class SysUserSessionTimeoutJob implements JobHandler {
15 15
16 @Override 16 @Override
17 public String execute(String param) throws Exception { 17 public String execute(String param) throws Exception {
  18 + if (true) {
  19 + throw new RuntimeException("测试异常");
  20 + }
18 // System.out.println("执行了一次任务"); 21 // System.out.println("执行了一次任务");
19 log.info("[execute][执行任务:{}]", param); 22 log.info("[execute][执行任务:{}]", param);
20 return null; 23 return null;
src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenServiceImpl.java
@@ -134,6 +134,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService { @@ -134,6 +134,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
134 } 134 }
135 135
136 @Override 136 @Override
  137 + @Transactional
137 public void syncCodegenFromDB(Long tableId) { 138 public void syncCodegenFromDB(Long tableId) {
138 // 校验是否已经存在 139 // 校验是否已经存在
139 ToolCodegenTableDO table = codegenTableMapper.selectById(tableId); 140 ToolCodegenTableDO table = codegenTableMapper.selectById(tableId);
@@ -148,6 +149,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService { @@ -148,6 +149,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
148 } 149 }
149 150
150 @Override 151 @Override
  152 + @Transactional
151 public void syncCodegenFromSQL(Long tableId, String sql) { 153 public void syncCodegenFromSQL(Long tableId, String sql) {
152 // 校验是否已经存在 154 // 校验是否已经存在
153 ToolCodegenTableDO table = codegenTableMapper.selectById(tableId); 155 ToolCodegenTableDO table = codegenTableMapper.selectById(tableId);
@@ -193,7 +195,9 @@ public class ToolCodegenServiceImpl implements ToolCodegenService { @@ -193,7 +195,9 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
193 codegenColumnMapper.insert(column); // TODO 批量插入 195 codegenColumnMapper.insert(column); // TODO 批量插入
194 }); 196 });
195 // 删除不存在的字段 197 // 删除不存在的字段
196 - codegenColumnMapper.deleteBatchIds(deleteColumnIds); 198 + if (CollUtil.isNotEmpty(deleteColumnIds)) {
  199 + codegenColumnMapper.deleteBatchIds(deleteColumnIds);
  200 + }
197 } 201 }
198 202
199 @Override 203 @Override
src/main/resources/codegen/java/dal/mapper.vm
@@ -27,7 +27,10 @@ import ${basePackage}.${table.moduleName}.controller.${table.businessName}.vo.*; @@ -27,7 +27,10 @@ import ${basePackage}.${table.moduleName}.controller.${table.businessName}.vo.*;
27 .geIfPresent("${column.columnName}", reqVO.get${JavaField}()) 27 .geIfPresent("${column.columnName}", reqVO.get${JavaField}())
28 #end 28 #end
29 #if (${column.listOperationCondition} == "<")##情况五,< 的时候 29 #if (${column.listOperationCondition} == "<")##情况五,< 的时候
30 - .gtIfPresent("${column.columnName}", reqVO.get${JavaField}()) 30 + .ltIfPresent("${column.columnName}", reqVO.get${JavaField}())
  31 +#end
  32 +#if (${column.listOperationCondition} == "<=")##情况五,<= 的时候
  33 + .leIfPresent("${column.columnName}", reqVO.get${JavaField}())
31 #end 34 #end
32 #if (${column.listOperationCondition} == "LIKE")##情况七,Like 的时候 35 #if (${column.listOperationCondition} == "LIKE")##情况七,Like 的时候
33 .likeIfPresent("${column.columnName}", reqVO.get${JavaField}()) 36 .likeIfPresent("${column.columnName}", reqVO.get${JavaField}())
src/test/java/cn/iocoder/dashboard/framework/quartz/core/scheduler/SchedulerManagerTest.java
@@ -20,13 +20,13 @@ class SchedulerManagerTest { @@ -20,13 +20,13 @@ class SchedulerManagerTest {
20 @Test 20 @Test
21 public void testAddJob() throws SchedulerException { 21 public void testAddJob() throws SchedulerException {
22 String jobHandlerName = StrUtil.lowerFirst(SysUserSessionTimeoutJob.class.getSimpleName()); 22 String jobHandlerName = StrUtil.lowerFirst(SysUserSessionTimeoutJob.class.getSimpleName());
23 - schedulerManager.addJob(1L, jobHandlerName, "test", "0/10 * * * * ? *"); 23 + schedulerManager.addJob(1L, jobHandlerName, "test", "0/10 * * * * ? *", 0, 0);
24 } 24 }
25 25
26 @Test 26 @Test
27 public void testUpdateJob() throws SchedulerException { 27 public void testUpdateJob() throws SchedulerException {
28 String jobHandlerName = StrUtil.lowerFirst(SysUserSessionTimeoutJob.class.getSimpleName()); 28 String jobHandlerName = StrUtil.lowerFirst(SysUserSessionTimeoutJob.class.getSimpleName());
29 - schedulerManager.updateJob(jobHandlerName, "hahaha", "0/20 * * * * ? *"); 29 + schedulerManager.updateJob(jobHandlerName, "hahaha", "0/20 * * * * ? *", 0, 0);
30 } 30 }
31 31
32 @Test 32 @Test