From 90e584f5a19892f17d2a8714ea76db95befb3157 Mon Sep 17 00:00:00 2001 From: augushong Date: Tue, 26 May 2026 02:50:40 +0800 Subject: [PATCH] =?UTF-8?q?feat(timer):=20=E6=96=B0=E5=A2=9E=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E5=99=A8=E9=85=8D=E7=BD=AE=E3=80=81=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E5=92=8C=E4=B8=BB=E6=9C=BA=E7=9A=84=E5=90=8E=E5=8F=B0=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- app/admin/controller/system/TimerConfig.php | 97 ++++++++++++ app/admin/controller/system/TimerLog.php | 109 ++++++++++++++ app/admin/model/SystemTimerConfig.php | 33 ++++- app/admin/model/SystemTimerLog.php | 27 +++- app/admin/view/system/timer_config/_common.js | 12 ++ app/admin/view/system/timer_config/add.html | 70 +++++++++ app/admin/view/system/timer_config/add.js | 3 + app/admin/view/system/timer_config/edit.html | 69 +++++++++ app/admin/view/system/timer_config/edit.js | 3 + app/admin/view/system/timer_config/index.html | 11 ++ app/admin/view/system/timer_config/index.js | 78 ++++++++++ app/admin/view/system/timer_config/read.html | 103 +++++++++++++ app/admin/view/system/timer_config/read.js | 3 + app/admin/view/system/timer_log/_common.js | 11 ++ app/admin/view/system/timer_log/index.html | 9 ++ app/admin/view/system/timer_log/index.js | 99 +++++++++++++ app/admin/view/system/timer_log/read.html | 139 ++++++++++++++++++ app/admin/view/system/timer_log/read.js | 3 + .../base/admin/controller/system/HostBase.php | 21 +++ extend/base/admin/model/SystemHostBase.php | 2 + extend/base/admin/view/system/host/_common.js | 1 + extend/base/admin/view/system/host/index.html | 1 + extend/base/admin/view/system/host/index.js | 57 +++++-- 23 files changed, 943 insertions(+), 18 deletions(-) create mode 100644 app/admin/controller/system/TimerConfig.php create mode 100644 app/admin/controller/system/TimerLog.php create mode 100644 app/admin/view/system/timer_config/_common.js create mode 100644 app/admin/view/system/timer_config/add.html create mode 100644 app/admin/view/system/timer_config/add.js create mode 100644 app/admin/view/system/timer_config/edit.html create mode 100644 app/admin/view/system/timer_config/edit.js create mode 100644 app/admin/view/system/timer_config/index.html create mode 100644 app/admin/view/system/timer_config/index.js create mode 100644 app/admin/view/system/timer_config/read.html create mode 100644 app/admin/view/system/timer_config/read.js create mode 100644 app/admin/view/system/timer_log/_common.js create mode 100644 app/admin/view/system/timer_log/index.html create mode 100644 app/admin/view/system/timer_log/index.js create mode 100644 app/admin/view/system/timer_log/read.html create mode 100644 app/admin/view/system/timer_log/read.js diff --git a/app/admin/controller/system/TimerConfig.php b/app/admin/controller/system/TimerConfig.php new file mode 100644 index 0000000..b38859b --- /dev/null +++ b/app/admin/controller/system/TimerConfig.php @@ -0,0 +1,97 @@ +model = new \app\admin\model\SystemTimerConfig(); + + $this->assign('select_list_run_type', $this->model::SELECT_LIST_RUN_TYPE, true); + $this->assign('select_list_status', $this->model::SELECT_LIST_STATUS, true); + $this->assign('select_list_is_synced', $this->model::SELECT_LIST_IS_SYNCED, true); + $this->assign('select_list_manual_trigger', $this->model::SELECT_LIST_MANUAL_TRIGGER, true); + + // 允许通过行内修改的字段 + $this->allowModifyFields = [ + 'status', + 'run_type', + ]; + } + + /** + * @NodeAnotation(title="添加") + */ + public function add() + { + $this->error('定时任务配置由系统同步生成,不支持手动添加'); + } + + /** + * @NodeAnotation(title="删除") + */ + public function delete($id) + { + $this->error('定时任务配置由系统管理,不支持删除'); + } + + /** + * @NodeAnotation(title="编辑") + */ + public function edit($id) + { + $row = $this->model->find($id); + empty($row) && $this->error('数据不存在'); + if ($this->request->isPost()) { + $post = $this->request->post(); + // 只允许修改 run_type 和 status + $post = array_intersect_key($post, array_flip(['run_type', 'status'])); + try { + $save = $row->save($post); + } catch (\Exception $e) { + $this->error('保存失败:' . $e->getMessage()); + } + $save ? $this->success('保存成功') : $this->error('保存失败'); + } + $this->assign('row', $row); + + return $this->fetch(); + } + + /** + * @NodeAnotation(title="手动触发") + */ + public function trigger($id) + { + $this->checkPostRequest(); + $row = $this->model->find($id); + if (!$row) { + $this->error('数据不存在'); + } + if ($row->getAttr('run_type') !== 'manual') { + $this->error('只有manual类型的任务支持手动触发'); + } + if ($row->getAttr('status') != 1) { + $this->error('任务已停用,请先启用'); + } + try { + $row->save(['manual_trigger' => 1]); + } catch (\Exception $e) { + $this->error('触发失败:' . $e->getMessage()); + } + $this->success('触发成功,等待定时器执行'); + } +} diff --git a/app/admin/controller/system/TimerLog.php b/app/admin/controller/system/TimerLog.php new file mode 100644 index 0000000..820a37b --- /dev/null +++ b/app/admin/controller/system/TimerLog.php @@ -0,0 +1,109 @@ + 'desc', + ]; + + public function __construct(App $app) + { + parent::__construct($app); + + $this->model = new \app\admin\model\SystemTimerLog(); + } + + /** + * @NodeAnotation(title="列表") + */ + public function index() + { + if ($this->request->isAjax()) { + if (input('selectFields')) { + return $this->selectList(); + } + list($page, $limit, $where, $excludes, $request_options, $group) = $this->buildTableParames(); + $count = $this->model + ->where($where) + ->group($group) + ->count(); + $list = $this->model + ->where($where) + ->page($page, $limit) + ->order($this->sort) + ->group($group) + ->select(); + $data = [ + 'code' => 0, + 'msg' => '', + 'count' => $count, + 'data' => $list, + ]; + + return json($data); + } + + return $this->fetch(); + } + + /** + * @NodeAnotation(title="详情") + */ + public function read($id) + { + $row = $this->model->find($id); + empty($row) && $this->error('数据不存在'); + + $title = $row->title; + + $this->assign('row', $row); + $this->assign('title', $title); + + return $this->fetch(); + } + + /** + * @NodeAnotation(title="添加") + */ + public function add() + { + $this->error('日志表不允许手动添加'); + } + + /** + * @NodeAnotation(title="编辑") + */ + public function edit($id) + { + $this->error('日志表不允许编辑'); + } + + /** + * @NodeAnotation(title="删除") + */ + public function delete($id) + { + $this->error('日志表不允许删除'); + } + + /** + * @NodeAnotation(title="属性修改") + */ + public function modify() + { + $this->error('日志表不允许修改'); + } +} diff --git a/app/admin/model/SystemTimerConfig.php b/app/admin/model/SystemTimerConfig.php index c32d62a..7f2dd3c 100644 --- a/app/admin/model/SystemTimerConfig.php +++ b/app/admin/model/SystemTimerConfig.php @@ -2,11 +2,36 @@ namespace app\admin\model; -use think\Model; +use app\common\model\TimeModel; -class SystemTimerConfig extends Model +/** + * @property int $id + * @property string $task_name 任务名称 + * @property string $run_type 运行类型:main/auto/all/manual main:main,auto:auto,all:all,manual:manual + * @property int $status 状态:0=停用,1=启用 0:停用,1:启用 + * @property int $is_synced 是否已同步:0=未同步,1=已同步 0:未同步,1:已同步 + * @property string $last_execute_node 最后执行节点ID + * @property int $last_execute_time 最后执行时间戳 + * @property int $manual_trigger 手动触发标记:0=未触发,1=已触发 0:未触发,1:已触发 + * @property int $create_time 创建时间 + */ +class SystemTimerConfig extends TimeModel { - protected $name = 'system_timer_config'; - protected $autoWriteTimestamp = true; + protected $name = "system_timer_config"; + + protected $deleteTime = false; + + + public const SELECT_LIST_RUN_TYPE = ['main' => 'main', 'auto' => 'auto', 'all' => 'all', 'manual' => 'manual']; + + public const SELECT_LIST_STATUS = ['0' => '停用', '1' => '启用']; + + public const SELECT_LIST_IS_SYNCED = ['0' => '未同步', '1' => '已同步']; + + public const SELECT_LIST_MANUAL_TRIGGER = ['0' => '未触发', '1' => '已触发']; + + + + } diff --git a/app/admin/model/SystemTimerLog.php b/app/admin/model/SystemTimerLog.php index 2771d6c..221b720 100644 --- a/app/admin/model/SystemTimerLog.php +++ b/app/admin/model/SystemTimerLog.php @@ -2,11 +2,30 @@ namespace app\admin\model; -use think\Model; +use app\common\model\TimeModel; -class SystemTimerLog extends Model +/** + * @property int $id + * @property string $task_name 任务名称 + * @property string $node_id 执行节点ID + * @property string $run_type 运行类型 + * @property int $start_time 开始时间戳 + * @property int $end_time 结束时间戳 + * @property int $duration 耗时 + * @property string $status 状态:running/success/error + * @property string $error_message 错误信息 + * @property int $concurrency_id 并发分片ID + * @property int $create_time 创建时间 + */ +class SystemTimerLog extends TimeModel { - protected $name = 'system_timer_log'; - protected $autoWriteTimestamp = true; + protected $name = "system_timer_log"; + + protected $deleteTime = false; + + + + + } diff --git a/app/admin/view/system/timer_config/_common.js b/app/admin/view/system/timer_config/_common.js new file mode 100644 index 0000000..a9aa393 --- /dev/null +++ b/app/admin/view/system/timer_config/_common.js @@ -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', +}; diff --git a/app/admin/view/system/timer_config/add.html b/app/admin/view/system/timer_config/add.html new file mode 100644 index 0000000..eeee5ae --- /dev/null +++ b/app/admin/view/system/timer_config/add.html @@ -0,0 +1,70 @@ +
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ {foreach $select_list_status as $k=>$v} + + {/foreach} +
+
+ +
+ +
+ {foreach $select_list_is_synced as $k=>$v} + + {/foreach} +
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ {foreach $select_list_manual_trigger as $k=>$v} + + {/foreach} +
+
+ +
+
+ {notempty name='$Request.param.backTagId'} +
返回
+ {/notempty} + + +
+ +
+
\ No newline at end of file diff --git a/app/admin/view/system/timer_config/add.js b/app/admin/view/system/timer_config/add.js new file mode 100644 index 0000000..4a445e0 --- /dev/null +++ b/app/admin/view/system/timer_config/add.js @@ -0,0 +1,3 @@ +$(function(){ + ua.listen(); +}) \ No newline at end of file diff --git a/app/admin/view/system/timer_config/edit.html b/app/admin/view/system/timer_config/edit.html new file mode 100644 index 0000000..43e4852 --- /dev/null +++ b/app/admin/view/system/timer_config/edit.html @@ -0,0 +1,69 @@ +
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ {foreach $select_list_status as $k=>$v} + + {/foreach} +
+
+ +
+ +
+ {if $row.is_synced == 1} + 已同步 + {else/} + 未同步 + {/if} +
+
+ +
+ +
+ {$row.last_execute_node|default='暂无'} +
+
+ +
+ +
+ {notempty name="row.last_execute_time"} + {$row.last_execute_time|date="Y-m-d H:i:s"} + {else/} + 暂无 + {/notempty} +
+
+ +
+
+ {notempty name='$Request.param.backTagId'} +
返回
+ {/notempty} + + +
+ +
+
diff --git a/app/admin/view/system/timer_config/edit.js b/app/admin/view/system/timer_config/edit.js new file mode 100644 index 0000000..4a445e0 --- /dev/null +++ b/app/admin/view/system/timer_config/edit.js @@ -0,0 +1,3 @@ +$(function(){ + ua.listen(); +}) \ No newline at end of file diff --git a/app/admin/view/system/timer_config/index.html b/app/admin/view/system/timer_config/index.html new file mode 100644 index 0000000..e1a373d --- /dev/null +++ b/app/admin/view/system/timer_config/index.html @@ -0,0 +1,11 @@ +
+
+ +
+
+
diff --git a/app/admin/view/system/timer_config/index.js b/app/admin/view/system/timer_config/index.js new file mode 100644 index 0000000..748db9a --- /dev/null +++ b/app/admin/view/system/timer_config/index.js @@ -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 '已同步'; + } + return '未同步'; + }}, + {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 '暂无'; + } + 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(); + } + }); + }); +}) diff --git a/app/admin/view/system/timer_config/read.html b/app/admin/view/system/timer_config/read.html new file mode 100644 index 0000000..83c9987 --- /dev/null +++ b/app/admin/view/system/timer_config/read.html @@ -0,0 +1,103 @@ +
+
+
+
+
+
+

