feat(timer): 新增定时器配置、日志和主机的后台管理界面

T10: TimerConfig CURD - task management with run_type/status editing,
     manual trigger button, task_name read-only, no add/delete
T11: TimerLog CURD - read-only log viewer with filters and color badges
T12: Host list enhanced - is_master column, setMaster button
This commit is contained in:
augushong
2026-05-26 02:50:40 +08:00
parent 25fab093fa
commit 90e584f5a1
23 changed files with 943 additions and 18 deletions

View File

@@ -0,0 +1,12 @@
var init = {
tableElem: '#currentTable',
tableRenderId: 'currentTableRenderId',
indexUrl: 'system.timer_config/index',
addUrl: 'system.timer_config/add' + location.search,
editUrl: 'system.timer_config/edit',
readUrl: 'system.timer_config/read',
deleteUrl: 'system.timer_config/delete',
exportUrl: 'system.timer_config/export',
modifyUrl: 'system.timer_config/modify',
triggerUrl: 'system.timer_config/trigger',
};

View File

@@ -0,0 +1,70 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label">任务名称</label>
<div class="layui-input-block">
<input type="text" name="task_name" class="layui-input" lay-verify="required" placeholder="请输入任务名称" value="{$Request.param.task_name|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">运行类型:main/auto/all/manual</label>
<div class="layui-input-block">
<select name="run_type" >
<option value=''></option>
{foreach $select_list_run_type as $k=>$v}
<option value='{$k}' {in name="k" value="$Request.param.run_type"}selected=""{/in}>{$v}</option>
{/foreach}
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态:0=停用,1=启用</label>
<div class="layui-input-block">
{foreach $select_list_status as $k=>$v}
<input type="radio" name="status" value="{$k}" title="{$v}" {in name="k" value="$Request.param.status"}checked=""{/in}>
{/foreach}
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">是否已同步:0=未同步,1=已同步</label>
<div class="layui-input-block">
{foreach $select_list_is_synced as $k=>$v}
<input type="radio" name="is_synced" value="{$k}" title="{$v}" {in name="k" value="$Request.param.is_synced"}checked=""{/in}>
{/foreach}
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">最后执行节点ID</label>
<div class="layui-input-block">
<input type="text" name="last_execute_node" class="layui-input" placeholder="请输入最后执行节点ID" value="{$Request.param.last_execute_node|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">最后执行时间戳</label>
<div class="layui-input-block">
<input type="text" name="last_execute_time" data-date="" data-date-type="datetime" class="layui-input" placeholder="请输入最后执行时间戳" value="{$Request.param.last_execute_time|default='0'}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">手动触发标记:0=未触发,1=已触发</label>
<div class="layui-input-block">
{foreach $select_list_manual_trigger as $k=>$v}
<input type="radio" name="manual_trigger" value="{$k}" title="{$v}" {in name="k" value="$Request.param.manual_trigger"}checked=""{/in}>
{/foreach}
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
{notempty name='$Request.param.backTagId'}
<div class="layui-btn layui-btn-sm page-back-button" layuimini-content-href="{$Request.param.backTagId}" data-back="1">返回</div>
{/notempty}
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

View File

@@ -0,0 +1,3 @@
$(function(){
ua.listen();
})

View File

@@ -0,0 +1,69 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label">任务名称</label>
<div class="layui-input-block">
<input type="text" name="task_name" class="layui-input layui-disabled" disabled value="{$row.task_name|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">运行类型</label>
<div class="layui-input-block">
<select name="run_type" lay-verify="required">
<option value=''></option>
{foreach $select_list_run_type as $k=>$v}
<option value='{$k}' {in name="k" value="$row.run_type"}selected=""{/in}>{$v}</option>
{/foreach}
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
{foreach $select_list_status as $k=>$v}
<input type="radio" name="status" value="{$k}" title="{$v}" {in name="k" value="$row.status"}checked=""{/in}>
{/foreach}
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">同步状态</label>
<div class="layui-input-block" style="padding-top: 8px;">
{if $row.is_synced == 1}
<span class="layui-badge layui-bg-green">已同步</span>
{else/}
<span class="layui-badge">未同步</span>
{/if}
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">最后执行节点</label>
<div class="layui-input-block" style="padding-top: 8px;">
{$row.last_execute_node|default='<span class="layui-text-em">暂无</span>'}
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">最后执行时间</label>
<div class="layui-input-block" style="padding-top: 8px;">
{notempty name="row.last_execute_time"}
{$row.last_execute_time|date="Y-m-d H:i:s"}
{else/}
<span class="layui-text-em">暂无</span>
{/notempty}
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
{notempty name='$Request.param.backTagId'}
<div class="layui-btn layui-btn-sm page-back-button" layuimini-content-href="{$Request.param.backTagId}" data-back="1">返回</div>
{/notempty}
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

View File

@@ -0,0 +1,3 @@
$(function(){
ua.listen();
})

View File

@@ -0,0 +1,11 @@
<div class="layuimini-container">
<div class="layuimini-main">
<table id="currentTable" class="layui-table layui-hide"
data-auth-index="{:auth('system.timer_config/index')}"
data-auth-edit="{:auth('system.timer_config/edit')}"
data-auth-export="{:auth('system.timer_config/export')}"
data-auth-modify="{:auth('system.timer_config/modify')}"
lay-filter="currentTable">
</table>
</div>
</div>

View File

