feat(admin): 重构控制器包结构并增强国际化支持

- 将 IndexController 和 LoginController 移至 base 包下统一管理
- 为菜单资源创建新的 DTO 类 XxlBootResourceDTO 支持权限控制
- 增强 I18nUtil 工具类实现 InitializingBean 接口以便初始化枚举标题
- 更新多语言配置文件,增加系统操作相关词条及帮助文档链接
- 调整用户与任务组控制器中的请求映射路径和参数验证逻辑
- 修改视图返回路径适配新的包结构调整
- 删除旧的 CommonDataInterceptor 并通过 FreeMarker 配置共享静态模型
- 优化登录逻辑使用 Cookie 进行 SSO 校验并支持密码修改功能
- 统一异常页面处理方式提升用户体验
- 完善日期绑定编辑器确保前端传参格式正确解析
3.3.0-release
xuxueli 3 weeks ago
parent 896feaa128
commit 5fe79778b4

@ -8,6 +8,7 @@ import com.xxl.job.admin.model.XxlJobInfo;
import com.xxl.job.admin.model.XxlJobLog;
import com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;
import com.xxl.job.admin.scheduler.exception.XxlJobException;
import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.admin.util.I18nUtil;
import com.xxl.job.admin.util.JobGroupPermissionUtil;
import com.xxl.job.core.openapi.ExecutorBiz;
@ -24,6 +25,7 @@ import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@ -43,7 +45,7 @@ import java.util.Map;
@Controller
@RequestMapping("/joblog")
public class JobLogController {
private static Logger logger = LoggerFactory.getLogger(JobLogController.class);
private static final Logger logger = LoggerFactory.getLogger(JobLogController.class);
@Resource
private XxlJobGroupMapper xxlJobGroupMapper;
@ -51,58 +53,71 @@ public class JobLogController {
public XxlJobInfoMapper xxlJobInfoMapper;
@Resource
public XxlJobLogMapper xxlJobLogMapper;
@Autowired
private XxlJobService xxlJobService;
@RequestMapping
public String index(HttpServletRequest request, Model model,
public String index(HttpServletRequest request,
Model model,
@RequestParam(value = "jobGroup", required = false, defaultValue = "0") Integer jobGroup,
@RequestParam(value = "jobId", required = false, defaultValue = "0") Integer jobId) {
// find jobGroup
// find all jobGroup
List<XxlJobGroup> jobGroupListTotal = xxlJobGroupMapper.findAll();
// filter jobGroup
// filter JobGroupList
List<XxlJobGroup> jobGroupList = JobGroupPermissionUtil.filterJobGroupByPermission(request, jobGroupListTotal);
if (CollectionTool.isEmpty(jobGroupList)) {
throw new XxlJobException(I18nUtil.getString("jobgroup_empty"));
}
// write jobGroup
model.addAttribute("JobGroupList", jobGroupList);
// parse jobId、jobGroup
// parse jobGroup
if (jobId > 0) {
// assign jobId (+ jobGroup)
XxlJobInfo jobInfo = xxlJobInfoMapper.loadById(jobId);
if (jobInfo == null) {
// jobId not exist, inteceptor
throw new RuntimeException(I18nUtil.getString("jobinfo_field_id") + I18nUtil.getString("system_unvalid"));
}
jobGroup = jobInfo.getJobGroup();
} else if (jobGroup > 0){
} else if (jobGroup > 0) {
// assign jobGroup
Integer finalJobGroup = jobGroup;
if (CollectionTool.isEmpty(jobGroupListTotal.stream().filter(item -> item.getId() == finalJobGroup).toList())) {
// jobGroup not exist, use first
jobGroup = jobGroupList.get(0).getId();
}
jobId = 0;
} else {
// default first valid jobGroup
jobGroup = jobGroupList.get(0).getId();
jobId = 0;
}
jobGroup = jobGroup > 0 ? jobGroup : jobGroupList.get(0).getId();
// valid permission
JobGroupPermissionUtil.validJobGroupPermission(request, jobGroup);
/*// valid permission
JobGroupPermissionUtil.validJobGroupPermission(request, jobGroup);*/
// find jobList
List<XxlJobInfo> jobInfoList = xxlJobInfoMapper.getJobsByGroup(jobGroup);
// parse jobId
if (CollectionTool.isEmpty(jobInfoList)) {
jobId = 0;
} else {
if (!jobInfoList.stream().map(XxlJobInfo::getId).toList().contains(jobId)) {
// jobId not exist, use first
jobId = jobInfoList.get(0).getId();
}
}
// write
model.addAttribute("JobGroupList", jobGroupList);
model.addAttribute("jobInfoList", jobInfoList);
model.addAttribute("jobGroup", jobGroup);
model.addAttribute("jobId", jobId);
return "joblog/joblog.index";
return "biz/log.list";
}
/*@RequestMapping("/getJobsByGroup")
@ResponseBody
public Response<List<XxlJobInfo>> getJobsByGroup(HttpServletRequest request, @RequestParam("jobGroup") int jobGroup){
// valid permission
JobInfoController.validJobGroupPermission(request, jobGroup);
// query
List<XxlJobInfo> list = xxlJobInfoMapper.getJobsByGroup(jobGroup);
return Response.ofSuccess(list);
}*/
@RequestMapping("/pageList")
@ResponseBody
@ -117,6 +132,11 @@ public class JobLogController {
// valid jobGroup permission
JobGroupPermissionUtil.validJobGroupPermission(request, jobGroup);
// valid jobId
if (jobId < 1) {
return Response.ofFail(I18nUtil.getString("system_please_choose") + I18nUtil.getString("jobinfo_job"));
}
// parse param
Date triggerTimeStart = null;
Date triggerTimeEnd = null;
@ -140,64 +160,8 @@ public class JobLogController {
return Response.ofSuccess(pageModel);
}
@RequestMapping("/logDetailPage")
public String logDetailPage(HttpServletRequest request, @RequestParam("id") int id, Model model){
// base check
XxlJobLog jobLog = xxlJobLogMapper.load(id);
if (jobLog == null) {
throw new RuntimeException(I18nUtil.getString("joblog_logid_unvalid"));
}
// valid permission
JobGroupPermissionUtil.validJobGroupPermission(request, jobLog.getJobGroup());
// data
model.addAttribute("triggerCode", jobLog.getTriggerCode());
model.addAttribute("handleCode", jobLog.getHandleCode());
model.addAttribute("logId", jobLog.getId());
return "joblog/joblog.detail";
}
@RequestMapping("/logDetailCat")
@ResponseBody
public Response<LogResult> logDetailCat(@RequestParam("logId") long logId, @RequestParam("fromLineNum") int fromLineNum){
try {
// valid
XxlJobLog jobLog = xxlJobLogMapper.load(logId); // todo, need to improve performance
if (jobLog == null) {
return Response.ofFail(I18nUtil.getString("joblog_logid_unvalid"));
}
// log cat
ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(jobLog.getExecutorAddress());
Response<LogResult> logResult = executorBiz.log(new LogRequest(jobLog.getTriggerTime().getTime(), logId, fromLineNum));
// is end
if (logResult.getData()!=null && logResult.getData().getFromLineNum() > logResult.getData().getToLineNum()) {
if (jobLog.getHandleCode() > 0) {
logResult.getData().setEnd(true);
}
}
// fix xss
if (logResult.getData()!=null && StringTool.isNotBlank(logResult.getData().getLogContent())) {
String newLogContent = filter(logResult.getData().getLogContent());
logResult.getData().setLogContent(newLogContent);
}
return logResult;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return Response.ofFail(e.getMessage());
}
}
/**
* filter xss tag
*
* @param originData
* @return
*/
private String filter(String originData){
@ -271,6 +235,11 @@ public class JobLogController {
// valid JobGroup permission
JobGroupPermissionUtil.validJobGroupPermission(request, jobGroup);
// valid jobId
if (jobId < 1) {
return Response.ofFail(I18nUtil.getString("system_please_choose") + I18nUtil.getString("jobinfo_job"));
}
// opt
Date clearBeforeTime = null;
int clearBeforeNum = 0;
@ -299,12 +268,69 @@ public class JobLogController {
List<Long> logIds = null;
do {
logIds = xxlJobLogMapper.findClearLogIds(jobGroup, jobId, clearBeforeTime, clearBeforeNum, 1000);
if (logIds!=null && logIds.size()>0) {
if (logIds!=null && !logIds.isEmpty()) {
xxlJobLogMapper.clearLog(logIds);
}
} while (logIds!=null && logIds.size()>0);
} while (logIds!=null && !logIds.isEmpty());
return Response.ofSuccess();
}
@RequestMapping("/logDetailPage")
public String logDetailPage(HttpServletRequest request, @RequestParam("id") int id, Model model){
// base check
XxlJobLog jobLog = xxlJobLogMapper.load(id);
if (jobLog == null) {
throw new RuntimeException(I18nUtil.getString("joblog_logid_unvalid"));
}
// valid permission
JobGroupPermissionUtil.validJobGroupPermission(request, jobLog.getJobGroup());
// load jobInfo
XxlJobInfo jobInfo = xxlJobInfoMapper.loadById(jobLog.getJobId());
// data
model.addAttribute("triggerCode", jobLog.getTriggerCode());
model.addAttribute("handleCode", jobLog.getHandleCode());
model.addAttribute("logId", jobLog.getId());
model.addAttribute("jobInfo", jobInfo);
return "biz/log.detail";
}
@RequestMapping("/logDetailCat")
@ResponseBody
public Response<LogResult> logDetailCat(@RequestParam("logId") long logId, @RequestParam("fromLineNum") int fromLineNum){
try {
// valid
XxlJobLog jobLog = xxlJobLogMapper.load(logId); // todo, need to improve performance
if (jobLog == null) {
return Response.ofFail(I18nUtil.getString("joblog_logid_unvalid"));
}
// log cat
ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(jobLog.getExecutorAddress());
Response<LogResult> logResult = executorBiz.log(new LogRequest(jobLog.getTriggerTime().getTime(), logId, fromLineNum));
// is end
if (logResult.getData()!=null && logResult.getData().getFromLineNum() > logResult.getData().getToLineNum()) {
if (jobLog.getHandleCode() > 0) {
logResult.getData().setEnd(true);
}
}
// fix xss
if (logResult.getData()!=null && StringTool.isNotBlank(logResult.getData().getLogContent())) {
String newLogContent = filter(logResult.getData().getLogContent());
logResult.getData().setLogContent(newLogContent);
}
return logResult;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return Response.ofFail(e.getMessage());
}
}
}

@ -52,7 +52,8 @@ public class JobGroupPermissionUtil {
return jobGroupListTotal;
} else {
List<String> jobGroups = (loginInfoResponse.getData().getExtraInfo()!=null && loginInfoResponse.getData().getExtraInfo().containsKey("jobGroups"))
? StringTool.split(loginInfoResponse.getData().getExtraInfo().get("jobGroups"), ",") :new ArrayList<>();
? StringTool.split(loginInfoResponse.getData().getExtraInfo().get("jobGroups"), ",")
:new ArrayList<>();
return jobGroupListTotal
.stream()

@ -0,0 +1,184 @@
<!DOCTYPE html>
<html>
<head>
<#-- import macro -->
<#import "../common/common.macro.ftl" as netCommon>
<!-- 1-style start -->
<@netCommon.commonStyle />
<!-- 1-style end -->
</head>
<body class="hold-transition skin-blue layout-top-nav" >
<div class="wrapper" >
<!-- 2-header start -->
<header class="main-header">
<nav class="navbar navbar-static-top">
<div class="container">
<#-- icon -->
<div class="navbar-header">
<a class="navbar-brand" href="javascript:void(0);" ><b>${I18n.joblog_rolling_log}</b> Console</a>
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
<i class="fa fa-bars"></i>
</button>
</div>
<#-- left nav -->
<div class="collapse navbar-collapse pull-left" id="navbar-collapse">
<ul class="nav navbar-nav">
<#--<li class="active" ><a href="javascript:;"><span class="sr-only">(current)</span></a></li>-->
</ul>
</div>
<#-- right nav -->
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
<li>
<a href="javascript:window.location.reload();" >
<i class="fa fa-fw fa-refresh" ></i>
${I18n.joblog_rolling_log_refresh}
</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<!-- 2-header end -->
<!-- 3-content start -->
<div class="content-wrapper">
<section class="content">
<!-- rolling log -->
<pre style="font-size:12px;position:relative;" >
<div id="logConsole"></div>
<li class="fa fa-refresh fa-spin" style="font-size: 20px;float: left;" id="logConsoleRunning" ></li>
</pre>
</section>
</div>
<!-- 3-content end -->
<!-- 4-footer start -->
<footer class="main-footer">
Powered by <b>XXL-JOB</b> ${I18n.admin_version}
<div class="pull-right hidden-xs">
<strong>Copyright &copy; 2015-${.now?string('yyyy')} &nbsp;
<a href="https://www.xuxueli.com/" target="_blank" >xuxueli</a>
&nbsp;
<a href="https://github.com/xuxueli/xxl-job" target="_blank" >github</a>
</strong><!-- All rights reserved. -->
</div>
</footer>
<!-- 4-footer end -->
</div>
<!-- 5-script start -->
<@netCommon.commonScript />
<script src="${request.contextPath}/static/biz/common/admin.setting.js?v=${I18n.admin_version}"></script>
<script>
$(function() {
// init param
var triggerCode = '${triggerCode}';
var handleCode = '${handleCode}';
var logId = '${logId}';
// valid trigger fail, end
if ( !(triggerCode == 200 || handleCode != 0) ) {
$('#logConsoleRunning').hide();
$('#logConsole').append('<span style="color: red;">'+ I18n.joblog_rolling_log_triggerfail +'</span>');
return;
}
/**
* pull log
*/
var fromLineNum = 1; // [from, to], start as 1
var pullFailCount = 0;
function pullLog() {
// pullFailCount, max=20
if (pullFailCount++ > 20) {
logRunStop('<span style="color: red;">'+ I18n.joblog_rolling_log_failoften +'</span>');
return;
}
// load
console.log("pullLog, fromLineNum:" + fromLineNum);
$.ajax({
type : 'POST',
async: false, // sync, make log ordered
url : base_url + '/joblog/logDetailCat',
data : {
"logId":logId,
"fromLineNum":fromLineNum
},
dataType : "json",
success : function(data){
if (data.code == 200) {
if (!data.data) {
console.log('pullLog fail');
return;
}
if (fromLineNum != data.data.fromLineNum) {
console.log('pullLog fromLineNum not match');
return;
}
if (fromLineNum > data.data.toLineNum ) {
console.log('pullLog already line-end');
// valid end
if (data.data.end) {
logRunStop('<br><span style="color: green;">[Rolling Log Finish]</span>');
return;
}
return;
}
// append content
fromLineNum = data.data.toLineNum + 1;
$('#logConsole').append(data.data.logContent);
pullFailCount = 0;
// scroll to bottom
scrollTo(0, document.body.scrollHeight); // $('#logConsolePre').scrollTop( document.body.scrollHeight + 300 );
} else {
console.log('pullLog fail:'+data.msg);
}
}
});
}
// pull first page
pullLog();
// if handle already callback, stop cycle pull
if (handleCode > 0) {
logRunStop('<br><span style="color: green;">[Load Log Finish]</span>');
return;
}
/**
* cycle pull, until end
*/
var logRun = setInterval(function () {
pullLog()
}, 3000);
function logRunStop(content){
$('#logConsoleRunning').hide();
logRun = window.clearInterval(logRun);
$('#logConsole').append(content);
}
});
</script>
<!-- 5-script end -->
</body>
</html>

@ -0,0 +1,564 @@
<!DOCTYPE html>
<html>
<head>
<#-- import macro -->
<#import "../common/common.macro.ftl" as netCommon>
<!-- 1-style start -->
<@netCommon.commonStyle />
<link rel="stylesheet" href="${request.contextPath}/static/plugins/bootstrap-table/bootstrap-table.min.css">
<!-- daterangepicker -->
<link rel="stylesheet" href="${request.contextPath}/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.css">
<!-- 1-style end -->
</head>
<body class="hold-transition" style="background-color: #ecf0f5;">
<div class="wrapper">
<section class="content">
<!-- 2-content start -->
<#-- -->
<div class="box" style="margin-bottom:9px;">
<div class="box-body">
<div class="row" id="data_filter" >
<div class="col-xs-2">
<div class="input-group">
<span class="input-group-addon">${I18n.jobinfo_field_jobgroup}</span>
<select class="form-control" id="jobGroup" >
<#list JobGroupList as group>
<option value="${group.id}" <#if jobGroup==group.id>selected</#if> >${group.title}</option>
</#list>
</select>
</div>
</div>
<div class="col-xs-2">
<div class="input-group">
<span class="input-group-addon">${I18n.jobinfo_job}</span>
<select class="form-control" id="jobId" >
<#if jobInfoList?size gt 0>
<#list jobInfoList as jobItem>
<option value="${jobItem.id}" >${jobItem.jobDesc}</option>
</#list>
<#else>
<option value="0" >${I18n.system_selected_nothing}</option>
</#if>
</select>
</div>
</div>
<div class="col-xs-2">
<div class="input-group">
<span class="input-group-addon">${I18n.joblog_status}</span>
<select class="form-control" id="logStatus" >
<option value="-1" >${I18n.joblog_status_all}</option>
<option value="1" >${I18n.joblog_status_suc}</option>
<option value="2" >${I18n.joblog_status_fail}</option>
<option value="3" >${I18n.joblog_status_running}</option>
</select>
</div>
</div>
<div class="col-xs-4">
<div class="input-group">
<span class="input-group-addon">
${I18n.joblog_field_triggerTime}
</span>
<input type="text" class="form-control" id="filterTime" readonly >
</div>
</div>
<div class="col-xs-1">
<button class="btn btn-block btn-primary searchBtn" >${I18n.system_search}</button>
</div>
<div class="col-xs-1">
<button class="btn btn-block btn-default resetBtn" >${I18n.system_reset}</button>
</div>
</div>
</div>
</div>
<#-- -->
<div class="row">
<div class="col-xs-12">
<div class="box">
<div class="box-header pull-left" id="data_operation" >
<button class="btn btn-sm btn-info selectOnlyOne logDetail" type="button"><#--<i class="fa fa-edit"></i>-->${I18n.joblog_rolling_log}</button>
<button class="btn btn-sm btn-warning selectOnlyOne logKill" type="button">${I18n.joblog_kill_log}</button>
<button class="btn btn-sm btn-danger selectAny clearLog" type="button">${I18n.joblog_clean_log}</button>
<#--warning
danger
info
default-->
</div>
<div class="box-body" >
<table id="data_list" class="table table-bordered table-striped" width="100%" >
<thead></thead>
<tbody></tbody>
<tfoot></tfoot>
</table>
</div>
</div>
</div>
</div>
<!-- . -->
<div class="modal fade" id="clearLogModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" >${I18n.joblog_clean_log}</h4>
</div>
<div class="modal-body">
<form class="form-horizontal form" role="form" >
<div class="form-group">
<label class="col-sm-3 control-label">${I18n.jobinfo_field_jobgroup}</label>
<div class="col-sm-9">
<input type="text" class="form-control jobGroupText" readonly >
<input type="hidden" name="jobGroup" >
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">${I18n.jobinfo_job}</label>
<div class="col-sm-9">
<input type="text" class="form-control jobIdText" readonly >
<input type="hidden" name="jobId" >
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">${I18n.joblog_clean_type}</label>
<div class="col-sm-9">
<select class="form-control" name="type" >
<option value="1" >${I18n.joblog_clean_type_1}</option>
<option value="2" >${I18n.joblog_clean_type_2}</option>
<option value="3" >${I18n.joblog_clean_type_3}</option>
<option value="4" >${I18n.joblog_clean_type_4}</option>
<option value="5" >${I18n.joblog_clean_type_5}</option>
<option value="6" >${I18n.joblog_clean_type_6}</option>
<option value="7" >${I18n.joblog_clean_type_7}</option>
<option value="8" >${I18n.joblog_clean_type_8}</option>
<option value="9" >${I18n.joblog_clean_type_9}</option>
</select>
</div>
</div>
<hr>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button type="button" class="btn btn-primary ok" >${I18n.system_ok}</button>
<button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- 2-content end -->
</section>
</div>
<!-- 3-script start -->
<@netCommon.commonScript />
<script src="${request.contextPath}/static/plugins/bootstrap-table/bootstrap-table.min.js"></script>
<script src="${request.contextPath}/static/plugins/bootstrap-table/locale/<#if I18n.admin_i18n?? && I18n.admin_i18n == 'en'>bootstrap-table-en-US.min.js<#else>bootstrap-table-zh-CN.min.js</#if>"></script>
<#--daterangepicker-->
<script src="${request.contextPath}/static/adminlte/bower_components/moment/moment.min.js"></script>
<script src="${request.contextPath}/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.js"></script>
<#-- admin table -->
<script src="${request.contextPath}/static/biz/common/admin.table.js"></script>
<script>
$(function() {
// ---------------------- filter ----------------------
/**
* jobGroup change
*/
$('#jobGroup').on('change', function(){
//reload
var jobGroup = $('#jobGroup').val();
window.location.href = base_url + "/joblog?jobGroup=" + jobGroup;
});
/**
* filter Time
*/
var rangesConf = {};
rangesConf[I18n.daterangepicker_ranges_recent_hour] = [moment().subtract(1, 'hours'), moment()];
rangesConf[I18n.daterangepicker_ranges_today] = [moment().startOf('day'), moment().endOf('day')];
rangesConf[I18n.daterangepicker_ranges_yesterday] = [moment().subtract(1, 'days').startOf('day'), moment().subtract(1, 'days').endOf('day')];
rangesConf[I18n.daterangepicker_ranges_this_month] = [moment().startOf('month'), moment().endOf('month')];
rangesConf[I18n.daterangepicker_ranges_last_month] = [moment().subtract(1, 'months').startOf('month'), moment().subtract(1, 'months').endOf('month')];
rangesConf[I18n.daterangepicker_ranges_recent_week] = [moment().subtract(1, 'weeks').startOf('day'), moment().endOf('day')];
rangesConf[I18n.daterangepicker_ranges_recent_month] = [moment().subtract(1, 'months').startOf('day'), moment().endOf('day')];
$('#filterTime').daterangepicker({
autoApply:false,
singleDatePicker:false,
showDropdowns:false, // 是否显示年月选择条件
timePicker: true, // 是否显示小时和分钟选择条件
timePickerIncrement: 10, // 时间的增量,单位为分钟
timePicker24Hour : true,
opens : 'left', //日期选择框的弹出位置
ranges: rangesConf,
locale : {
format: 'YYYY-MM-DD HH:mm:ss',
separator : ' - ',
customRangeLabel : I18n.daterangepicker_custom_name ,
applyLabel : I18n.system_ok ,
cancelLabel : I18n.system_cancel ,
fromLabel : I18n.daterangepicker_custom_starttime ,
toLabel : I18n.daterangepicker_custom_endtime ,
daysOfWeek : I18n.daterangepicker_custom_daysofweek.split(',') , // '日', '一', '二', '三', '四', '五', '六'
monthNames : I18n.daterangepicker_custom_monthnames.split(',') , // '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'
firstDay : 1
}/*,
startDate: rangesConf[I18n.daterangepicker_ranges_today][0],
endDate: rangesConf[I18n.daterangepicker_ranges_today][1]*/
});
// init filter
var jobGroup = '${jobGroup}';
var jobId = '${jobId}';
function resetFilter(){
$('#filterTime').data("daterangepicker").setStartDate( rangesConf[I18n.daterangepicker_ranges_today][0] );
$('#filterTime').data("daterangepicker").setEndDate( rangesConf[I18n.daterangepicker_ranges_today][1] );
// todo
$('#filterTime').data("daterangepicker").setStartDate( rangesConf[I18n.daterangepicker_ranges_recent_month][0] );
$('#filterTime').data("daterangepicker").setEndDate( rangesConf[I18n.daterangepicker_ranges_recent_month][1] );
$("#jobGroup").val( jobGroup );
$("#jobId").val( jobId );
$('#logStatus').prop('selectedIndex', 0);
}
resetFilter();
// ---------------------- page ----------------------
/**
* init table
*/
$.adminTable.initTable({
table: '#data_list',
url: base_url + "/joblog/pageList",
queryParams: function (params) {
var obj = {};
obj.jobGroup = $('#jobGroup').val();
obj.jobId = $('#jobId').val();
obj.logStatus = $('#logStatus').val();
obj.filterTime = $('#filterTime').val();
obj.offset = params.offset;
obj.pagesize = params.limit;
return obj;
},
resetHandler : function() {
// reset filter
resetFilter();
},
columns:[
{
checkbox: true,
field: 'state',
width: '5',
widthUnit: '%',
align: 'center',
valign: 'middle'
},{
title: I18n.jobinfo_field_id,
field: 'jobId',
width: '10',
widthUnit: '%',
align: 'left',
formatter: function(value, row, index) {
// logTips
var temp = '';
temp += I18n.joblog_field_executorAddress + '' + (row.executorAddress?row.executorAddress:'');
if (row.executorHandler) {
temp += "<br>JobHandler" + row.executorHandler;
}
temp += '<br>'+ I18n.jobinfo_field_executorparam +'' + row.executorParam;
// build
return '<a class="logTips" href="javascript:;" >'+ row.jobId +'<span style="display:none;">'+ temp +'</span></a>';
}
},{
title: I18n.joblog_field_triggerTime,
field: 'triggerTime',
width: '16',
widthUnit: '%',
formatter: function(value, row, index) {
return value?moment(value).format("YYYY-MM-DD HH:mm:ss"):"";
}
},{
title: I18n.joblog_field_triggerCode,
field: 'triggerCode',
width: '10',
widthUnit: '%',
formatter: function(value, row, index) {
var html = value;
if (value == 200) { // 200, success
html = '<span style="color: green">'+ I18n.system_success +'</span>';
} else if (value > 0) { // >0 or 500, fail
html = '<span style="color: red">'+ I18n.system_fail +'</span>';
} else if (value == 0) { // 0, original pass
html = '';
}
return html;
}
},{
title: I18n.joblog_field_triggerMsg,
field: 'triggerMsg',
width: '10',
widthUnit: '%',
formatter: function(value, row, index) {
return value?'<a class="logTips" href="javascript:;" >'+ I18n.system_show +'<span style="display:none;">'+ value +'</span></a>':I18n.system_empty;
}
},{
title: I18n.joblog_field_handleTime,
field: 'handleTime',
width: '16',
widthUnit: '%',
formatter: function(value, row, index) {
return value?moment(value).format("YYYY-MM-DD HH:mm:ss"):"";
}
},{
title: I18n.joblog_field_handleCode,
field: 'handleCode',
width: '10',
widthUnit: '%',
formatter: function(value, row, index) {
var html = value;
if (value == 200) { // 200, success
html = '<span style="color: green">'+ I18n.joblog_handleCode_200 +'</span>';
} else if (value == 502) { // 502, timeout
html = '<span style="color: red">'+ I18n.joblog_handleCode_502 +'</span>';
} else if (value > 0) { // >0 or 500, fail
html = '<span style="color: red">'+ I18n.joblog_handleCode_500 +'</span>';
} else if (value == 0) { // 0, original pass
html = '';
}
return html;
}
},{
title: I18n.joblog_field_handleMsg,
field: 'handleMsg',
width: '10',
widthUnit: '%',
formatter: function(value, row, index) {
return value?'<a class="logTips" href="javascript:;" >'+ I18n.system_show +'<span style="display:none;">'+ value +'</span></a>':I18n.system_empty;
}
}/*,{
title: I18n.system_opt,
field: 'handleMsg',
width: '13',
widthUnit: '%',
formatter: function(value, row, index) {
if (row.triggerCode == 200 || row.handleCode != 0){
var logKillDiv = '';
if(row.handleCode == 0 || true){
logKillDiv = ' <li class="divider"></li>\n' +
' <li><a href="javascript:void(0);" class="logKill" _id="'+ row.id +'" >'+ I18n.joblog_kill_log +'</a></li>\n';
}
var html = '<div class="btn-group">\n' +
' <button type="button" class="btn btn-primary btn-sm">'+ I18n.system_opt +'</button>\n' +
' <button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown">\n' +
' <span class="caret"></span>\n' +
' <span class="sr-only">Toggle Dropdown</span>\n' +
' </button>\n' +
' <ul class="dropdown-menu dropdown-menu-right " role="menu" _id="'+ row.id +'" >\n' +
' <li><a href="javascript:void(0);" class="logDetail" _id="'+ row.id +'" >'+ I18n.joblog_rolling_log +'</a></li>\n' +
logKillDiv +
' </ul>\n' +
' </div>';
return html;
}
return '';
}
}*/
]
});
/**
* logDetail
*/
$("#data_operation").on('click', '.logDetail',function() {
// get select rows
var rows = $.adminTable.table.bootstrapTable('getSelections');
// find select row
if (rows.length !== 1) {
layer.msg(I18n.system_please_choose + I18n.system_one + I18n.system_data);
return;
}
var row = rows[0];
window.open(base_url + '/joblog/logDetailPage?id=' + row.id);
});
/**
* log Kill
*/
$('#data_operation').on('click', '.logKill', function(){
// get select rows
var rows = $.adminTable.table.bootstrapTable('getSelections');
// find select row
if (rows.length !== 1) {
layer.msg(I18n.system_please_choose + I18n.system_one + I18n.system_data);
return;
}
var row = rows[0];
// do kill
layer.confirm( (I18n.system_ok + I18n.joblog_kill_log + '?'), {
icon: 3,
title: I18n.system_tips ,
btn: [ I18n.system_ok, I18n.system_cancel ]
}, function(index){
layer.close(index);
$.ajax({
type : 'POST',
url : base_url + '/joblog/logKill',
data : {
"id": row.id
},
dataType : "json",
success : function(data){
if (data.code == 200) {
layer.open({
title: I18n.system_tips,
btn: [ I18n.system_ok ],
content: I18n.system_opt_suc ,
icon: '1',
end: function(layero, index){
// refresh table
$('#data_filter .searchBtn').click();
}
});
} else {
layer.open({
title: I18n.system_tips,
btn: [ I18n.system_ok ],
content: (data.msg || I18n.system_opt_fail ),
icon: '2'
});
}
},
});
});
});
/**
* clear Log
*/
$('#data_operation').on('click', '.clearLog', function(){
var jobGroup = $('#jobGroup').val();
var jobId = $('#jobId').val();
var jobGroupText = $("#jobGroup").find("option:selected").text();
var jobIdText = $("#jobId").find("option:selected").text();
$('#clearLogModal input[name=jobGroup]').val(jobGroup);
$('#clearLogModal input[name=jobId]').val(jobId);
$('#clearLogModal .jobGroupText').val(jobGroupText);
$('#clearLogModal .jobIdText').val(jobIdText);
$('#clearLogModal').modal('show');
});
$("#clearLogModal .ok").on('click', function(){
$.post(base_url + "/joblog/clearLog", $("#clearLogModal .form").serialize(), function(data, status) {
if (data.code == "200") {
$('#clearLogModal').modal('hide');
layer.open({
title: I18n.system_tips ,
btn: [ I18n.system_ok ],
content: (I18n.joblog_clean_log + I18n.system_success) ,
icon: '1',
end: function(layero, index){
logTable.fnDraw();
}
});
} else {
layer.open({
title: I18n.system_tips ,
btn: [ I18n.system_ok ],
content: (data.msg || (I18n.joblog_clean_log + I18n.system_fail) ),
icon: '2'
});
}
});
});
$("#clearLogModal").on('hide.bs.modal', function () {
$("#clearLogModal .form")[0].reset();
});
// ---------------------- ComAlertTec ----------------------
/**
* logTips alert
*/
$('body').on('click', '.logTips', function(){
var msg = $(this).find('span').html();
ComAlertTec.show(msg);
});
// Com Alert by Tec theme
var ComAlertTec = {
html:function(){
var html =
'<div class="modal fade" id="ComAlertTec" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">' +
' <div class="modal-dialog modal-lg-">' +
' <div class="modal-content-tec">' +
' <div class="modal-body">' +
' <div class="alert" style="color:#fff;word-wrap: break-word;">' +
' </div>' +
' </div>' +
' <div class="modal-footer">' +
' <div class="text-center" >' +
' <button type="button" class="btn btn-info ok" data-dismiss="modal" >'+ I18n.system_ok +'</button>' +
' </div>' +
' </div>' +
' </div>' +
' </div>' +
'</div>';
return html;
},
show:function(msg, callback){
// dom init
if ($('#ComAlertTec').length == 0){
$('body').append(ComAlertTec.html());
}
// init com alert
$('#ComAlertTec .alert').html(msg);
$('#ComAlertTec').modal('show');
$('#ComAlertTec .ok').click(function(){
$('#ComAlertTec').modal('hide');
if(typeof callback == 'function') {
callback();
}
});
}
};
});
</script>
<!-- 3-script end -->
</body>
</html>

@ -1,92 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<#-- import macro -->
<#import "../common/common.macro.ftl" as netCommon>
<#-- commonStyle -->
<@netCommon.commonStyle />
<#-- biz start1/5 style -->
<#-- biz end1/5 end -->
</head>
<body class="hold-transition skin-blue layout-top-nav">
<div class="wrapper">
<!-- header -->
<#-- biz start2/5 style -->
<header class="main-header">
<nav class="navbar navbar-static-top">
<div class="container">
<#-- icon -->
<div class="navbar-header">
<a class="navbar-brand"><b>${I18n.joblog_rolling_log}</b> Console</a>
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
<i class="fa fa-bars"></i>
</button>
</div>
<#-- left nav -->
<div class="collapse navbar-collapse pull-left" id="navbar-collapse">
<ul class="nav navbar-nav">
<#--<li class="active" ><a href="javascript:;"><span class="sr-only">(current)</span></a></li>-->
</ul>
</div>
<#-- right nav -->
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
<li>
<a href="javascript:window.location.reload();" >
<i class="fa fa-fw fa-refresh" ></i>
${I18n.joblog_rolling_log_refresh}
</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<#-- biz end2/5 end -->
<!-- right start -->
<div class="content-wrapper" >
<#-- biz start3/5 name -->
<#-- biz end3/5 name -->
<!-- content-main -->
<section class="content">
<#-- biz start4/5 content -->
<pre style="font-size:12px;position:relative;" >
<div id="logConsole"></div>
<li class="fa fa-refresh fa-spin" style="font-size: 20px;float: left;" id="logConsoleRunning" ></li>
</pre>
<#-- biz end4/5 content -->
</section>
</div>
<!-- right end -->
<!-- footer -->
<@netCommon.commonFooter />
</div>
<@netCommon.commonScript />
<#-- biz start5/5 script -->
<script>
// 参数
var triggerCode = '${triggerCode}';
var handleCode = '${handleCode}';
var logId = '${logId}';
</script>
<script src="${request.contextPath}/static/js/joblog.detail.1.js"></script>
<#-- biz end5/5 script -->
</body>
</html>

@ -1,206 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<#-- import macro -->
<#import "../common/common.macro.ftl" as netCommon>
<#-- commonStyle -->
<@netCommon.commonStyle />
<#-- biz start1/5 style -->
<!-- DataTables -->
<link rel="stylesheet" href="${request.contextPath}/static/adminlte/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css">
<!-- daterangepicker -->
<link rel="stylesheet" href="${request.contextPath}/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.css">
<#-- biz end1/5 end -->
</head>
<body class="hold-transition skin-blue sidebar-mini">
<div class="wrapper">
<!-- header -->
<@netCommon.commonHeader />
<!-- left -->
<#-- biz start2/5 left -->
<@netCommon.commonLeft "joblog" />
<#-- biz end2/5 left -->
<!-- right start -->
<div class="content-wrapper">
<!-- content-header -->
<section class="content-header">
<#-- biz start3/5 name -->
<h1>${I18n.joblog_name}</h1>
<#-- biz end3/5 name -->
</section>
<!-- content-main -->
<section class="content">
<#-- biz start4/5 content -->
<!-- filter-->
<div class="row">
<div class="col-xs-2">
<div class="input-group">
<span class="input-group-addon">${I18n.jobinfo_field_jobgroup}</span>
<select class="form-control" id="jobGroup" >
<#list JobGroupList as group>
<option value="${group.id}" <#if jobGroup==group.id>selected</#if> >${group.title}</option>
</#list>
</select>
</div>
</div>
<div class="col-xs-2">
<div class="input-group">
<span class="input-group-addon">${I18n.jobinfo_job}</span>
<select class="form-control" id="jobId" >
<option value="0" >${I18n.system_all}</option>
<#list jobInfoList as jobItem>
<option value="${jobItem.id}" <#if jobId==jobItem.id>selected</#if> >${jobItem.jobDesc}</option>
</#list>
</select>
</div>
</div>
<div class="col-xs-2">
<div class="input-group">
<span class="input-group-addon">${I18n.joblog_status}</span>
<select class="form-control" id="logStatus" >
<option value="-1" >${I18n.joblog_status_all}</option>
<option value="1" >${I18n.joblog_status_suc}</option>
<option value="2" >${I18n.joblog_status_fail}</option>
<option value="3" >${I18n.joblog_status_running}</option>
</select>
</div>
</div>
<div class="col-xs-4">
<div class="input-group">
<span class="input-group-addon">
${I18n.joblog_field_triggerTime}
</span>
<input type="text" class="form-control" id="filterTime" readonly >
</div>
</div>
<div class="col-xs-1">
<button class="btn btn-block btn-info" id="searchBtn">${I18n.system_search}</button>
</div>
<div class="col-xs-1">
<button class="btn btn-block btn-default" id="clearLog">${I18n.joblog_clean}</button>
</div>
</div>
<!-- table-->
<div class="row">
<div class="col-xs-12">
<div class="box">
<#--<div class="box-header hide"><h3 class="box-title"></h3></div>-->
<div class="box-body">
<table id="joblog_list" class="table table-bordered table-striped display" width="100%" >
<thead>
<tr>
<th name="jobId" >${I18n.jobinfo_field_id}</th>
<th name="jobGroup" >jobGroup</th>
<#--<th name="executorAddress" ></th>
<th name="glueType" ></th>
<th name="executorParam" ></th>-->
<th name="triggerTime" >${I18n.joblog_field_triggerTime}</th>
<th name="triggerCode" >${I18n.joblog_field_triggerCode}</th>
<th name="triggerMsg" >${I18n.joblog_field_triggerMsg}</th>
<th name="handleTime" >${I18n.joblog_field_handleTime}</th>
<th name="handleCode" >${I18n.joblog_field_handleCode}</th>
<th name="handleMsg" >${I18n.joblog_field_handleMsg}</th>
<th name="handleMsg" >${I18n.system_opt}</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
</div>
</section>
<!-- . -->
<div class="modal fade" id="clearLogModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" >${I18n.joblog_clean_log}</h4>
</div>
<div class="modal-body">
<form class="form-horizontal form" role="form" >
<div class="form-group">
<label class="col-sm-3 control-label">${I18n.jobinfo_field_jobgroup}</label>
<div class="col-sm-9">
<input type="text" class="form-control jobGroupText" readonly >
<input type="hidden" name="jobGroup" >
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">${I18n.jobinfo_job}</label>
<div class="col-sm-9">
<input type="text" class="form-control jobIdText" readonly >
<input type="hidden" name="jobId" >
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">${I18n.joblog_clean_type}</label>
<div class="col-sm-9">
<select class="form-control" name="type" >
<option value="1" >${I18n.joblog_clean_type_1}</option>
<option value="2" >${I18n.joblog_clean_type_2}</option>
<option value="3" >${I18n.joblog_clean_type_3}</option>
<option value="4" >${I18n.joblog_clean_type_4}</option>
<option value="5" >${I18n.joblog_clean_type_5}</option>
<option value="6" >${I18n.joblog_clean_type_6}</option>
<option value="7" >${I18n.joblog_clean_type_7}</option>
<option value="8" >${I18n.joblog_clean_type_8}</option>
<option value="9" >${I18n.joblog_clean_type_9}</option>
</select>
</div>
</div>
<hr>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button type="button" class="btn btn-primary ok" >${I18n.system_ok}</button>
<button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<#-- biz end4/5 content -->
</div>
<!-- right end -->
<!-- footer -->
<@netCommon.commonFooter />
</div>
<@netCommon.commonScript />
<#-- biz start5/5 script -->
<!-- DataTables -->
<script src="${request.contextPath}/static/adminlte/bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
<script src="${request.contextPath}/static/adminlte/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
<!-- daterangepicker -->
<script src="${request.contextPath}/static/adminlte/bower_components/moment/moment.min.js"></script>
<script src="${request.contextPath}/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.js"></script>
<script src="${request.contextPath}/static/js/joblog.index.1.js"></script>
<#-- biz end5/5 script -->
</body>
</html>
Loading…
Cancel
Save