执行器UI交互优化

master
xuxueli 5 years ago
parent ae05b5ce36
commit fbd83d5161
  1. 2
      doc/XXL-JOB官方文档.md
  2. 26
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java
  3. 9
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java
  4. 11
      xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobGroupDao.java
  5. 1
      xxl-job-admin/src/main/resources/i18n/message_en.properties
  6. 1
      xxl-job-admin/src/main/resources/i18n/message_zh_CN.properties
  7. 1
      xxl-job-admin/src/main/resources/i18n/message_zh_TC.properties
  8. 39
      xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobGroupMapper.xml
  9. 202
      xxl-job-admin/src/main/resources/static/js/jobgroup.index.1.js
  10. 75
      xxl-job-admin/src/main/resources/templates/jobgroup/jobgroup.index.ftl
  11. 5
      xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobGroupDaoTest.java

@ -1730,7 +1730,7 @@ data: post-data
- 15、执行器注册逻辑优化:新增配置项 ”注册地址 / xxl.job.executor.address“,优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
- 16、执行器初始化逻辑优化:修复懒加载的Bean被提前初始化问题;
- 17、任务复制功能:点击复制是弹出新建任务弹框,并初始化被复制任务信息;
- 18、[迭代中]新增执行器描述、任务描述属性;
- 18、执行器UI交互优化;(新增执行器描述属性)
- 19、[迭代中]任务执行一次的时候指定IP;
- 20、[迭代中]自定义失败重试时间间隔;
- 21、[迭代中]任务结果丢失处理:针对长期处于运行中的任务(设置过期时间时,运行超过"过期时间+1min";未设置超时时间时,运行超过"30min"),主动检测该执行器是否在线,如果不在线主动标记失败;