@@ -0,0 +1,78 @@
$(function(){
ua.table.render({
init: init,
cols: [[
{type: 'checkbox'},
{field: 'id', title: 'ID', width: 80},
{field: 'task_name', title: '任务名称', minWidth: 160},
{field: 'run_type', search: 'select', selectList: ua.getDataBrage('select_list_run_type'), title: '运行类型', width: 130, templet: function(d){
var map = ua.getDataBrage('select_list_run_type');
return map[d.run_type] || d.run_type;
}},
{field: 'status', search: 'select', selectList: ua.getDataBrage('select_list_status'), title: '状态', width: 100, templet: ua.table.switch},
{field: 'is_synced', search: 'select', selectList: ua.getDataBrage('select_list_is_synced'), title: '同步状态', width: 100, templet: function(d){
if(d.is_synced == 1){
return '<span class="layui-badge layui-bg-green">已同步</span>';
}
return '<span class="layui-badge">未同步</span>';
}},
{field: 'last_execute_node', title: '最后执行节点', width: 140},
{field: 'last_execute_time', title: '最后执行时间', width: 170, templet: function(d){
if(!d.last_execute_time || d.last_execute_time == 0){
return '<span class="layui-text-em">暂无</span>';
}
var date = new Date(d.last_execute_time * 1000);
var Y = date.getFullYear();
var m = ('0' + (date.getMonth()+1)).slice(-2);
var day = ('0' + date.getDate()).slice(-2);
var H = ('0' + date.getHours()).slice(-2);
var i = ('0' + date.getMinutes()).slice(-2);
var s = ('0' + date.getSeconds()).slice(-2);
return Y+'-'+m+'-'+day+' '+H+':'+i+':'+s;
}},
{
width: 200, title: '操作', templet: ua.table.tool, fixed: 'right', operat: [
[{
class: 'layui-btn layui-btn-primary layui-btn-xs',
method: 'tab',
field: 'id',
text: '详情',
title: '查看详情',
auth: 'read',
url: init.readUrl,
icon: ''
}],
'edit',
[{
class: 'layui-btn layui-btn-warm layui-btn-xs',
method: 'request',
field: 'id',
text: '触发',
title: '手动触发',
auth: 'trigger',
url: init.triggerUrl,
icon: '',
extend: '',
callback: function(o){
// 只对 manual 类型显示,通过 CSS 控制显隐
}
}]
]
},
]],
});
// 控制触发按钮显隐:只有 run_type=manual 时显示
ua.listen();
// 监听表格渲染完成后处理触发按钮显隐
$(document).on('renderComplete', function(){
$('table tbody tr').each(function(){
var runType = $(this).find('td[data-field="run_type"] .layui-table-cell').text().trim();
if(runType !== 'manual'){
$(this).find('.layui-btn[title="手动触发"]').hide();
}
});
});
})

View File

@@ -0,0 +1,103 @@
<div class="layuimini-container detail-container">
<div class="layuimini-main">
<div class="layui-card detail-card">
<div class="layui-card-header detail-header">
<div class="layui-row">
<div class="layui-col-md9">
<h2 class="detail-title">#{$row.id} {$title}</h2>
<div class="detail-id">ID: {$row.id}</div>
</div>
<div class="layui-col-md3 text-right detail-actions">
<button class="layui-btn layui-btn-primary" layuimini-content-href="{$Request.param.backTagId}" data-back="1">返回</button>
<button class="layui-btn" onclick="location.href='{:url("edit", ["id" => $row.id])}'">编辑</button>
</div>
</div>
</div>
<div class="layui-card-body detail-content">
<div class="layui-row layui-col-space12">
<div class="layui-col-md8 detail-main">
<div class="detail-field-group">
<div class="detail-field-item">
<div class="detail-field-label">任务名称</div>
<div class="detail-field-value">
{notempty name="row.task_name"}
{$row.task_name}
{else/}
<span class="layui-text-em">暂无数据</span>
{/notempty}
</div>
</div>
<div class="detail-field-item">
<div class="detail-field-label">运行类型</div>
<div class="detail-field-value">
{$select_list_run_type[$row.run_type]|default=''}
</div>
</div>
<div class="detail-field-item">
<div class="detail-field-label">同步状态</div>
<div class="detail-field-value">
{if $row.is_synced == 1}
<span class="layui-badge layui-bg-green">已同步</span>
{else/}
<span class="layui-badge">未同步</span>
{/if}
</div>
</div>
<div class="detail-field-item">
<div class="detail-field-label">最后执行节点</div>
<div class="detail-field-value">
{notempty name="row.last_execute_node"}
{$row.last_execute_node}
{else/}
<span class="layui-text-em">暂无数据</span>
{/notempty}
</div>
</div>
<div class="detail-field-item">
<div class="detail-field-label">最后执行时间</div>
<div class="detail-field-value">
{notempty name="row.last_execute_time"}
{$row.last_execute_time|date="Y-m-d H:i:s"}
{else/}
<span class="layui-text-em">暂无数据</span>
{/notempty}
</div>
</div>
<div class="detail-field-item">
<div class="detail-field-label">手动触发标记</div>
<div class="detail-field-value">
<span class="layui-badge">{$select_list_manual_trigger[$row.manual_trigger]|default=''}</span>
</div>
</div>
</div>
</div>
<div class="layui-col-md4 detail-side">
<h3 class="detail-side-title">基础信息</h3>
<div class="detail-field-group">
<div class="detail-field-item">
<div class="detail-field-label">ID</div>
<div class="detail-field-value">{$row.id}</div>
</div>
<div class="detail-field-item">
<div class="detail-field-label">状态</div>
<div class="detail-field-value">
<span class="layui-badge">{$select_list_status[$row.status]|default=''}</span>
</div>
</div>
<div class="detail-field-item">
<div class="detail-field-label">创建时间</div>
<div class="detail-field-value">
{notempty name="row.create_time"}
{$row.create_time|date="Y-m-d H:i:s"}
{else/}
<span class="layui-text-em">暂无数据</span>
{/notempty}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,3 @@
$(function(){
ua.listen();
})