chore: 重写初始提交(清空历史,整理后全量提交)
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
{extend name="layout"}
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">ACL 权限规则</div>
|
||||
<div class="layui-text" style="margin-bottom:10px;color:#999;">
|
||||
需在"服务设置"中开启 ACL 才生效。按 sort 升序匹配,命中第一条即决定放行/拒绝;
|
||||
主题支持通配符 <code>+ / #</code> 与占位符 <code>%u</code>(用户名) <code>%c</code>(clientId)。
|
||||
</div>
|
||||
<button class="layui-btn layui-btn-sm" onclick="editAcl()">+ 新增规则</button>
|
||||
<table class="layui-table" style="margin-top:10px;">
|
||||
<thead>
|
||||
<tr><th>sort</th><th>目标</th><th>主题过滤器</th><th>权限</th><th>动作</th><th>备注</th><th>操作</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{foreach $list as $c}
|
||||
<tr>
|
||||
<td>{$c.sort}</td>
|
||||
<td>{$c.target_type}{if $c.target}:{$c.target}{/if}</td>
|
||||
<td>{$c.topic}</td>
|
||||
<td>{if $c.access==1}订阅{elseif $c.access==2}发布{else}订阅+发布{/if}</td>
|
||||
<td>{if $c.allow}<span class="layui-badge layui-bg-green">允许</span>{else}<span class="layui-badge">拒绝</span>{/if}</td>
|
||||
<td>{$c.remark}</td>
|
||||
<td>
|
||||
<a class="layui-btn layui-btn-xs" onclick='editAcl({$c|json_encode})'>编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" onclick="delAcl({$c.id})">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
{$list|raw}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['layer', 'jquery'], function(){
|
||||
var $ = layui.jquery, layer = layui.layer;
|
||||
window.editAcl = function(row){
|
||||
row = row || {};
|
||||
var sel = function(name, val, opts){
|
||||
var s = '<select name="'+name+'">';
|
||||
opts.forEach(function(o){ s += '<option value="'+o[0]+'" '+(val==o[0]?'selected':'')+'>'+o[1]+'</option>'; });
|
||||
return s + '</select>';
|
||||
};
|
||||
var html = '<form class="layui-form" style="padding:20px;" lay-filter="aclForm">'
|
||||
+ '<input type="hidden" name="id" value="'+(row.id||'')+'">'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">目标类型</label><div class="layui-input-inline">'+sel('target_type', row.target_type||'all', [['all','全部'],['user','按用户名'],['client','按clientId']])+'</div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">目标值</label><div class="layui-input-inline"><input name="target" class="layui-input" value="'+(row.target||'')+'" placeholder="target_type=all 时留空"></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">主题过滤器</label><div class="layui-input-inline"><input name="topic" class="layui-input" value="'+(row.topic||'')+'" placeholder="如 device/%c/# 或 sensor/+/temp"></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">权限</label><div class="layui-input-inline">'+sel('access', row.access||3, [[1,'订阅'],[2,'发布'],[3,'订阅+发布']])+'</div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">动作</label><div class="layui-input-inline">'+sel('allow', (row.allow===undefined?1:row.allow), [[1,'允许'],[0,'拒绝']])+'</div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">排序</label><div class="layui-input-inline"><input name="sort" class="layui-input" value="'+(row.sort||0)+'"></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">备注</label><div class="layui-input-inline"><input name="remark" class="layui-input" value="'+(row.remark||'')+'"></div></div>'
|
||||
+ '</form>';
|
||||
layer.open({type:1, title:(row.id?'编辑':'新增')+'规则', area:['520px','auto'], content:html, btn:['保存','取消'],
|
||||
success:function(){ layui.form.render(); },
|
||||
yes:function(idx){
|
||||
var data = {};
|
||||
$('[lay-filter=aclForm]').serializeArray().forEach(function(i){ data[i.name]=i.value; });
|
||||
$.post('/mqttbroker/backend/saveAcl', data, function(res){
|
||||
layer.msg(res.message||res.msg||'ok');
|
||||
layer.close(idx); setTimeout(function(){location.reload();},600);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
window.delAcl = function(id){
|
||||
layer.confirm('确认删除该规则?', function(idx){
|
||||
$.post('/mqttbroker/backend/deleteAcl', {id:id}, function(res){ layer.msg(res.message||'已删除'); setTimeout(function(){location.reload();},600); });
|
||||
layer.close(idx);
|
||||
});
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
{extend name="layout"}
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">认证账号</div>
|
||||
<div class="layui-text" style="margin-bottom:10px;color:#999;">
|
||||
当"允许匿名连接"关闭时,客户端必须使用此处账号连接;超级用户跳过 ACL 校验。
|
||||
</div>
|
||||
<button class="layui-btn layui-btn-sm" onclick="editAuth()">+ 新增账号</button>
|
||||
<table class="layui-table" style="margin-top:10px;">
|
||||
<thead>
|
||||
<tr><th>ID</th><th>用户名</th><th>超级用户</th><th>状态</th><th>备注</th><th>操作</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{foreach $list as $c}
|
||||
<tr>
|
||||
<td>{$c.id}</td>
|
||||
<td>{$c.username}</td>
|
||||
<td>{if $c.is_superuser}<span class="layui-badge layui-bg-orange">是</span>{else}否{/if}</td>
|
||||
<td>{if $c.status}<span class="layui-badge layui-bg-green">启用</span>{else}<span class="layui-badge">禁用</span>{/if}</td>
|
||||
<td>{$c.remark}</td>
|
||||
<td>
|
||||
<a class="layui-btn layui-btn-xs" onclick='editAuth({$c|json_encode})'>编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" onclick="delAuth({$c.id})">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
{$list|raw}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['layer', 'jquery'], function(){
|
||||
var $ = layui.jquery, layer = layui.layer;
|
||||
window.editAuth = function(row){
|
||||
row = row || {};
|
||||
var html = '<form class="layui-form" style="padding:20px;" lay-filter="authForm">'
|
||||
+ '<input type="hidden" name="id" value="'+(row.id||'')+'">'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">用户名</label><div class="layui-input-inline"><input name="username" class="layui-input" value="'+(row.username||'')+'"></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">密码</label><div class="layui-input-inline"><input name="password" class="layui-input" placeholder="'+(row.id?'留空表示不修改':'必填')+'"></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">超级用户</label><div class="layui-input-inline"><select name="is_superuser"><option value="0" '+(!row.is_superuser?'selected':'')+'>否</option><option value="1" '+(row.is_superuser==1?'selected':'')+'>是</option></select></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">状态</label><div class="layui-input-inline"><select name="status"><option value="1" '+(row.status!=0?'selected':'')+'>启用</option><option value="0" '+(row.status==0?'selected':'')+'>禁用</option></select></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">备注</label><div class="layui-input-inline"><input name="remark" class="layui-input" value="'+(row.remark||'')+'"></div></div>'
|
||||
+ '</form>';
|
||||
layer.open({type:1, title:(row.id?'编辑':'新增')+'账号', area:['480px','auto'], content:html, btn:['保存','取消'],
|
||||
success:function(){ layui.form.render(); },
|
||||
yes:function(idx){
|
||||
var data = {};
|
||||
$('[lay-filter=authForm]').serializeArray().forEach(function(i){ data[i.name]=i.value; });
|
||||
$.post('/mqttbroker/backend/saveAuth', data, function(res){
|
||||
layer.msg(res.message||res.msg||'ok');
|
||||
if((res.code===0)||(res.code===1)) { layer.close(idx); setTimeout(function(){location.reload();},600); }
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
window.delAuth = function(id){
|
||||
layer.confirm('确认删除该账号?', function(idx){
|
||||
$.post('/mqttbroker/backend/deleteAuth', {id:id}, function(res){ layer.msg(res.message||'已删除'); setTimeout(function(){location.reload();},600); });
|
||||
layer.close(idx);
|
||||
});
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">客户端连接</div>
|
||||
<table class="layui-table">
|
||||
<thead>
|
||||
<tr><th>ID</th><th>ClientID</th><th>用户名</th><th>IP</th><th>状态</th><th>连接时间</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{foreach $list as $c}
|
||||
<tr>
|
||||
<td>{$c.id}</td>
|
||||
<td>{$c.client_id}</td>
|
||||
<td>{$c.username}</td>
|
||||
<td>{$c.ip}</td>
|
||||
<td>{$c.status|default=0}</td>
|
||||
<td>{if !empty($c.create_at)}{$c.create_at|date='Y-m-d H:i:s'}{else}-{/if}</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
{$list|raw}
|
||||
</div>
|
||||
@@ -0,0 +1,53 @@
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">MQTT 代理概览</div>
|
||||
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">在线连接</div>
|
||||
<div class="layui-card-body" style="font-size:30px;font-weight:bold;color:#1E9FFF;">{$stats.online}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">累计连接</div>
|
||||
<div class="layui-card-body" style="font-size:30px;font-weight:bold;">{$stats.total}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">消息总数</div>
|
||||
<div class="layui-card-body" style="font-size:30px;font-weight:bold;">{$stats.messages}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">订阅关系</div>
|
||||
<div class="layui-card-body" style="font-size:30px;font-weight:bold;">{$stats.topics}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-title">最近消息</div>
|
||||
<table class="layui-table">
|
||||
<thead>
|
||||
<tr><th>ID</th><th>主题</th><th>来源</th><th>内容</th><th>时间</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{foreach $recent as $m}
|
||||
<tr>
|
||||
<td>{$m.id}</td>
|
||||
<td>{$m.topic}</td>
|
||||
<td>{$m.source}</td>
|
||||
<td>{$m.payload}</td>
|
||||
<td>{if !empty($m.create_at)}{$m.create_at|date='Y-m-d H:i:s'}{else}-{/if}</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="layui-text" style="margin-top:15px;color:#999;">
|
||||
启动 Broker:<code>php think mqttbroker:start</code>(需在命令行运行常驻进程)
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">消息日志</div>
|
||||
<form class="layui-form" action="" style="margin-bottom:10px;">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="topic" value="{$topic}" placeholder="按主题搜索" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit>搜索</button>
|
||||
</div>
|
||||
</form>
|
||||
<table class="layui-table">
|
||||
<thead>
|
||||
<tr><th>ID</th><th>ClientID</th><th>主题</th><th>QoS</th><th>内容</th><th>来源</th><th>时间</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{foreach $list as $m}
|
||||
<tr>
|
||||
<td>{$m.id}</td>
|
||||
<td>{$m.client_id}</td>
|
||||
<td>{$m.topic}</td>
|
||||
<td>{$m.qos}</td>
|
||||
<td>{$m.payload}</td>
|
||||
<td>{$m.source}</td>
|
||||
<td>{if !empty($m.create_at)}{$m.create_at|date='Y-m-d H:i:s'}{else}-{/if}</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
{$list|raw}
|
||||
</div>
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">发布消息</div>
|
||||
<form class="layui-form" id="publishForm">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">主题</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="topic" required lay-verify="required" placeholder="如 sensor/room1/temp" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">内容</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="payload" placeholder="消息内容" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">QoS</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="qos">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="publish">发布</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['form', 'jquery'], function(){
|
||||
var form = layui.form, $ = layui.jquery;
|
||||
form.on('submit(publish)', function(data){
|
||||
$.post('/mqttbroker/backend/publish', data.field, function(res){
|
||||
layer.msg(res.message || res.msg || '已提交');
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,79 @@
|
||||
{extend name="layout"}
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">转发规则(规则引擎 / 桥接到 EMQX)</div>
|
||||
<div class="layui-text" style="margin-bottom:10px;color:#999;">
|
||||
匹配"源主题过滤器"的消息,将被转发到外部 MQTT Broker(如 EMQX)。目标主题支持
|
||||
<code>${topic}</code> 变量(沿用原主题)。规则最多 30s 后在 Broker 生效。
|
||||
转发依赖 <code>workerman/mqtt</code> 客户端,未安装时自动跳过。
|
||||
</div>
|
||||
<button class="layui-btn layui-btn-sm" onclick="editRule()">+ 新增规则</button>
|
||||
<table class="layui-table" style="margin-top:10px;">
|
||||
<thead>
|
||||
<tr><th>名称</th><th>源主题过滤器</th><th>目标Broker</th><th>目标主题</th><th>QoS</th><th>状态</th><th>操作</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{foreach $list as $r}
|
||||
<tr>
|
||||
<td>{$r.name}</td>
|
||||
<td>{$r.source_filter}</td>
|
||||
<td>{$r.target_broker}</td>
|
||||
<td>{if !empty($r.target_topic)}{$r.target_topic}{else/}${topic}{/if}</td>
|
||||
<td>{$r.target_qos}</td>
|
||||
<td>{if $r.enabled}<span class="layui-badge layui-bg-green">启用</span>{else}<span class="layui-badge">停用</span>{/if}</td>
|
||||
<td>
|
||||
<a class="layui-btn layui-btn-xs" onclick='editRule({$r|json_encode})'>编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" onclick="delRule({$r.id})">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
{$list|raw}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['layer', 'jquery'], function(){
|
||||
var $ = layui.jquery, layer = layui.layer;
|
||||
window.editRule = function(row){
|
||||
row = row || {};
|
||||
var sel = function(name, val, opts){
|
||||
var s = '<select name="'+name+'">';
|
||||
opts.forEach(function(o){ s += '<option value="'+o[0]+'" '+(val==o[0]?'selected':'')+'>'+o[1]+'</option>'; });
|
||||
return s + '</select>';
|
||||
};
|
||||
var html = '<form class="layui-form" style="padding:20px;" lay-filter="ruleForm">'
|
||||
+ '<input type="hidden" name="id" value="'+(row.id||'')+'">'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">规则名称</label><div class="layui-input-inline"><input name="name" class="layui-input" value="'+(row.name||'')+'"></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">源主题过滤器</label><div class="layui-input-inline"><input name="source_filter" class="layui-input" value="'+(row.source_filter||'')+'" placeholder="如 sensor/+/temp"></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">目标类型</label><div class="layui-input-inline">'+sel('target_type', row.target_type||'mqtt', [['mqtt','MQTT Broker']])+'</div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">目标Broker</label><div class="layui-input-inline"><input name="target_broker" class="layui-input" value="'+(row.target_broker||'')+'" placeholder="host:port,如 192.168.1.10:1883"></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">目标主题</label><div class="layui-input-inline"><input name="target_topic" class="layui-input" value="'+(row.target_topic||'')+'" placeholder="${topic} 表示沿用原主题"></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">目标QoS</label><div class="layui-input-inline">'+sel('target_qos', (row.target_qos===undefined?0:row.target_qos), [[0,'0'],[1,'1'],[2,'2']])+'</div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">ClientID</label><div class="layui-input-inline"><input name="target_clientid" class="layui-input" value="'+(row.target_clientid||'')+'" placeholder="可选"></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">用户名</label><div class="layui-input-inline"><input name="target_username" class="layui-input" value="'+(row.target_username||'')+'" placeholder="可选"></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">密码</label><div class="layui-input-inline"><input name="target_password" type="password" class="layui-input" value="'+(row.target_password||'')+'" placeholder="可选"></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">状态</label><div class="layui-input-inline">'+sel('enabled', (row.enabled===undefined?1:row.enabled), [[1,'启用'],[0,'停用']])+'</div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label">备注</label><div class="layui-input-inline"><input name="remark" class="layui-input" value="'+(row.remark||'')+'"></div></div>'
|
||||
+ '</form>';
|
||||
layer.open({type:1, title:(row.id?'编辑':'新增')+'转发规则', area:['560px','auto'], content:html, btn:['保存','取消'],
|
||||
success:function(){ layui.form.render(); },
|
||||
yes:function(idx){
|
||||
var data = {};
|
||||
$('[lay-filter=ruleForm]').serializeArray().forEach(function(i){ data[i.name]=i.value; });
|
||||
$.post('/mqttbroker/backend/saveRule', data, function(res){
|
||||
layer.msg(res.message||res.msg||'ok');
|
||||
layer.close(idx); setTimeout(function(){location.reload();},600);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
window.delRule = function(id){
|
||||
layer.confirm('确认删除该规则?', function(idx){
|
||||
$.post('/mqttbroker/backend/deleteRule', {id:id}, function(res){ layer.msg(res.message||'已删除'); setTimeout(function(){location.reload();},600); });
|
||||
layer.close(idx);
|
||||
});
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
<div class="layui-card-body">
|
||||
<div class="admin-title">服务设置</div>
|
||||
<form class="layui-form" id="settingForm">
|
||||
{foreach $def as $item}
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">{$item.title}</label>
|
||||
<div class="layui-input-inline">
|
||||
{if isset($item.options) && $item.options}
|
||||
<select name="{$item.name}">
|
||||
{foreach $item.options as $k=>$v}
|
||||
<option value="{$k}" {if (isset($saved[$item['name']]) && $saved[$item['name']]==$k)}selected{/if}>{$v}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
{else}
|
||||
<input type="text" name="{$item.name}" value="{$saved[$item['name']] ?? $item.value}" class="layui-input">
|
||||
{/if}
|
||||
</div>
|
||||
{if isset($item.tip) && $item.tip}<div class="layui-form-mid layui-word-aux">{$item.tip}</div>{/if}
|
||||
</div>
|
||||
{/foreach}
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="save">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['form', 'jquery'], function(){
|
||||
var form = layui.form, $ = layui.jquery;
|
||||
form.on('submit(save)', function(data){
|
||||
$.post('/mqttbroker/backend/setting', data.field, function(res){
|
||||
layer.msg(res.message || '已保存');
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,80 @@
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="admin-title">MQTT 实时运行监控
|
||||
<span class="layui-badge layui-bg-blue" id="live" style="margin-left:10px;">实时</span>
|
||||
<span style="float:right;color:#999;font-size:12px;">最后刷新:<span id="lastSync">--</span></span>
|
||||
</div>
|
||||
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card"><div class="layui-card-header">在线连接</div>
|
||||
<div class="layui-card-body" style="font-size:30px;font-weight:bold;color:#1E9FFF;" id="m_online">0</div></div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card"><div class="layui-card-header">会话总数</div>
|
||||
<div class="layui-card-body" style="font-size:30px;font-weight:bold;" id="m_total">0</div></div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card"><div class="layui-card-header">订阅关系</div>
|
||||
<div class="layui-card-body" style="font-size:30px;font-weight:bold;color:#16a34a;" id="m_subs">0</div></div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card"><div class="layui-card-header">运行时长</div>
|
||||
<div class="layui-card-body" style="font-size:30px;font-weight:bold;" id="m_uptime">00:00:00</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card"><div class="layui-card-header">累计接收</div>
|
||||
<div class="layui-card-body" style="font-size:26px;font-weight:bold;" id="m_recv">0</div></div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card"><div class="layui-card-header">累计发送</div>
|
||||
<div class="layui-card-body" style="font-size:26px;font-weight:bold;" id="m_sent">0</div></div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card"><div class="layui-card-header">保留消息</div>
|
||||
<div class="layui-card-body" style="font-size:26px;font-weight:bold;" id="m_retained">0</div></div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card"><div class="layui-card-header">快照时间</div>
|
||||
<div class="layui-card-body" style="font-size:18px;" id="m_ts">--</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-text" style="margin-top:10px;color:#999;">
|
||||
指标由 Broker 进程每 2 秒写入数据库,本页每 3 秒轮询刷新(跨进程安全,Windows 调试与 Linux 生产通用)。
|
||||
若长时间显示 0,请确认 Broker 已启动:<code>php think mqttbroker:start</code>。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['jquery'], function(){
|
||||
var $ = layui.jquery;
|
||||
function fmtUptime(s){
|
||||
s = parseInt(s||0);
|
||||
var h = Math.floor(s/3600), m = Math.floor((s%3600)/60), ss = s%60;
|
||||
var p = function(n){ return (n<10?'0':'')+n; };
|
||||
return p(h)+':'+p(m)+':'+p(ss);
|
||||
}
|
||||
function load(){
|
||||
$.getJSON('/mqttbroker/backend/stats', function(res){
|
||||
if (res.code !== 0 || !res.data) return;
|
||||
var d = res.data;
|
||||
$('#m_online').text(d.db_online != null ? d.db_online : d.clients_online);
|
||||
$('#m_total').text(d.clients_total);
|
||||
$('#m_subs').text(d.subscriptions);
|
||||
$('#m_uptime').text(fmtUptime(d.uptime));
|
||||
$('#m_recv').text(d.messages_received);
|
||||
$('#m_sent').text(d.messages_sent);
|
||||
$('#m_retained').text(d.retained);
|
||||
$('#m_ts').text(new Date((d.timestamp||0)*1000).toLocaleString());
|
||||
$('#lastSync').text(new Date().toLocaleTimeString());
|
||||
$('#live').text('实时●');
|
||||
}).fail(function(){ $('#live').text('断开'); });
|
||||
}
|
||||
load();
|
||||
setInterval(load, 3000);
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user