#{$row.id} {$title}

+
ID: {$row.id}
+
+
+ + +
+
+
+
+
+
+
+
+
任务名称
+
+ {notempty name="row.task_name"} + {$row.task_name} + {else/} + 暂无数据 + {/notempty} +
+
+
+
运行类型
+
+ {$select_list_run_type[$row.run_type]|default=''} +
+
+
+
同步状态
+
+ {if $row.is_synced == 1} + 已同步 + {else/} + 未同步 + {/if} +
+
+
+
最后执行节点
+
+ {notempty name="row.last_execute_node"} + {$row.last_execute_node} + {else/} + 暂无数据 + {/notempty} +
+
+
+
最后执行时间
+
+ {notempty name="row.last_execute_time"} + {$row.last_execute_time|date="Y-m-d H:i:s"} + {else/} + 暂无数据 + {/notempty} +
+
+
+
手动触发标记
+
+ {$select_list_manual_trigger[$row.manual_trigger]|default=''} +
+
+
+
+
+

基础信息

+
+
+
ID
+
{$row.id}
+
+
+
状态
+
+ {$select_list_status[$row.status]|default=''} +
+
+
+
创建时间
+
+ {notempty name="row.create_time"} + {$row.create_time|date="Y-m-d H:i:s"} + {else/} + 暂无数据 + {/notempty} +
+
+
+
+
+
+
+
+
diff --git a/app/admin/view/system/timer_config/read.js b/app/admin/view/system/timer_config/read.js new file mode 100644 index 0000000..81a35d4 --- /dev/null +++ b/app/admin/view/system/timer_config/read.js @@ -0,0 +1,3 @@ +$(function(){ + ua.listen(); +}) diff --git a/app/admin/view/system/timer_log/_common.js b/app/admin/view/system/timer_log/_common.js new file mode 100644 index 0000000..1c140a5 --- /dev/null +++ b/app/admin/view/system/timer_log/_common.js @@ -0,0 +1,11 @@ +var init = { + tableElem: '#currentTable', + tableRenderId: 'currentTableRenderId', + indexUrl: 'system.timer_log/index', + addUrl: '', + editUrl: '', + readUrl: 'system.timer_log/read', + deleteUrl: '', + exportUrl: '', + modifyUrl: '', +}; diff --git a/app/admin/view/system/timer_log/index.html b/app/admin/view/system/timer_log/index.html new file mode 100644 index 0000000..4498cc3 --- /dev/null +++ b/app/admin/view/system/timer_log/index.html @@ -0,0 +1,9 @@ +
+
+ +
+
+
diff --git a/app/admin/view/system/timer_log/index.js b/app/admin/view/system/timer_log/index.js new file mode 100644 index 0000000..af6f874 --- /dev/null +++ b/app/admin/view/system/timer_log/index.js @@ -0,0 +1,99 @@ +$(function(){ + // 状态徽章模板 + var statusTemplet = function(d) { + var statusMap = { + 'success': {text: '成功', color: '#5FB878', bgColor: '#e8f8ef'}, + 'error': {text: '失败', color: '#FF5722', bgColor: '#ffe8e2'}, + 'running': {text: '运行中', color: '#1E9FFF', bgColor: '#e2f1ff'}, + }; + var item = statusMap[d.status] || {text: d.status, color: '#999', bgColor: '#f5f5f5'}; + return ''+item.text+''; + }; + + // 时间格式化模板 + var timeTemplet = function(d) { + if (!d.start_time || d.start_time === 0) return '-'; + var date = new Date(d.start_time * 1000); + var Y = date.getFullYear(); + var M = (date.getMonth()+1).toString().padStart(2,'0'); + var D = date.getDate().toString().padStart(2,'0'); + var h = date.getHours().toString().padStart(2,'0'); + var m = date.getMinutes().toString().padStart(2,'0'); + var s = date.getSeconds().toString().padStart(2,'0'); + return Y+'-'+M+'-'+D+' '+h+':'+m+':'+s; + }; + + var endTimeTemplet = function(d) { + if (!d.end_time || d.end_time === 0) return '-'; + var date = new Date(d.end_time * 1000); + var Y = date.getFullYear(); + var M = (date.getMonth()+1).toString().padStart(2,'0'); + var D = date.getDate().toString().padStart(2,'0'); + var h = date.getHours().toString().padStart(2,'0'); + var m = date.getMinutes().toString().padStart(2,'0'); + var s = date.getSeconds().toString().padStart(2,'0'); + return Y+'-'+M+'-'+D+' '+h+':'+m+':'+s; + }; + + // 耗时格式化模板 + var durationTemplet = function(d) { + if (!d.duration || d.duration === 0) return '-'; + if (d.duration < 1000) { + return d.duration + ' ms'; + } + return (d.duration / 1000).toFixed(2) + ' s'; + }; + + // 错误信息截断模板 + var errorMsgTemplet = function(d) { + if (!d.error_message) return '-'; + var text = d.error_message; + if (text.length > 50) { + return ''+text.substring(0,50)+'...'; + } + return text; + }; + + ua.table.render({ + init: init, + cols: [[ + {type: 'checkbox'}, + {field: 'id', title: 'ID', width: 80, sort: true}, + {field: 'task_name', title: '任务名称', width: 160, search: 'select', searchUrl: 'system.timer_log/index?selectFields=task_name'}, + {field: 'node_id', title: '节点ID', width: 120, search: 'select', searchUrl: 'system.timer_log/index?selectFields=node_id'}, + {field: 'run_type', title: '运行类型', width: 100}, + {field: 'start_time', title: '开始时间', width: 170, templet: timeTemplet, search: 'range'}, + {field: 'end_time', title: '结束时间', width: 170, templet: endTimeTemplet}, + {field: 'duration', title: '耗时', width: 100, templet: durationTemplet}, + {field: 'status', title: '状态', width: 100, templet: statusTemplet, search: 'select', selectList: {success:'成功', error:'失败', running:'运行中'}}, + {field: 'error_message', title: '错误信息', minWidth: 200, templet: errorMsgTemplet}, + { + width: 100, 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: '' + }] + ] + }, + ]], + }); + + // 点击错误信息查看完整内容 + ua.table.on('tool(currentTable)', function(obj) { + if (obj.event === 'showError') { + var text = obj.data.error_message || ''; + layer.alert('
'+text.replace(//g,'>')+'
', { + title: '错误信息详情', + area: ['600px', '400px'] + }); + } + }); + + ua.listen(); +}) diff --git a/app/admin/view/system/timer_log/read.html b/app/admin/view/system/timer_log/read.html new file mode 100644 index 0000000..fe205c6 --- /dev/null +++ b/app/admin/view/system/timer_log/read.html @@ -0,0 +1,139 @@ +
+
+
+
+
+
+

#{$row.id} {$title}

+
ID: {$row.id}
+
+
+ +
+
+
+
+
+ +
+
+
+
任务名称
+
+ {notempty name="row.task_name"} + {$row.task_name} + {else/} + 暂无数据 + {/notempty} +
+
+
+
执行节点ID
+
+ {notempty name="row.node_id"} + {$row.node_id} + {else/} + 暂无数据 + {/notempty} +
+
+
+
运行类型
+
+ {notempty name="row.run_type"} + {$row.run_type} + {else/} + 暂无数据 + {/notempty} +
+
+
+
开始时间
+
+ {notempty name="row.start_time"} + {:date('Y-m-d H:i:s', $row['start_time'])} + {else/} + 暂无数据 + {/notempty} +
+
+
+
结束时间
+
+ {notempty name="row.end_time"} + {:date('Y-m-d H:i:s', $row['end_time'])} + {else/} + 暂无数据 + {/notempty} +
+
+
+
耗时
+
+ {notempty name="row.duration"} + {:php echo ($row['duration'] < 1000) ? $row['duration'].' ms' : round($row['duration']/1000, 2).' s';} + {else/} + 暂无数据 + {/notempty} +
+
+
+
错误信息
+
+ {notempty name="row.error_message"} + {$row.error_message|raw} + {else/} + 暂无内容 + {/notempty} +
+
+
+
并发分片ID
+
+ {notempty name="row.concurrency_id"} + {$row.concurrency_id} + {else/} + 暂无数据 + {/notempty} +
+
+ +
+
+ +
+

基础信息

+
+
+
ID
+
{$row.id}
+
+
+
状态
+
+ {switch name="row.status"} + {case value="success"}成功{/case} + {case value="error"}失败{/case} + {case value="running"}运行中{/case} + {default /}{$row.status} + {/switch} +
+
+
+
创建时间
+
+ {notempty name="row.create_time"} + {$row.create_time|date="Y-m-d H:i:s"} + {else/} + 暂无数据 + {/notempty} +
+
+ +
+
+
+
+
+
+
diff --git a/app/admin/view/system/timer_log/read.js b/app/admin/view/system/timer_log/read.js new file mode 100644 index 0000000..81a35d4 --- /dev/null +++ b/app/admin/view/system/timer_log/read.js @@ -0,0 +1,3 @@ +$(function(){ + ua.listen(); +}) diff --git a/extend/base/admin/controller/system/HostBase.php b/extend/base/admin/controller/system/HostBase.php index 723fe41..c09336c 100644 --- a/extend/base/admin/controller/system/HostBase.php +++ b/extend/base/admin/controller/system/HostBase.php @@ -20,5 +20,26 @@ class HostBase extends AdminController $this->model = new \app\admin\model\SystemHost(); $this->assign('select_list_status', $this->model::SELECT_LIST_STATUS, true); + $this->assign('select_list_is_master', $this->model::SELECT_LIST_IS_MASTER, true); + } + + /** + * 设置主节点. + * + * @auth true + */ + public function setMaster() + { + $nodeId = $this->request->param('node_id', ''); + if (empty($nodeId)) { + $this->error('参数错误'); + } + + $result = \app\common\service\HostService::setMasterNode($nodeId); + if ($result) { + $this->success('主节点切换成功'); + } else { + $this->error('节点不存在'); + } } } diff --git a/extend/base/admin/model/SystemHostBase.php b/extend/base/admin/model/SystemHostBase.php index e2d941a..e2d5112 100644 --- a/extend/base/admin/model/SystemHostBase.php +++ b/extend/base/admin/model/SystemHostBase.php @@ -26,4 +26,6 @@ class SystemHostBase extends TimeModel protected $deleteTime = false; public const SELECT_LIST_STATUS = ['0' => '离线', '1' => '在线']; + + public const SELECT_LIST_IS_MASTER = ['0' => '从节点', '1' => '主节点']; } diff --git a/extend/base/admin/view/system/host/_common.js b/extend/base/admin/view/system/host/_common.js index ad6eb5d..984b2ab 100644 --- a/extend/base/admin/view/system/host/_common.js +++ b/extend/base/admin/view/system/host/_common.js @@ -7,4 +7,5 @@ var init = { deleteUrl: 'system.host/delete', exportUrl: 'system.host/export', modifyUrl: 'system.host/modify', + set_master_url: 'system.host/setMaster', }; \ No newline at end of file diff --git a/extend/base/admin/view/system/host/index.html b/extend/base/admin/view/system/host/index.html index 083bdc6..146e27c 100644 --- a/extend/base/admin/view/system/host/index.html +++ b/extend/base/admin/view/system/host/index.html @@ -7,6 +7,7 @@ data-auth-delete="{:auth('system.host/delete')}" data-auth-export="{:auth('system.host/export')}" data-auth-modify="{:auth('system.host/modify')}" + data-auth-set-master="{:auth('system.host/setMaster')}" lay-filter="currentTable"> diff --git a/extend/base/admin/view/system/host/index.js b/extend/base/admin/view/system/host/index.js index 21b3c53..61d5ac7 100644 --- a/extend/base/admin/view/system/host/index.js +++ b/extend/base/admin/view/system/host/index.js @@ -1,10 +1,47 @@ -$(function(){ - ua.table.render({ - init: init, - cols: [[ - {type: 'checkbox'}, {field: 'id', title: 'ID'}, {field: 'node_id', title: '节点ID'}, {field: 'ip_address', title: 'IP地址'}, {field: 'status', search: 'select', selectList: ua.getDataBrage('select_list_status'), title: '状态', templet: ua.table.switch}, {field: 'last_heartbeat_at', title: '最后心跳时间'}, {field: 'os_info', title: '系统信息'}, {field: 'php_version', title: 'PHP版本'}, {field: 'cpu_load', title: 'CPU负载'}, {field: 'memory_usage', title: '内存占用'}, {field: 'disk_free', title: '磁盘可用空间'}, {field: 'disk_total', title: '磁盘总空间'}, {field: 'create_time', title: '首次运行时间'}, {width: 250, title: '操作', templet: ua.table.tool , fixed:'right'}, - ]], - }); - - ua.listen(); -}) \ No newline at end of file +$(function(){ + ua.table.render({ + init: init, + cols: [[ + {type: 'checkbox'}, + {field: 'id', title: 'ID'}, + {field: 'node_id', title: '节点ID'}, + {field: 'ip_address', title: 'IP地址'}, + {field: 'status', search: 'select', selectList: ua.getDataBrage('select_list_status'), title: '状态', templet: ua.table.switch}, + {field: 'is_master', search: 'select', selectList: ua.getDataBrage('select_list_is_master'), title: '节点角色', templet: function(data) { + if (data.is_master == 1) { + return '主节点'; + } + return '从节点'; + }}, + {field: 'last_heartbeat_at', title: '最后心跳时间'}, + {field: 'os_info', title: '系统信息'}, + {field: 'php_version', title: 'PHP版本'}, + {field: 'cpu_load', title: 'CPU负载'}, + {field: 'memory_usage', title: '内存占用'}, + {field: 'disk_free', title: '磁盘可用空间'}, + {field: 'disk_total', title: '磁盘总空间'}, + {field: 'create_time', title: '首次运行时间'}, + {width: 300, title: '操作', templet: ua.table.tool, operat: [ + 'edit', + [{ + text: '设为主节点', + url: init.set_master_url, + method: 'request', + field: function(data) { + return {node_id: data.node_id}; + }, + auth: 'set-master', + class: 'layui-btn layui-btn-xs layui-btn-warm', + title: '确认将该节点设为主节点?切换后原主节点将变为从节点。', + _if: function(data) { + return data.status == 1 && data.is_master != 1; + } + }], + 'delete' + ], fixed:'right'}, + + ]], + }); + + ua.listen(); +})