@ -11,9 +11,11 @@ import com.xxl.job.core.enums.RegistryConfig;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
/**
@ -33,14 +35,28 @@ public class JobGroupController {
@RequestMapping
public String index(Model model) {
// job group (executor)
List<XxlJobGroup> list = xxlJobGroupDao.findAll();
model.addAttribute("list", list);
return "jobgroup/jobgroup.index";
}
@RequestMapping("/pageList")
@ResponseBody
public Map<String, Object> pageList(HttpServletRequest request,
@RequestParam(required = false, defaultValue = "0") int start,
@RequestParam(required = false, defaultValue = "10") int length,
String appName, String title) {
// page query
List<XxlJobGroup> list = xxlJobGroupDao.pageList(start, length, appName, title);
int list_count = xxlJobGroupDao.pageListCount(start, length, appName, title);
// package result
Map<String, Object> maps = new HashMap<String, Object>();
maps.put("recordsTotal", list_count); // 总记录数
maps.put("recordsFiltered", list_count); // 过滤后的总记录数
maps.put("data", list); // 分页列表
return maps;
}
@RequestMapping("/save")
@ResponseBody
public ReturnT<String> save(XxlJobGroup xxlJobGroup){

@ -12,7 +12,6 @@ public class XxlJobGroup {
private int id;
private String appName;
private String title;
private int order;
private int addressType; // 执行器地址类型:0=自动注册、1=手动录入
private String addressList; // 执行器地址列表,多地址逗号分隔(手动录入)
@ -49,14 +48,6 @@ public class XxlJobGroup {
this.title = title;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public int getAddressType() {
return addressType;
}

@ -23,4 +23,15 @@ public interface XxlJobGroupDao {
public int remove(@Param("id") int id);
public XxlJobGroup load(@Param("id") int id);
public List<XxlJobGroup> pageList(@Param("offset") int offset,
@Param("pagesize") int pagesize,
@Param("appName") String appName,
@Param("title") String title);
public int pageListCount(@Param("offset") int offset,
@Param("pagesize") int pagesize,
@Param("appName") String appName,
@Param("title") String title);
}

@ -189,7 +189,6 @@ jobgroup_list=Executor List
jobgroup_add=Add Executor
jobgroup_edit=Edit Executor
jobgroup_del=Delete Executor
jobgroup_field_order=Order
jobgroup_field_title=Title
jobgroup_field_addressType=Registry Type
jobgroup_field_addressType_0=Automatic registration

@ -189,7 +189,6 @@ jobgroup_list=执行器列表
jobgroup_add=新增执行器
jobgroup_edit=编辑执行器
jobgroup_del=删除执行器
jobgroup_field_order=排序
jobgroup_field_title=名称
jobgroup_field_addressType=注册方式
jobgroup_field_addressType_0=自动注册

@ -189,7 +189,6 @@ jobgroup_list=執行器列表
jobgroup_add=新增執行器
jobgroup_edit=編輯執行器
jobgroup_del=刪除執行器
jobgroup_field_order=排序
jobgroup_field_title=名稱
jobgroup_field_addressType=注冊方式
jobgroup_field_addressType_0=自動注冊

@ -7,7 +7,6 @@
<result column="id" property="id" />
<result column="app_name" property="appName" />
<result column="title" property="title" />
<result column="order" property="order" />
<result column="address_type" property="addressType" />
<result column="address_list" property="addressList" />
</resultMap>
@ -16,7 +15,6 @@
t.id,
t.app_name,
t.title,
t.`order`,
t.address_type,
t.address_list
</sql>
@ -24,26 +22,25 @@
<select id="findAll" resultMap="XxlJobGroup">
SELECT <include refid="Base_Column_List" />
FROM xxl_job_group AS t
ORDER BY t.order ASC
ORDER BY t.app_name, t.title, t.id ASC
</select>
<select id="findByAddressType" parameterType="java.lang.Integer" resultMap="XxlJobGroup">
SELECT <include refid="Base_Column_List" />
FROM xxl_job_group AS t
WHERE t.address_type = #{addressType}
ORDER BY t.order ASC
ORDER BY t.app_name, t.title, t.id ASC
</select>
<insert id="save" parameterType="com.xxl.job.admin.core.model.XxlJobGroup" useGeneratedKeys="true" keyProperty="id" >
INSERT INTO xxl_job_group ( `app_name`, `title`, `order`, `address_type`, `address_list`)
values ( #{appName}, #{title}, #{order}, #{addressType}, #{addressList});
INSERT INTO xxl_job_group ( `app_name`, `title`, `address_type`, `address_list`)
values ( #{appName}, #{title}, #{addressType}, #{addressList});
</insert>
<update id="update" parameterType="com.xxl.job.admin.core.model.XxlJobGroup" >
UPDATE xxl_job_group
SET `app_name` = #{appName},
`title` = #{title},
`order` = #{order},
`address_type` = #{addressType},
`address_list` = #{addressList}
WHERE id = #{id}
@ -60,4 +57,32 @@
WHERE t.id = #{id}
</select>
<select id="pageList" parameterType="java.util.HashMap" resultMap="XxlJobGroup">
SELECT <include refid="Base_Column_List" />
FROM xxl_job_group AS t
<trim prefix="WHERE" prefixOverrides="AND | OR" >
<if test="appName != null and appName != ''">
AND t.app_name like CONCAT(CONCAT('%', #{appName}), '%')
</if>
<if test="title != null and title != ''">
AND t.title like CONCAT(CONCAT('%', #{title}), '%')
</if>
</trim>
ORDER BY t.app_name, t.title, t.id ASC
LIMIT #{offset}, #{pagesize}
</select>
<select id="pageListCount" parameterType="java.util.HashMap" resultType="int">
SELECT count(1)
FROM xxl_job_group AS t
<trim prefix="WHERE" prefixOverrides="AND | OR" >
<if test="appName != null and appName != ''">
AND t.app_name like CONCAT(CONCAT('%', #{appName}), '%')
</if>
<if test="title != null and title != ''">
AND t.title like CONCAT(CONCAT('%', #{title}), '%')
</if>
</trim>
</select>
</mapper>

@ -1,13 +1,153 @@
$(function() {
// remove
$('.remove').on('click', function(){
var id = $(this).attr('id');
// init date tables
var jobGroupTable = $("#jobgroup_list").dataTable({
"deferRender": true,
"processing" : true,
"serverSide": true,
"ajax": {
url: base_url + "/jobgroup/pageList",
type:"post",
data : function ( d ) {
var obj = {};
obj.appName = $('#appName').val();
obj.title = $('#title').val();
obj.start = d.start;
obj.length = d.length;
return obj;
}
},
"searching": false,
"ordering": false,
//"scrollX": true, // scroll x,close self-adaption
"columns": [
{
"data": 'id',
"visible" : false
},
{
"data": 'appName',
"visible" : true,
"width":'30%'
},
{
"data": 'title',
"visible" : true,
"width":'30%'
},
{
"data": 'addressType',
"width":'10%',
"visible" : true,
"render": function ( data, type, row ) {
if (row.addressType == 0) {
return I18n.jobgroup_field_addressType_0;
} else {
return I18n.jobgroup_field_addressType_1;
}
}
},
{
"data": 'registryList',
"width":'15%',
"visible" : true,
"render": function ( data, type, row ) {
return row.registryList
?'<a class="show_registryList" href="javascript:;" _id="'+ row.id +'" >'
+ I18n.system_show +' ( ' + row.registryList.length+ ' </a>'
:I18n.system_empty;
}
},
{
"data": I18n.system_opt ,
"width":'15%',
"render": function ( data, type, row ) {
return function(){
// data
tableData['key'+row.id] = row;
// opt
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" role="menu" _id="'+ row.id +'" >\n' +
' <li><a href="javascript:void(0);" class="opt_edit" >'+ I18n.system_opt_edit +'</a></li>\n' +
' <li><a href="javascript:void(0);" class="opt_del" >'+ I18n.system_opt_del +'</a></li>\n' +
' </ul>\n' +
' </div>';
return html;
};
}
}
],
"language" : {
"sProcessing" : I18n.dataTable_sProcessing ,
"sLengthMenu" : I18n.dataTable_sLengthMenu ,
"sZeroRecords" : I18n.dataTable_sZeroRecords ,
"sInfo" : I18n.dataTable_sInfo ,
"sInfoEmpty" : I18n.dataTable_sInfoEmpty ,
"sInfoFiltered" : I18n.dataTable_sInfoFiltered ,
"sInfoPostFix" : "",
"sSearch" : I18n.dataTable_sSearch ,
"sUrl" : "",
"sEmptyTable" : I18n.dataTable_sEmptyTable ,
"sLoadingRecords" : I18n.dataTable_sLoadingRecords ,
"sInfoThousands" : ",",
"oPaginate" : {
"sFirst" : I18n.dataTable_sFirst ,
"sPrevious" : I18n.dataTable_sPrevious ,
"sNext" : I18n.dataTable_sNext ,
"sLast" : I18n.dataTable_sLast
},
"oAria" : {
"sSortAscending" : I18n.dataTable_sSortAscending ,
"sSortDescending" : I18n.dataTable_sSortDescending
}
}
});
// table data
var tableData = {};
// search btn
$('#searchBtn').on('click', function(){
jobGroupTable.fnDraw();
});
// job registryinfo
$("#jobgroup_list").on('click', '.show_registryList',function() {
var id = $(this).attr("_id");
var row = tableData['key'+id];
var html = '<center>';
if (row.registryList) {
for (var index in row.registryList) {
html += '<span class="badge bg-green" >' + row.registryList[index] + '</span><br>';
}
}
html += '</center>';
layer.open({
title: I18n.jobinfo_opt_registryinfo ,
btn: [ I18n.system_ok ],
content: html
});
});
// opt_del
$("#jobgroup_list").on('click', '.opt_del',function() {
var id = $(this).parents('ul').attr("_id");
layer.confirm( (I18n.system_ok + I18n.jobgroup_del + '?') , {
icon: 3,
title: I18n.system_tips ,
btn: [ I18n.system_ok, I18n.system_cancel ]
btn: [ I18n.system_ok, I18n.system_cancel ]
}, function(index){
layer.close(index);
@ -20,17 +160,17 @@ $(function() {
if (data.code == 200) {
layer.open({
title: I18n.system_tips ,
btn: [ I18n.system_ok ],
btn: [ I18n.system_ok ],
content: (I18n.jobgroup_del + I18n.system_success),
icon: '1',
end: function(layero, index){
window.location.reload();
jobGroupTable.fnDraw();
}
});
} else {
layer.open({
title: I18n.system_tips,
btn: [ I18n.system_ok ],
btn: [ I18n.system_ok ],
content: (data.msg || (I18n.jobgroup_del + I18n.system_fail)),
icon: '2'
});
@ -38,9 +178,9 @@ $(function() {
},
});
});
});
// jquery.validate “low letters start, limit contants、 letters、numbers and line-through.”
jQuery.validator.addMethod("myValid01", function(value, element) {
var length = value.length;
@ -64,11 +204,6 @@ $(function() {
title : {
required : true,
rangelength:[4, 12]
},
order : {
required : true,
digits:true,
range:[1,1000]
}
},
messages : {
@ -80,11 +215,6 @@ $(function() {
title : {
required : I18n.system_please_input + I18n.jobgroup_field_title ,
rangelength: I18n.jobgroup_field_title_length
},
order : {
required : I18n.system_please_input + I18n.jobgroup_field_order ,
digits: I18n.jobgroup_field_order_digits ,
range: I18n.jobgroup_field_orderrange
}
},
highlight : function(element) {
@ -107,7 +237,7 @@ $(function() {
content: I18n.system_add_suc ,
icon: '1',
end: function(layero, index){
window.location.reload();
jobGroupTable.fnDraw();
}
});
} else {
@ -141,20 +271,20 @@ $(function() {
}
});
// update
$('.update').on('click', function(){
$("#updateModal .form input[name='id']").val($(this).attr("id"));
$("#updateModal .form input[name='appName']").val($(this).attr("appName"));
$("#updateModal .form input[name='title']").val($(this).attr("title"));
$("#updateModal .form input[name='order']").val($(this).attr("order"));
// opt_edit
$("#jobgroup_list").on('click', '.opt_edit',function() {
var id = $(this).parents('ul').attr("_id");
var row = tableData['key'+id];
$("#updateModal .form input[name='id']").val( row.id );
$("#updateModal .form input[name='appName']").val( row.appName );
$("#updateModal .form input[name='title']").val( row.title );
// 注册方式
var addressType = $(this).attr("addressType");
$("#updateModal .form input[name='addressType']").removeAttr('checked');
//$("#updateModal .form input[name='addressType'][value='"+ addressType +"']").attr('checked', 'true');
$("#updateModal .form input[name='addressType'][value='"+ addressType +"']").click();
$("#updateModal .form input[name='addressType'][value='"+ row.addressType +"']").click();
// 机器地址
$("#updateModal .form textarea[name='addressList']").val($(this).attr("addressList"));
$("#updateModal .form textarea[name='addressList']").val( row.addressList );
$('#updateModal').modal({backdrop: false, keyboard: false}).modal('show');
});
@ -171,11 +301,6 @@ $(function() {
title : {
required : true,
rangelength:[4, 12]
},
order : {
required : true,
digits:true,
range:[1,1000]
}
},
messages : {
@ -187,11 +312,6 @@ $(function() {
title : {
required : I18n.system_please_input + I18n.jobgroup_field_title ,
rangelength: I18n.jobgroup_field_title_length
},
order : {
required : I18n.system_please_input + I18n.jobgroup_field_order ,
digits: I18n.jobgroup_field_order_digits ,
range: I18n.jobgroup_field_orderrange
}
},
highlight : function(element) {
@ -207,7 +327,7 @@ $(function() {
submitHandler : function(form) {
$.post(base_url + "/jobgroup/update", $("#updateModal .form").serialize(), function(data, status) {
if (data.code == "200") {
$('#addModal').modal('hide');
$('#updateModal').modal('hide');
layer.open({
title: I18n.system_tips ,
@ -215,7 +335,7 @@ $(function() {
content: I18n.system_update_suc ,
icon: '1',
end: function(layero, index){
window.location.reload();
jobGroupTable.fnDraw();
}
});
} else {

@ -23,63 +23,44 @@
<!-- Main content -->
<section class="content">
<div class="row">
<div class="col-xs-3">
<div class="input-group">
<span class="input-group-addon">AppName</span>
<input type="text" class="form-control" id="appName" autocomplete="on" placeholder="${I18n.system_please_input}AppName" >
</div>
</div>
<div class="col-xs-3">
<div class="input-group">
<span class="input-group-addon">${I18n.jobgroup_field_title}</span>
<input type="text" class="form-control" id="title" autocomplete="on" placeholder="${I18n.jobgroup_field_title}JobHandler" >
</div>
</div>
<div class="col-xs-2">
<button class="btn btn-block btn-info" id="searchBtn">${I18n.system_search}</button>
</div>
<div class="col-xs-2">
<button class="btn btn-block btn-success add" type="button">${I18n.jobinfo_field_add}</button>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="box">
<div class="box-header">
<h3 class="box-title">${I18n.jobgroup_list}</h3>&nbsp;&nbsp;
<button class="btn btn-info btn-xs pull-left2 add" >${I18n.jobgroup_add}</button>
</div>
<div class="box-body">
<table id="joblog_list" class="table table-bordered table-striped display" width="100%" >
<table id="jobgroup_list" class="table table-bordered table-striped display" width="100%" >
<thead>
<tr>
<#--<th name="id" >ID</th>-->
<th name="order" >${I18n.jobgroup_field_order}</th>
<th name="id" >ID</th>
<th name="appName" >AppName</th>
<th name="title" >${I18n.jobgroup_field_title}</th>
<th name="addressType" >${I18n.jobgroup_field_addressType}</th>
<th name="registryList" >OnLine ${I18n.jobgroup_field_registryList}</th>
<th name="operate" >${I18n.system_opt}</th>
<th>${I18n.system_opt}</th>
</tr>
</thead>
<tbody>
<#if list?exists && list?size gt 0>
<#list list as group>
<tr>
<#--<td>${group.id}</td>-->
<td>${group.order}</td>
<td>${group.appName}</td>
<td>${group.title}</td>
<td><#if group.addressType==0>${I18n.jobgroup_field_addressType_0}<#else>${I18n.jobgroup_field_addressType_1}</#if></td>
<td>
<#if group.registryList?exists>
<#list group.registryList as item>
<span class="badge bg-green" title="${item}" >
<#if item?length gt 35>
${item?substring(0, 35)}...
<#else>
${item}
</#if>
</span>
<br>
</#list>
</#if>
</td>
<td>
<button class="btn btn-warning btn-xs update"
id="${group.id}"
appName="${group.appName}"
title="${group.title}"
order="${group.order}"
addressType="${group.addressType}"
addressList="${group.addressList!}" >${I18n.system_opt_edit}</button>
<button class="btn btn-danger btn-xs remove" id="${group.id}" >${I18n.system_opt_del}</button>
</td>
</tr>
</#list>
</#if>
</tbody>
</table>
</div>
@ -106,10 +87,6 @@
<label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_title}<font color="red">*</font></label>
<div class="col-sm-10"><input type="text" class="form-control" name="title" placeholder="${I18n.system_please_input}${I18n.jobgroup_field_title}" maxlength="12" ></div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_order}<font color="red">*</font></label>
<div class="col-sm-10"><input type="text" class="form-control" name="order" placeholder="${I18n.system_please_input}${I18n.jobgroup_field_order}" maxlength="50" ></div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_addressType}<font color="red">*</font></label>
<div class="col-sm-10">
@ -154,10 +131,6 @@
<label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_title}<font color="red">*</font></label>
<div class="col-sm-10"><input type="text" class="form-control" name="title" placeholder="${I18n.system_please_input}${I18n.jobgroup_field_title}" maxlength="12" ></div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_order}<font color="red">*</font></label>
<div class="col-sm-10"><input type="text" class="form-control" name="order" placeholder="${I18n.system_please_input}${I18n.jobgroup_field_order}" maxlength="50" ></div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_addressType}<font color="red">*</font></label>
<div class="col-sm-10">

@ -1,12 +1,9 @@
package com.xxl.job.admin.dao;
import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.dao.XxlJobGroupDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
@ -28,7 +25,6 @@ public class XxlJobGroupDaoTest {
XxlJobGroup group = new XxlJobGroup();
group.setAppName("setAppName");
group.setTitle("setTitle");
group.setOrder(1);
group.setAddressType(0);
group.setAddressList("setAddressList");
@ -37,7 +33,6 @@ public class XxlJobGroupDaoTest {
XxlJobGroup group2 = xxlJobGroupDao.load(group.getId());
group2.setAppName("setAppName2");
group2.setTitle("setTitle2");
group2.setOrder(2);
group2.setAddressType(2);
group2.setAddressList("setAddressList2");

Loading…
Cancel
Save