chore: 重写初始提交(清空历史,整理后全量提交)
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">站点广告管理</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="data-search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="title" placeholder="标题" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<select name="position" lay-search="">
|
||||
<option value="">全部广告位</option>
|
||||
{volist name="positionList" id="p"}
|
||||
<option value="{$key}">{$p}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="data-search-btn"><i class="layui-icon"></i> 搜索</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="btn-reset">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataCreate" data-perm="ad:add"><i class="layui-icon"></i> 新增</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="dataDelete" data-perm="ad:del"><i class="layui-icon"></i> 删除</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataRecybin" data-perm="ad:restore"><i class="layui-icon"></i> 回收站</button>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="dataBar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="update" data-perm="ad:edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete" data-perm="ad:del">删除</a>
|
||||
</script>
|
||||
<script type="text/html" id="statusTpl">
|
||||
<input type="checkbox" name="status" value="{{ d.id }}" lay-skin="switch" lay-text="开|关" lay-filter="statusSwitch" {{ d.status == 1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form" id="wxapp-form" lay-filter="wxapp-form" style="padding:15px;">
|
||||
<input type="hidden" name="id" value="{{ d.id || '' }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标题</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" placeholder="请输入标题" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">广告位</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="position" lay-search="">
|
||||
{volist name="positionList" id="p"}
|
||||
<option value="{$key}">{$p}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">类型</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="type">
|
||||
{volist name="typeList" id="t"}
|
||||
<option value="{$key}">{$t}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">内容</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="content" placeholder="请输入内容" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">链接</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="url" placeholder="请输入链接" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">图片</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="image" placeholder="请输入图片" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="sort" placeholder="请输入排序" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="status" lay-skin="switch" lay-text="启用|禁用" value="1" checked>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<table class="layui-hide" id="dataRecybinTable" lay-filter="dataRecybinTable"></table>
|
||||
<script type="text/html" id="dataRecybinBarTpl">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="restore" data-perm="ad:restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="forcedelete" data-perm="ad:destroy">彻底删除</a>
|
||||
</script>
|
||||
</script>
|
||||
<script>
|
||||
layui.use('ad', layui.factory('ad'));
|
||||
</script>
|
||||
@@ -0,0 +1,374 @@
|
||||
<div class="layui-card" style="margin:15px;">
|
||||
<div class="layui-card-header">
|
||||
插件设计器 <span id="addonName" class="layui-badge layui-bg-blue"></span>
|
||||
<a href="{:url('addon/index')}" class="layui-btn layui-btn-sm layui-btn-primary" style="float:right;"><i class="layui-icon layui-icon-return"></i> 返回插件列表</a>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
|
||||
<!-- 新建模式:填写插件标识与基础信息 -->
|
||||
<div id="createBox">
|
||||
<fieldset class="layui-elem-field layui-field-title"><legend>新建插件</legend></fieldset>
|
||||
<form class="layui-form" lay-filter="createForm" style="max-width:640px;">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">插件标识</label>
|
||||
<div class="layui-input-inline" style="width:300px;">
|
||||
<input type="text" name="name" id="createName" class="layui-input" placeholder="如 myaddon(字母开头)">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">目录名 / 命名空间标识,创建后不可改</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">名称</label>
|
||||
<div class="layui-input-inline" style="width:300px;"><input type="text" name="title" class="layui-input" placeholder="插件显示名称"></div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">简介</label>
|
||||
<div class="layui-input-inline" style="width:300px;"><input type="text" name="intro" class="layui-input"></div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">作者</label>
|
||||
<div class="layui-input-inline" style="width:300px;"><input type="text" name="author" class="layui-input"></div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">官网</label>
|
||||
<div class="layui-input-inline" style="width:300px;"><input type="text" name="website" class="layui-input"></div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">版本</label>
|
||||
<div class="layui-input-inline" style="width:300px;"><input type="text" name="version" value="1.0.0" class="layui-input"></div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">前台入口</label>
|
||||
<div class="layui-input-inline" style="width:300px;"><input type="text" name="url" class="layui-input" placeholder="如 /myaddon"></div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="createBtn"><i class="layui-icon layui-icon-add-1"></i> 创建骨架</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- 设计模式 -->
|
||||
<div id="designBox" style="display:none;">
|
||||
<div class="layui-tab" lay-filter="designTab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">基础信息</li>
|
||||
<li>配置项</li>
|
||||
<li>菜单</li>
|
||||
<li>事件/中间件</li>
|
||||
<li>路由</li>
|
||||
<li>页面模块</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
|
||||
<!-- 基础信息 -->
|
||||
<div class="layui-tab-item layui-show">
|
||||
<form class="layui-form" lay-filter="basicForm" style="max-width:640px;">
|
||||
<div class="layui-form-item"><label class="layui-form-label">标识</label><div class="layui-input-inline" style="width:300px;"><input type="text" name="name" id="basicName" class="layui-input" readonly></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">名称</label><div class="layui-input-inline" style="width:300px;"><input type="text" name="title" class="layui-input"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">简介</label><div class="layui-input-inline" style="width:300px;"><input type="text" name="intro" class="layui-input"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">作者</label><div class="layui-input-inline" style="width:300px;"><input type="text" name="author" class="layui-input"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">官网</label><div class="layui-input-inline" style="width:300px;"><input type="text" name="website" class="layui-input"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">版本</label><div class="layui-input-inline" style="width:300px;"><input type="text" name="version" class="layui-input"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">前台入口</label><div class="layui-input-inline" style="width:300px;"><input type="text" name="url" class="layui-input"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">授权</label><div class="layui-input-inline" style="width:300px;"><input type="text" name="license" class="layui-input"></div></div>
|
||||
<div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn" lay-submit lay-filter="basicBtn">保存基础信息</button></div></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- 配置项 -->
|
||||
<div class="layui-tab-item">
|
||||
<button class="layui-btn layui-btn-sm" id="cfgAdd"><i class="layui-icon layui-icon-add-1"></i> 新增配置项</button>
|
||||
<table class="layui-table" style="margin-top:10px;">
|
||||
<thead><tr><th>名称(name)</th><th>标题(title)</th><th>类型(type)</th><th>默认值(value)</th><th>提示(tip)</th><th>操作</th></tr></thead>
|
||||
<tbody id="cfgRows"></tbody>
|
||||
</table>
|
||||
<button class="layui-btn" id="cfgSave">保存配置项</button>
|
||||
</div>
|
||||
|
||||
<!-- 菜单 -->
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-form-item"><label class="layui-form-label">后台菜单</label><div class="layui-input-block"><textarea id="menuBackend" class="layui-textarea" style="min-height:120px;"></textarea></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">会员菜单</label><div class="layui-input-block"><textarea id="menuMember" class="layui-textarea" style="min-height:80px;"></textarea></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">前台菜单</label><div class="layui-input-block"><textarea id="menuFrontend" class="layui-textarea" style="min-height:80px;"></textarea></div></div>
|
||||
<button class="layui-btn" id="menuSave">保存菜单(JSON)</button>
|
||||
<div class="layui-form-mid layui-word-aux">格式参考现有插件 menu.json;保存时会校验 JSON。</div>
|
||||
</div>
|
||||
|
||||
<!-- 事件/中间件 -->
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-form-item"><label class="layui-form-label">events</label><div class="layui-input-block"><textarea id="evEvents" class="layui-textarea" style="min-height:100px;"></textarea></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">middleware</label><div class="layui-input-block"><textarea id="evMiddleware" class="layui-textarea" style="min-height:100px;"></textarea></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">services</label><div class="layui-input-block"><textarea id="evServices" class="layui-textarea" style="min-height:80px;"></textarea></div></div>
|
||||
<button class="layui-btn" id="hooksSave">保存事件/中间件/服务</button>
|
||||
<div class="layui-form-mid layui-word-aux">填写合法 JSON;events 含 bind/listen/subscribe,middleware 含 alias/priority。</div>
|
||||
</div>
|
||||
|
||||
<!-- 路由 -->
|
||||
<div class="layui-tab-item">
|
||||
<button class="layui-btn layui-btn-sm" id="routeAdd"><i class="layui-icon layui-icon-add-1"></i> 新增路由</button>
|
||||
<table class="layui-table" style="margin-top:10px;">
|
||||
<thead><tr><th>方法</th><th>路径(path)</th><th>控制器(controller)</th><th>方法(action)</th><th>操作</th></tr></thead>
|
||||
<tbody id="routeRows"></tbody>
|
||||
</table>
|
||||
<button class="layui-btn" id="routeSave">保存路由</button>
|
||||
</div>
|
||||
|
||||
<!-- 页面模块 -->
|
||||
<div class="layui-tab-item">
|
||||
<form class="layui-form" lay-filter="genForm" style="max-width:560px;">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">类型</label>
|
||||
<div class="layui-input-inline" style="width:200px;">
|
||||
<select name="gtype" id="genType">
|
||||
<option value="controller">控制器 Controller</option>
|
||||
<option value="model">模型 Model</option>
|
||||
<option value="event">事件 Event</option>
|
||||
<option value="listener">监听器 Listener</option>
|
||||
<option value="middleware">中间件 Middleware</option>
|
||||
<option value="service">服务 Service</option>
|
||||
<option value="subscribe">订阅者 Subscribe</option>
|
||||
<option value="validate">验证器 Validate</option>
|
||||
<option value="command">命令行 Command</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="genLayerBox">
|
||||
<label class="layui-form-label">层级</label>
|
||||
<div class="layui-input-inline" style="width:200px;">
|
||||
<select name="layer" id="genLayer">
|
||||
<option value="frontend">前台 frontend</option>
|
||||
<option value="backend">后台 backend</option>
|
||||
<option value="member">会员 member</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="genKindBox">
|
||||
<label class="layui-form-label">风格</label>
|
||||
<div class="layui-input-inline" style="width:200px;">
|
||||
<select name="kind" id="genKind">
|
||||
<option value="default">资源(默认)</option>
|
||||
<option value="api">API</option>
|
||||
<option value="plain">空白</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">类名</label>
|
||||
<div class="layui-input-inline" style="width:200px;"><input type="text" name="name" id="genName" class="layui-input" placeholder="如 Category"></div>
|
||||
<div class="layui-form-mid layui-word-aux">不含命名空间</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="genCmdBox" style="display:none;">
|
||||
<label class="layui-form-label">命令名</label>
|
||||
<div class="layui-input-inline" style="width:200px;"><input type="text" name="command" id="genCmd" class="layui-input" placeholder="如 myaddon:demo"></div>
|
||||
</div>
|
||||
<div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn layui-btn-normal" id="genBtn">生成文件</button></div></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<button class="layui-btn layui-btn-normal" id="btnInstall"><i class="layui-icon layui-icon-ok"></i> 开发安装(建表/注入菜单/启用)</button>
|
||||
<button class="layui-btn layui-btn-danger" id="btnRemove"><i class="layui-icon layui-icon-delete"></i> 删除插件</button>
|
||||
<span class="layui-word-aux">开发安装后改动实时生效,无需重新打包。</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<script>
|
||||
layui.use(['form', 'layer', 'element', 'jquery', 'http'], function () {
|
||||
var form = layui.form, layer = layui.layer, element = layui.element, $ = layui.jquery, http = layui.http;
|
||||
var addon = '{$addon|default=""}';
|
||||
|
||||
function showCreate(defName) {
|
||||
$('#createBox').show();
|
||||
$('#designBox').hide();
|
||||
if (defName) $('#createName').val(defName);
|
||||
}
|
||||
function showDesign() {
|
||||
$('#createBox').hide();
|
||||
$('#designBox').show();
|
||||
}
|
||||
|
||||
// 初始化:有 addon 则尝试读取,否则新建
|
||||
if (addon) {
|
||||
http.get('designRead?addon=' + encodeURIComponent(addon)).then(function (res) {
|
||||
if (res.code === 0) {
|
||||
fillForm(res.data);
|
||||
showDesign();
|
||||
} else {
|
||||
showCreate(addon);
|
||||
}
|
||||
}).catch(function () { showCreate(addon); });
|
||||
} else {
|
||||
showCreate('');
|
||||
}
|
||||
|
||||
function fillForm(d) {
|
||||
$('#addonName').text(d.name || '');
|
||||
addon = d.name || addon;
|
||||
var info = d.info || {};
|
||||
form.val('basicForm', {
|
||||
name: info.name || '', title: info.title || '', intro: info.intro || '',
|
||||
author: info.author || '', website: info.website || '', version: info.version || '',
|
||||
url: info.url || '', license: info.license || ''
|
||||
});
|
||||
// 配置项
|
||||
$('#cfgRows').empty();
|
||||
(d.config || []).forEach(function (f) { addCfgRow(f); });
|
||||
// 菜单
|
||||
var m = d.menu || {};
|
||||
$('#menuBackend').val(JSON.stringify(m.backend || [], null, 2));
|
||||
$('#menuMember').val(JSON.stringify(m.member || [], null, 2));
|
||||
$('#menuFrontend').val(JSON.stringify(m.frontend || [], null, 2));
|
||||
// 事件/中间件
|
||||
var ev = info.events || {};
|
||||
$('#evEvents').val(JSON.stringify(ev, null, 2));
|
||||
$('#evMiddleware').val(JSON.stringify(info.middleware || {}, null, 2));
|
||||
$('#evServices').val(JSON.stringify(info.services || [], null, 2));
|
||||
// 路由(从 route_raw 解析较复杂,这里留空由用户手动加;如需可解析 TODO)
|
||||
}
|
||||
|
||||
// ===== 新建骨架 =====
|
||||
form.on('submit(createBtn)', function (data) {
|
||||
http.post('designCreate', data.field).then(function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('创建成功', { icon: 1 });
|
||||
addon = data.field.name;
|
||||
location.href = 'design?addon=' + encodeURIComponent(addon);
|
||||
} else {
|
||||
layer.msg(res.message || '创建失败', { icon: 2 });
|
||||
}
|
||||
}).catch(function () { layer.msg('请求失败', { icon: 2 }); });
|
||||
return false;
|
||||
});
|
||||
|
||||
// ===== 基础信息保存 =====
|
||||
form.on('submit(basicBtn)', function (data) {
|
||||
var fd = data.field; fd.addon = addon; fd.type = 'basic';
|
||||
http.post('designSave', fd).then(function (res) {
|
||||
layer.msg(res.code === 0 ? '已保存' : (res.message || '失败'), { icon: res.code === 0 ? 1 : 2 });
|
||||
}).catch(function () { layer.msg('请求失败', { icon: 2 }); });
|
||||
return false;
|
||||
});
|
||||
|
||||
// ===== 配置项行 =====
|
||||
function addCfgRow(f) {
|
||||
f = f || {};
|
||||
var tr = $('<tr>').append(
|
||||
$('<td>').append($('<input class="layui-input cfg-name" value="' + (f.name||'') + '">')),
|
||||
$('<td>').append($('<input class="layui-input cfg-title" value="' + (f.title||'') + '">')),
|
||||
$('<td>').append($('<input class="layui-input cfg-type" value="' + (f.type||'string') + '">')),
|
||||
$('<td>').append($('<input class="layui-input cfg-value" value="' + (f.value||'') + '">')),
|
||||
$('<td>').append($('<input class="layui-input cfg-tip" value="' + (f.tip||'') + '">')),
|
||||
$('<td>').append($('<button class="layui-btn layui-btn-xs layui-btn-danger cfg-del">删除</button>'))
|
||||
);
|
||||
$('#cfgRows').append(tr);
|
||||
}
|
||||
$('#cfgAdd').on('click', function () { addCfgRow(); });
|
||||
$('#cfgRows').on('click', '.cfg-del', function () { $(this).closest('tr').remove(); });
|
||||
$('#cfgSave').on('click', function () {
|
||||
var fields = [];
|
||||
$('#cfgRows tr').each(function () {
|
||||
var t = $(this);
|
||||
fields.push({ name: t.find('.cfg-name').val(), title: t.find('.cfg-title').val(),
|
||||
type: t.find('.cfg-type').val(), value: t.find('.cfg-value').val(), tip: t.find('.cfg-tip').val() });
|
||||
});
|
||||
http.post('designSave', { addon: addon, type: 'config', fields: JSON.stringify(fields) })
|
||||
.then(function (res) { layer.msg(res.code === 0 ? '配置已保存' : (res.message || '失败'), { icon: res.code === 0 ? 1 : 2 }); })
|
||||
.catch(function () { layer.msg('请求失败', { icon: 2 }); });
|
||||
});
|
||||
|
||||
// ===== 菜单保存 =====
|
||||
$('#menuSave').on('click', function () {
|
||||
try {
|
||||
var menu = {
|
||||
backend: JSON.parse($('#menuBackend').val() || '[]'),
|
||||
member: JSON.parse($('#menuMember').val() || '[]'),
|
||||
frontend: JSON.parse($('#menuFrontend').val() || '[]')
|
||||
};
|
||||
http.post('designSave', { addon: addon, type: 'menu', menu: JSON.stringify(menu) })
|
||||
.then(function (res) { layer.msg(res.code === 0 ? '菜单已保存' : (res.message || '失败'), { icon: res.code === 0 ? 1 : 2 }); })
|
||||
.catch(function () { layer.msg('请求失败', { icon: 2 }); });
|
||||
} catch (e) { layer.msg('菜单 JSON 格式错误:' + e.message, { icon: 2 }); }
|
||||
});
|
||||
|
||||
// ===== 事件/中间件保存 =====
|
||||
$('#hooksSave').on('click', function () {
|
||||
try {
|
||||
var events = JSON.parse($('#evEvents').val() || '{}');
|
||||
var middleware = JSON.parse($('#evMiddleware').val() || '{}');
|
||||
var services = JSON.parse($('#evServices').val() || '[]');
|
||||
http.post('designSave', { addon: addon, type: 'hooks',
|
||||
events: JSON.stringify(events), middleware: JSON.stringify(middleware), services: JSON.stringify(services) })
|
||||
.then(function (res) { layer.msg(res.code === 0 ? '已保存' : (res.message || '失败'), { icon: res.code === 0 ? 1 : 2 }); })
|
||||
.catch(function () { layer.msg('请求失败', { icon: 2 }); });
|
||||
} catch (e) { layer.msg('JSON 格式错误:' + e.message, { icon: 2 }); }
|
||||
});
|
||||
|
||||
// ===== 路由行 =====
|
||||
function addRouteRow(r) {
|
||||
r = r || {};
|
||||
var tr = $('<tr>').append(
|
||||
$('<td>').append($('<select class="layui-input rt-method"><option>get</option><option>post</option><option>put</option><option>delete</option><option>any</option></select>').val(r.method||'get')),
|
||||
$('<td>').append($('<input class="layui-input rt-path" value="' + (r.path||'') + '">')),
|
||||
$('<td>').append($('<input class="layui-input rt-ctrl" value="' + (r.controller||'') + '">')),
|
||||
$('<td>').append($('<input class="layui-input rt-action" value="' + (r.action||'index') + '">')),
|
||||
$('<td>').append($('<button class="layui-btn layui-btn-xs layui-btn-danger rt-del">删除</button>'))
|
||||
);
|
||||
$('#routeRows').append(tr);
|
||||
}
|
||||
$('#routeAdd').on('click', function () { addRouteRow(); });
|
||||
$('#routeRows').on('click', '.rt-del', function () { $(this).closest('tr').remove(); });
|
||||
$('#routeSave').on('click', function () {
|
||||
var routes = [];
|
||||
$('#routeRows tr').each(function () {
|
||||
var t = $(this);
|
||||
routes.push({ method: t.find('.rt-method').val(), path: t.find('.rt-path').val(),
|
||||
controller: t.find('.rt-ctrl').val(), action: t.find('.rt-action').val() });
|
||||
});
|
||||
http.post('designSave', { addon: addon, type: 'route', routes: JSON.stringify(routes) })
|
||||
.then(function (res) { layer.msg(res.code === 0 ? '路由已保存' : (res.message || '失败'), { icon: res.code === 0 ? 1 : 2 }); })
|
||||
.catch(function () { layer.msg('请求失败', { icon: 2 }); });
|
||||
});
|
||||
|
||||
// ===== 页面模块生成 =====
|
||||
$('#genType').on('change', function () {
|
||||
var t = $(this).val();
|
||||
var isCtrl = (t === 'controller');
|
||||
$('#genLayerBox').toggle(isCtrl);
|
||||
$('#genKindBox').toggle(isCtrl);
|
||||
$('#genCmdBox').toggle(t === 'command');
|
||||
});
|
||||
$('#genBtn').on('click', function () {
|
||||
var gtype = $('#genType').val();
|
||||
var opts = { name: $('#genName').val() };
|
||||
if (gtype === 'controller') { opts.layer = $('#genLayer').val(); opts.kind = $('#genKind').val(); }
|
||||
if (gtype === 'command') { opts.command = $('#genCmd').val(); }
|
||||
if (!opts.name) { layer.msg('请填写类名', { icon: 2 }); return; }
|
||||
http.post('designGenerate', { addon: addon, gtype: gtype, opts: JSON.stringify(opts) })
|
||||
.then(function (res) { layer.msg(res.code === 0 ? ('已生成:' + (res.data.file||'')) : (res.message || '失败'), { icon: res.code === 0 ? 1 : 2 }); })
|
||||
.catch(function () { layer.msg('请求失败', { icon: 2 }); });
|
||||
});
|
||||
|
||||
// ===== 开发安装 / 删除 =====
|
||||
$('#btnInstall').on('click', function () {
|
||||
http.post('designInstall', { addon: addon }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('开发安装成功,菜单已注入', { icon: 1 }); }
|
||||
else { layer.msg(res.message || '失败', { icon: 2 }); }
|
||||
}).catch(function () { layer.msg('请求失败', { icon: 2 }); });
|
||||
});
|
||||
$('#btnRemove').on('click', function () {
|
||||
layer.confirm('确定删除该插件目录?(开发调试用,不可恢复)', function (index) {
|
||||
layer.close(index);
|
||||
http.post('designRemove', { addon: addon }).then(function (res) {
|
||||
if (res.code === 0) { layer.msg('已删除', { icon: 1 }); location.href = 'index'; }
|
||||
else { layer.msg(res.message || '失败', { icon: 2 }); }
|
||||
}).catch(function () { layer.msg('请求失败', { icon: 2 }); });
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,85 @@
|
||||
<!--
|
||||
* @Author: YwxApp <ywx@ywxapp.cn>
|
||||
* @Date: 2026-04-29 02:32:33
|
||||
* @LastEditors: YwxApp <ywx@ywxapp.cn>
|
||||
* @LastEditTime: 2026-07-31 14:57:37
|
||||
* @Description:
|
||||
* @FilePath: \ywxapp_dev\app\backend\view\addon\index.html
|
||||
* @CustomString: Copyright (c) 2026 YwxApp
|
||||
-->
|
||||
|
||||
<div class="plugin-container layui-card" style="margin-bottom: 5px;">
|
||||
<!-- 1. 顶部搜索与操作栏 -->
|
||||
<div class="layui-card-header layui-row layui-col-space15">
|
||||
<div class="layui-col-md12">
|
||||
<form class="layui-form" lay-filter="searchForm">
|
||||
<div class="layui-form-item" style="margin-bottom: 0;">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label" style="width: auto;">插件搜索</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="keyword" placeholder="输入插件名称..." class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label" style="width: auto;">运行状态</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="status">
|
||||
<option value="">全部</option>
|
||||
<option value="1">已启用</option>
|
||||
<option value="0">已停用</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="searchBtn">
|
||||
<i class="layui-icon layui-icon-search"></i> 搜索
|
||||
</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="layui-border-green">
|
||||
|
||||
<!-- 2. 功能性操作按钮组 -->
|
||||
<div class="layui-card-header" style="margin: 15px;">
|
||||
<button class="layui-btn" data-type="install" id="buttonInstall" data-perm="addon:*"><i class="layui-icon layui-icon-add-1"></i> 安装新插件</button>
|
||||
<a class="layui-btn layui-btn-normal" href="{:url('addon/market')}" data-perm="addon:*"><i class="layui-icon layui-icon-app"></i> 应用市场</a>
|
||||
<a class="layui-btn layui-btn-normal" href="{:url('addon/my')}" data-perm="addon:*"><i class="layui-icon layui-icon-username"></i> 我的插件</a>
|
||||
<button class="layui-btn layui-btn-danger" data-type="batchDel" data-perm="addon:delete"><i class="layui-icon layui-icon-delete"></i> 批量卸载</button>
|
||||
<button class="layui-btn layui-btn-warm" data-type="refresh"><i class="layui-icon layui-icon-refresh"></i> 刷新列表</button>
|
||||
{if config('ywxapp.addon_developer')}
|
||||
<a class="layui-btn layui-btn-warm" href="{:url('addon/design')}"><i class="layui-icon layui-icon-set"></i> 设计插件</a>
|
||||
{/if}
|
||||
</div>
|
||||
<diiv class="layui-card-body">
|
||||
<!-- 3. 核心数据表格 -->
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 状态开关模板 (控制启用/禁用) -->
|
||||
<script type="text/html" id="switchTpl">
|
||||
<input type="checkbox" name="status" value="{{= d.id }}" lay-skin="switch" lay-text="启用|停用"
|
||||
lay-filter="statusSwitch" {{= d.status == 1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
|
||||
<!-- 右侧操作列模板 (配置/卸载) -->
|
||||
|
||||
<script type="text/html" id="operateTpl">
|
||||
<div class="layui-clear-space">
|
||||
{{# if(d.hasConfig){ }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="config" data-perm="addon:config"><i class="layui-icon layui-icon-set"></i> 配置</a>
|
||||
{{# } }}
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="uninstall" data-perm="addon:delete"><i class="layui-icon layui-icon-close"></i> 卸载</a>
|
||||
{{# if(layui.app.devToken){ }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="more"> 更多 <i class="layui-icon layui-icon-down"></i></a>
|
||||
{{# } }}
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
console.log(window)
|
||||
layui.use(['addon', 'table']);
|
||||
</script>
|
||||
@@ -0,0 +1,354 @@
|
||||
<div class="layui-card" style="margin-bottom:5px;">
|
||||
<div class="layui-card-header" style="display:flex;align-items:center;justify-content:space-between;">
|
||||
<div>
|
||||
<span class="title" style="font-size:18px;font-weight:700;">应用市场</span>
|
||||
{if $is_client}
|
||||
<span class="mode-badge client">客户端模式 · 连接:{$api_url}</span>
|
||||
{else /}
|
||||
<span class="mode-badge center">服务中心模式(本地市场)</span>
|
||||
{/if}
|
||||
</div>
|
||||
<span>
|
||||
<a href="{:url('addon/my')}" class="layui-btn layui-btn-normal layui-btn-sm">我的插件</a>
|
||||
<a href="{:url('addon/index')}" class="layui-btn layui-btn-primary layui-btn-sm"><i class="layui-icon layui-icon-return"></i> 返回已安装插件</a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{if $error}
|
||||
<div class="store-banner err">{$error}</div>
|
||||
{/if}
|
||||
|
||||
<div class="layui-card-body">
|
||||
<form class="store-search" method="get" action="{:url('addon/market')}" style="margin-bottom:14px;display:flex;gap:10px;flex-wrap:wrap;align-items:center;">
|
||||
<input type="text" name="keyword" value="{$keyword|default=''}" placeholder="搜索插件名称/作者/描述" class="layui-input" style="width:240px;">
|
||||
<select name="category" class="layui-input" style="width:140px;">
|
||||
<option value="">全部分类</option>
|
||||
{volist name="categories" id="c"}
|
||||
<option value="{$c}" {eq name="category" value="$c"}selected{/eq}>{$c}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
<select name="type" class="layui-input" style="width:120px;">
|
||||
<option value="">全部类型</option>
|
||||
<option value="addon" {eq name="type" value="addon"}selected{/eq}>插件</option>
|
||||
<option value="template" {eq name="type" value="template"}selected{/eq}>模板</option>
|
||||
</select>
|
||||
<select name="order" class="layui-input" style="width:130px;">
|
||||
<option value="new" {eq name="order" value="new"}selected{/eq}>最新上架</option>
|
||||
<option value="hot" {eq name="order" value="hot"}selected{/eq}>最热门</option>
|
||||
<option value="price_asc" {eq name="order" value="price_asc"}selected{/eq}>价格升序</option>
|
||||
<option value="price_desc" {eq name="order" value="price_desc"}selected{/eq}>价格降序</option>
|
||||
</select>
|
||||
<button type="submit" class="layui-btn layui-btn-sm">筛选</button>
|
||||
{if $keyword || $category || $type}<a href="{:url('addon/market')}" class="layui-btn layui-btn-sm layui-btn-primary">清空</a>{/if}
|
||||
</form>
|
||||
<div class="store-wrap">
|
||||
{if empty($list)}
|
||||
<div class="empty">暂无可用插件</div>
|
||||
{else /}
|
||||
{volist name="list" id="it"}
|
||||
<div class="layui-card plugin-card" data-logo="{$it.logo|htmlspecialchars}" data-title="{$it.title|htmlspecialchars}" data-version="{$it.version|htmlspecialchars}" data-author="{$it.author|htmlspecialchars}" data-price="{$it.price}" data-rating="{$it.rating|default=0}" data-intro="{$it.intro|htmlspecialchars}" data-screenshots="{$it.screenshots|default=''|htmlspecialchars}" data-tags="{$it.tags|default=''|htmlspecialchars}" data-name="{$it.name|htmlspecialchars}" data-installed="{$it.installed}" data-upgradable="{$it.upgradable}" data-localversion="{$it.local_version|default=''|htmlspecialchars}" data-category="{$it.category|default=''|htmlspecialchars}" data-download_count="{$it.download_count|default=0}" data-update_at="{$it.update_at|default=0}" data-changelog="{$it.changelog|default=''|htmlspecialchars}" data-require_framework="{$it.require_framework|default=''|htmlspecialchars}" data-type="{$it.type|default='addon'}" data-versions="{:htmlspecialchars(json_encode($it['versions'] ?? []))}">
|
||||
<div class="layui-card-body">
|
||||
{if $it.logo}
|
||||
<img class="plugin-logo" src="{$it.logo}" alt="">
|
||||
{/if}
|
||||
<div class="plugin-title">{$it.title}<span class="ver">v{$it.version}</span>{eq name="it.type" value="template"}<span class="type-badge tpl">模板</span>{/eq}</div>
|
||||
{if $it.category}<span class="plugin-cat">{$it.category}</span>{/if}
|
||||
<div class="plugin-author">作者:{$it.author}</div>
|
||||
{if $it.rating > 0}<div class="plugin-rate">★ <span>{$it.rating|default='0.0'}</span></div>{/if}
|
||||
{if !empty($it.tag_list)}<div class="plugin-tags">{volist name="it.tag_list" id="t"}<span class="plugin-cat">{$t}</span> {/volist}</div>{/if}
|
||||
<div class="plugin-intro">{$it.intro}</div>
|
||||
<div class="plugin-foot">
|
||||
{if $it.price > 0}
|
||||
<span class="price">¥{$it.price}</span>
|
||||
{else /}
|
||||
<span class="price free">免费</span>
|
||||
{/if}
|
||||
{if $it.installed}
|
||||
{if $it.upgradable}
|
||||
<button class="layui-btn layui-btn-xs layui-btn-warm" data-act="install" data-name="{$it.name}" data-version="{$it.version}" data-type="{$it.type|default='addon'}">升级</button>
|
||||
{else /}
|
||||
<span class="layui-badge layui-bg-green">已安装 v{$it.local_version}</span>
|
||||
{/if}
|
||||
{else /}
|
||||
<button class="layui-btn layui-btn-xs layui-btn-normal" data-act="install" data-name="{$it.name}" data-version="{$it.version}" data-type="{$it.type|default='addon'}">安装</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/volist}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.store-wrap{max-width:1100px;margin:20px auto;padding:0 14px;display:flex;flex-wrap:wrap;gap:14px;}
|
||||
.plugin-card{width:calc(33.333% - 10px);min-width:260px;flex:1 1 260px;cursor:pointer;transition:box-shadow .2s,transform .2s;}
|
||||
.plugin-card:hover{box-shadow:0 6px 20px rgba(0,0,0,.12);transform:translateY(-2px);}
|
||||
.plugin-card .layui-card-body{padding:18px;}
|
||||
.plugin-logo{width:48px;height:48px;border-radius:8px;object-fit:cover;float:left;margin-right:12px;background:#eee;}
|
||||
.plugin-title{font-size:16px;font-weight:700;line-height:24px;}
|
||||
.plugin-title .ver{color:#999;font-size:12px;font-weight:400;margin-left:6px;}
|
||||
.plugin-author{color:#999;font-size:12px;line-height:20px;}
|
||||
.plugin-cat{display:inline-block;font-size:11px;color:#1e80ff;background:#e8f3ff;border-radius:10px;padding:1px 8px;margin:2px 4px 2px 0;vertical-align:middle;}
|
||||
.type-badge{display:inline-block;font-size:11px;font-weight:400;border-radius:10px;padding:1px 8px;margin-left:6px;vertical-align:middle;}
|
||||
.type-badge.tpl{color:#722ed1;background:#f4eefe;}
|
||||
.plugin-rate{color:#ff9f00;font-size:12px;line-height:20px;}
|
||||
.plugin-rate span{color:#ff9f00;font-weight:700;}
|
||||
.plugin-tags{margin:4px 0;}
|
||||
.store-search .layui-input{display:inline-block;}
|
||||
.plugin-intro{color:#666;font-size:13px;line-height:22px;margin:12px 0;min-height:44px;}
|
||||
.plugin-foot{display:flex;align-items:center;justify-content:space-between;}
|
||||
.price{color:#e4393c;font-weight:700;font-size:16px;}
|
||||
.price.free{color:#18a058;}
|
||||
.empty{text-align:center;color:#999;padding:80px 0;width:100%;}
|
||||
.mode-badge{display:inline-block;font-size:12px;font-weight:400;padding:2px 10px;border-radius:12px;margin-left:10px;}
|
||||
.mode-badge.client{background:#e8f3ff;color:#1e80ff;}
|
||||
.mode-badge.center{background:#e8f7ef;color:#18a058;}
|
||||
.store-banner{padding:10px 20px;font-size:13px;}
|
||||
.store-banner.err{background:#fde2e2;color:#d03050;}
|
||||
|
||||
/* 详情弹窗 */
|
||||
.detail-pop{padding:20px;color:#333;}
|
||||
.dp-head{display:flex;align-items:flex-start;gap:14px;}
|
||||
.dp-logo{width:64px;height:64px;border-radius:10px;object-fit:cover;background:#eee;flex:0 0 auto;}
|
||||
.dp-meta{flex:1 1 auto;min-width:0;}
|
||||
.dp-title{font-size:18px;font-weight:700;}
|
||||
.dp-title .ver{color:#999;font-size:12px;font-weight:400;margin-left:6px;}
|
||||
.dp-author{color:#999;font-size:12px;line-height:22px;}
|
||||
.dp-rate{color:#ff9f00;font-size:13px;line-height:22px;}
|
||||
.dp-rate .rate-num{color:#999;margin-left:4px;}
|
||||
.dp-tags{margin-top:4px;}
|
||||
.dp-price{text-align:right;flex:0 0 auto;}
|
||||
.dp-gal{margin:16px 0;}
|
||||
.dp-main{width:100%;max-height:320px;object-fit:contain;background:#f5f5f5;border-radius:8px;}
|
||||
.dp-thumbs{display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;}
|
||||
.shot-thumb{width:64px;height:64px;object-fit:cover;border-radius:6px;border:2px solid transparent;cursor:pointer;background:#eee;}
|
||||
.shot-thumb.active{border-color:#1e80ff;}
|
||||
.dp-intro{color:#555;font-size:14px;line-height:24px;margin:12px 0;}
|
||||
.dp-changelog{color:#555;font-size:13px;line-height:1.8;margin:4px 0;white-space:normal;word-break:break-word;}
|
||||
.dp-foot{text-align:right;margin-top:10px;}
|
||||
.dp-ver-sel{font-size:13px;font-weight:400;color:#333;border:1px solid #d9d9d9;border-radius:4px;padding:2px 6px;margin-left:6px;vertical-align:middle;background:#fff;cursor:pointer;}
|
||||
.dp-meta-extra{display:flex;flex-wrap:wrap;gap:16px;margin-top:10px;padding-top:10px;border-top:1px dashed #eee;color:#777;font-size:13px;}
|
||||
.dp-meta-extra .mi b{color:#333;font-weight:600;}
|
||||
.dp-section{margin-top:18px;}
|
||||
.dp-section h4{font-size:14px;font-weight:700;color:#333;margin:0 0 10px;padding-left:8px;border-left:3px solid #1e80ff;}
|
||||
.dp-versions{display:flex;flex-direction:column;gap:8px;}
|
||||
.ver-item{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border:1px solid #eee;border-radius:8px;cursor:pointer;transition:border-color .15s,background .15s;}
|
||||
.ver-item:hover{border-color:#1e80ff;}
|
||||
.ver-item.active{background:#e8f3ff;border-color:#1e80ff;}
|
||||
.ver-item .ver-name{font-weight:600;color:#333;}
|
||||
.ver-item .ver-date{color:#999;font-size:12px;}
|
||||
.ver-item .ver-price{color:#e4393c;font-weight:600;font-size:13px;}
|
||||
.ver-item .ver-price.free{color:#18a058;}
|
||||
@media (max-width:768px){.plugin-card{width:100%;}}
|
||||
</style>
|
||||
<script>
|
||||
layui.use(['layer', 'http'], function () {
|
||||
var layer = layui.layer, http = layui.http, $ = layui.$;
|
||||
|
||||
// 解析逗号分隔或 JSON 数组文本为列表
|
||||
function parseList(s) {
|
||||
s = (s || '').trim();
|
||||
if (!s) return [];
|
||||
if (s.charAt(0) === '[') {
|
||||
try { return JSON.parse(s); } catch (e) {}
|
||||
}
|
||||
return s.split(',').map(function (x) { return x.trim(); }).filter(Boolean);
|
||||
}
|
||||
|
||||
// 评分星级
|
||||
function starsHtml(r) {
|
||||
r = parseFloat(r) || 0;
|
||||
var html = '';
|
||||
for (var i = 1; i <= 5; i++) {
|
||||
if (r >= i) html += '<i class="star on">★</i>';
|
||||
else if (r >= i - 0.5) html += '<i class="star half">★</i>';
|
||||
else html += '<i class="star">★</i>';
|
||||
}
|
||||
return html + ' <span class="rate-num">' + r.toFixed(1) + '</span>';
|
||||
}
|
||||
|
||||
// 简单版本号比较:a>b 返回 1,a<b 返回 -1,相等 0
|
||||
function cmpVer(a, b) {
|
||||
var pa = String(a || '0').split('.'), pb = String(b || '0').split('.');
|
||||
for (var i = 0; i < Math.max(pa.length, pb.length); i++) {
|
||||
var x = parseInt(pa[i] || 0, 10), y = parseInt(pb[i] || 0, 10);
|
||||
if (x !== y) return x > y ? 1 : -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function priceHtmlOf(p) {
|
||||
return (parseFloat(p) > 0)
|
||||
? '<span class="price">¥' + p + '</span>'
|
||||
: '<span class="price free">免费</span>';
|
||||
}
|
||||
|
||||
// 按所选版本生成操作按钮(已装同版=徽章;已装低版=升级;未装=安装)
|
||||
function actBtnOf(d, ver) {
|
||||
var tAttr = ' data-type="' + (d.type || 'addon') + '"';
|
||||
if (d.installed) {
|
||||
if (cmpVer(ver, d.localVersion) > 0) {
|
||||
return '<button class="layui-btn layui-btn-warm layui-btn-sm" data-act="install" data-name="' + d.name + '" data-version="' + ver + '"' + tAttr + '>升级到 v' + ver + '</button>';
|
||||
}
|
||||
if (cmpVer(ver, d.localVersion) === 0) {
|
||||
return '<span class="layui-badge layui-bg-green">已安装 v' + d.localVersion + '</span>';
|
||||
}
|
||||
return '<button class="layui-btn layui-btn-primary layui-btn-sm" data-act="install" data-name="' + d.name + '" data-version="' + ver + '"' + tAttr + '>安装 v' + ver + '(低于本地 v' + d.localVersion + ')</button>';
|
||||
}
|
||||
return '<button class="layui-btn layui-btn-normal layui-btn-sm" data-act="install" data-name="' + d.name + '" data-version="' + ver + '"' + tAttr + '>安装 v' + ver + '</button>';
|
||||
}
|
||||
|
||||
// 时间戳格式化为 YYYY-MM-DD
|
||||
function fmtDate(ts) {
|
||||
ts = parseInt(ts || 0, 10);
|
||||
if (!ts) return '';
|
||||
var d = new Date(ts * 1000);
|
||||
var p = function (n) { return (n < 10 ? '0' : '') + n; };
|
||||
return d.getFullYear() + '-' + p(d.getMonth() + 1) + '-' + p(d.getDate());
|
||||
}
|
||||
|
||||
// HTML 转义(防 XSS)
|
||||
function escapeHtml(s) {
|
||||
return String(s == null ? '' : s)
|
||||
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
||||
.replace(/"/g, '"').replace(/'/g, ''');
|
||||
}
|
||||
// 换行转 <br>
|
||||
function nl2br(s) {
|
||||
return String(s == null ? '' : s).replace(/\r\n|\r|\n/g, '<br>');
|
||||
}
|
||||
|
||||
function openDetail(d) {
|
||||
var shots = parseList(d.screenshots);
|
||||
var mainShot = shots.length ? shots[0] : (d.logo || '');
|
||||
var thumbs = shots.map(function (u, i) {
|
||||
return '<img class="shot-thumb' + (i === 0 ? ' active' : '') + '" src="' + u + '" data-src="' + u + '">';
|
||||
}).join('');
|
||||
var tags = parseList(d.tags).map(function (t) {
|
||||
return '<span class="plugin-cat">' + t + '</span>';
|
||||
}).join('');
|
||||
|
||||
// 历史版本(服务端已按版本号降序返回);无 versions 时退化为当前版本单项
|
||||
var versions = [];
|
||||
try { versions = JSON.parse(d.versions || '[]'); } catch (e) {}
|
||||
if (!versions || !versions.length) versions = [{ version: d.version, price: d.price, update_at: d.updateAt || 0 }];
|
||||
|
||||
// 版本选择:多版本时渲染下拉,否则只显示版本号
|
||||
var verSelHtml;
|
||||
if (versions.length > 1) {
|
||||
var opts = versions.map(function (v, i) {
|
||||
var tag = (parseFloat(v.price) > 0) ? '¥' + v.price : '免费';
|
||||
return '<option value="' + i + '"' + (i === 0 ? ' selected' : '') + '>v' + v.version + '(' + tag + ')' + (i === 0 ? ' · 最新' : '') + '</option>';
|
||||
}).join('');
|
||||
verSelHtml = '<select class="dp-ver-sel" id="dpVerSel">' + opts + '</select>';
|
||||
} else {
|
||||
verSelHtml = '<span class="ver">v' + versions[0].version + '</span>';
|
||||
}
|
||||
|
||||
// 版本历史区块(DZ 风格:列出全部版本,点击切换)
|
||||
var verHistory = versions.map(function (v, i) {
|
||||
var pt = (parseFloat(v.price) > 0) ? '¥' + v.price : '免费';
|
||||
return '<div class="ver-item' + (i === 0 ? ' active' : '') + '" data-idx="' + i + '">'
|
||||
+ '<span class="ver-name">v' + v.version + (i === 0 ? ' · 最新' : '') + '</span>'
|
||||
+ '<span class="ver-date">' + (v.update_at ? fmtDate(v.update_at) : '—') + '</span>'
|
||||
+ '<span class="ver-price' + (parseFloat(v.price) > 0 ? '' : ' free') + '">' + pt + '</span>'
|
||||
+ '</div>';
|
||||
}).join('');
|
||||
|
||||
var cur = versions[0];
|
||||
// 信息栏:评分 / 下载量 / 更新时间 / 分类
|
||||
var extra = ''
|
||||
+ (d.rating > 0 ? '<span class="mi">评分:<b>' + (parseFloat(d.rating) || 0).toFixed(1) + '</b></span>' : '')
|
||||
+ (d.downloadCount ? '<span class="mi">下载:<b>' + d.downloadCount + '</b></span>' : '')
|
||||
+ (d.updateAt && fmtDate(d.updateAt) ? '<span class="mi">更新:<b>' + fmtDate(d.updateAt) + '</b></span>' : '')
|
||||
+ (d.category ? '<span class="mi">分类:<b>' + d.category + '</b></span>' : '')
|
||||
+ (d.requireFramework ? '<span class="mi">最低框架:<b>v' + d.requireFramework + '</b></span>' : '');
|
||||
|
||||
var html = ''
|
||||
+ '<div class="detail-pop">'
|
||||
+ '<div class="dp-head">'
|
||||
+ (d.logo ? '<img class="dp-logo" src="' + d.logo + '">' : '')
|
||||
+ '<div class="dp-meta">'
|
||||
+ '<div class="dp-title">' + d.title + ' ' + verSelHtml + '</div>'
|
||||
+ '<div class="dp-author">作者:' + d.author + '</div>'
|
||||
+ '<div class="dp-rate">' + starsHtml(d.rating) + '</div>'
|
||||
+ (tags ? '<div class="dp-tags">' + tags + '</div>' : '')
|
||||
+ '</div>'
|
||||
+ '<div class="dp-price" id="dpPrice">' + priceHtmlOf(cur.price) + '</div>'
|
||||
+ '</div>'
|
||||
+ (extra ? '<div class="dp-meta-extra">' + extra + '</div>' : '')
|
||||
+ (shots.length ? '<div class="dp-gal"><img class="dp-main" src="' + mainShot + '"><div class="dp-thumbs">' + thumbs + '</div></div>' : '')
|
||||
+ '<div class="dp-intro">' + (d.intro || '暂无简介') + '</div>'
|
||||
+ (d.changelog ? '<div class="dp-section"><h4>更新日志</h4><div class="dp-changelog">' + nl2br(escapeHtml(d.changelog)) + '</div></div>' : '')
|
||||
+ (versions.length > 1 ? '<div class="dp-section"><h4>历史版本</h4><div class="dp-versions" id="dpVers">' + verHistory + '</div></div>' : '')
|
||||
+ '<div class="dp-foot" id="dpFoot">' + actBtnOf(d, cur.version) + '</div>'
|
||||
+ '</div>';
|
||||
layer.open({ type: 1, title: false, area: ['680px', 'auto'], shadeClose: true, content: html, success: function () {
|
||||
bindDetailEvents(versions, d);
|
||||
}});
|
||||
}
|
||||
|
||||
// 绑定详情弹窗内交互:截略图切换、版本切换(下拉/历史列表联动价格与安装按钮)
|
||||
function bindDetailEvents(versions, d) {
|
||||
function apply(idx) {
|
||||
var v = versions[idx] || versions[0];
|
||||
$('#dpPrice').html(priceHtmlOf(v.price));
|
||||
$('#dpFoot').html(actBtnOf(d, v.version));
|
||||
$('#dpVerSel').val(String(idx));
|
||||
$('#dpVers .ver-item').removeClass('active').filter('[data-idx="' + idx + '"]').addClass('active');
|
||||
}
|
||||
$('.dp-thumbs .shot-thumb').off('click').on('click', function () {
|
||||
$('.dp-main').attr('src', $(this).data('src'));
|
||||
$('.dp-thumbs .shot-thumb').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
});
|
||||
$('#dpVerSel').off('change').on('change', function () { apply(parseInt(this.value, 10)); });
|
||||
$('#dpVers .ver-item').off('click').on('click', function () { apply(parseInt($(this).data('idx'), 10)); });
|
||||
}
|
||||
|
||||
// 卡片点击(安装按钮除外)打开详情
|
||||
$(document).on('click', '.plugin-card', function (e) {
|
||||
if ($(e.target).closest('[data-act="install"]').length) return;
|
||||
var $c = $(this);
|
||||
openDetail({
|
||||
logo: $c.data('logo'), title: $c.data('title'), version: $c.data('version'),
|
||||
author: $c.data('author'), price: $c.data('price'), rating: $c.data('rating'),
|
||||
intro: $c.data('intro'), screenshots: $c.data('screenshots'), tags: $c.data('tags'),
|
||||
name: $c.data('name'), installed: $c.data('installed') === '1',
|
||||
upgradable: $c.data('upgradable') === '1', localVersion: $c.data('localversion'),
|
||||
category: $c.data('category'), downloadCount: $c.data('download_count'), updateAt: $c.data('update_at'),
|
||||
changelog: $c.data('changelog'), requireFramework: $c.data('require_framework'),
|
||||
type: $c.data('type') || 'addon',
|
||||
versions: $c.attr('data-versions') || '[]'
|
||||
});
|
||||
});
|
||||
|
||||
// 安装 / 升级(卡片与弹窗内按钮共用)
|
||||
$(document).on('click', '[data-act="install"]', function () {
|
||||
var $btn = $(this);
|
||||
var name = $btn.data('name');
|
||||
var version = $btn.data('version');
|
||||
var type = $btn.data('type') || 'addon';
|
||||
var label = type === 'template' ? '模板' : '';
|
||||
layer.confirm('确认安装' + label + '「' + name + '」' + (version ? ' v' + version : '') + '?', function (idx) {
|
||||
layer.close(idx);
|
||||
var loading = layer.load();
|
||||
http.post('{:url("addon/downloadInstall")}', { name: name, version: version, type: type })
|
||||
.then(function (res) {
|
||||
layer.close(loading);
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.message || '安装成功', { icon: 1 });
|
||||
setTimeout(function () { location.reload(); }, 800);
|
||||
} else {
|
||||
layer.msg(res.message || '安装失败', { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
layer.close(loading);
|
||||
layer.msg('请求失败', { icon: 2 });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,60 @@
|
||||
<div class="layui-card" style="margin-bottom:5px;">
|
||||
<div class="layui-card-header" style="display:flex;align-items:center;justify-content:space-between;">
|
||||
<div>
|
||||
<span class="title" style="font-size:18px;font-weight:700;">我的插件</span>
|
||||
{if $is_client}
|
||||
<span class="mode-badge client">客户端模式 · 连接:{$api_url|default=''}</span>
|
||||
{else /}
|
||||
<span class="mode-badge center">服务中心模式(本地市场)</span>
|
||||
{/if}
|
||||
</div>
|
||||
<span>
|
||||
<a href="{:url('addon/market')}" class="layui-btn layui-btn-normal layui-btn-sm">应用市场</a>
|
||||
<a href="{:url('addon/index')}" class="layui-btn layui-btn-primary layui-btn-sm">完整管理</a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="layui-card-body">
|
||||
<div class="store-wrap">
|
||||
{if empty($list)}
|
||||
<div class="empty">本机尚未安装任何插件,去 <a href="{:url('addon/market')}">应用市场</a> 看看吧</div>
|
||||
{else /}
|
||||
{volist name="list" id="it"}
|
||||
<div class="layui-card plugin-card">
|
||||
<div class="layui-card-body">
|
||||
<div class="plugin-title">{$it.title}<span class="ver">v{$it.version}</span></div>
|
||||
<div class="plugin-author">标识:{$it.name} · 作者:{$it.author|default='官方'}</div>
|
||||
<div class="plugin-intro">{$it.description|default=''}</div>
|
||||
<div class="plugin-foot">
|
||||
{if $it.status == 1}
|
||||
<span class="layui-badge layui-bg-green">已启用</span>
|
||||
{else /}
|
||||
<span class="layui-badge">已停用</span>
|
||||
{/if}
|
||||
<span>
|
||||
<a href="{:url('addon/setting')}?addon={$it.name}" class="layui-btn layui-btn-xs layui-btn-primary">配置</a>
|
||||
<a href="{:url('addon/index')}" class="layui-btn layui-btn-xs layui-btn-normal">升级/卸载</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/volist}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.store-wrap{max-width:1100px;margin:20px auto;padding:0 14px;display:flex;flex-wrap:wrap;gap:14px;}
|
||||
.plugin-card{width:calc(33.333% - 10px);min-width:260px;flex:1 1 260px;}
|
||||
.plugin-card .layui-card-body{padding:18px;}
|
||||
.plugin-title{font-size:16px;font-weight:700;line-height:24px;}
|
||||
.plugin-title .ver{color:#999;font-size:12px;font-weight:400;margin-left:6px;}
|
||||
.plugin-author{color:#999;font-size:12px;line-height:20px;}
|
||||
.plugin-intro{color:#666;font-size:13px;line-height:22px;margin:12px 0;min-height:44px;}
|
||||
.plugin-foot{display:flex;align-items:center;justify-content:space-between;}
|
||||
.empty{text-align:center;color:#999;padding:80px 0;width:100%;}
|
||||
.mode-badge{display:inline-block;font-size:12px;font-weight:400;padding:2px 10px;border-radius:12px;margin-left:10px;}
|
||||
.mode-badge.client{background:#e8f3ff;color:#1e80ff;}
|
||||
.mode-badge.center{background:#e8f7ef;color:#18a058;}
|
||||
@media (max-width:768px){.plugin-card{width:100%;}}
|
||||
</style>
|
||||
@@ -0,0 +1,134 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link href="/assets/layui/css/layui.css" rel="stylesheet">
|
||||
<link href="/assets/ywxapp/css/ywxapp.css" rel="stylesheet">
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
body {
|
||||
padding-bottom: 64px;
|
||||
}
|
||||
|
||||
.layui-card {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.layui-card-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.layui-table-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.layui-table-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.layui-table-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<script type="text/javascript">
|
||||
// 全局路径配置:仅注入部署参数,路由方法来自 layui 的 route 模块。
|
||||
// app 为 ThinkPHP 真实应用目录名(backend/member/frontend/home),对应 public/static/<app> 目录。
|
||||
layui.app = {
|
||||
root: "{$site.root|default=''}",
|
||||
assetUrl: "/assets",
|
||||
module: "{$site.module}",
|
||||
realModule: "{$site.app}",
|
||||
routeBase: "{$route_base}",
|
||||
controller: "{$site.controller}",
|
||||
action: "{$site.action}"
|
||||
};
|
||||
</script>
|
||||
<script src="/assets/ywxapp/ywxapp.js" module="{$site.app}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="layui-card" style="margin:15px;">
|
||||
<div class="layui-card-header">插件配置:{$addon}</div>
|
||||
<div class="layui-card-body">
|
||||
{if empty($fields)}
|
||||
<div class="layui-form-mid layui-word-aux">该插件未定义 config.php,暂无可配置项。</div>
|
||||
{else /}
|
||||
<form class="layui-form" lay-filter="cfgForm">
|
||||
{volist name="fields" id="f"}
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">{$f.title}</label>
|
||||
<div class="layui-input-block">
|
||||
{if $f.type == 'textarea'}
|
||||
<textarea name="{$f.name}" class="layui-textarea">{$f.value}</textarea>
|
||||
{elseif $f.type == 'select' /}
|
||||
<select name="{$f.name}">
|
||||
{volist name="$f.options" id="opt"}
|
||||
<option value="{$key}" {if $key==$f.value}selected{/if}>{$opt}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
{elseif $f.type == 'radio' /}
|
||||
{volist name="$f.options" id="opt"}
|
||||
<input type="radio" name="{$f.name}" value="{$key}" title="{$opt}" {if $key==$f.value}checked{/if}>
|
||||
{/volist}
|
||||
{elseif $f.type == 'checkbox' /}
|
||||
{volist name="$f.options" id="opt"}
|
||||
<input type="checkbox" name="{$f.name}[]" value="{$key}" title="{$opt}" {if in_array($key,(array)$f.value)}checked{/if}>
|
||||
{/volist}
|
||||
{elseif $f.type == 'number' /}
|
||||
<input type="number" name="{$f.name}" value="{$f.value}" class="layui-input">
|
||||
{else /}
|
||||
<input type="text" name="{$f.name}" value="{$f.value}" class="layui-input">
|
||||
{/if}
|
||||
{if $f.tip}<div class="layui-form-mid layui-word-aux">{$f.tip}</div>{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/volist}
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="cfgForm">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<script>
|
||||
layui.use(['form', 'layer'], function () {
|
||||
var form = layui.form, $ = layui.jquery, layer = layui.layer;
|
||||
form.on('submit(cfgForm)', function (data) {
|
||||
$.post(window.location.href, data.field, function (r) {
|
||||
if (r.code === 0) {
|
||||
layer.msg(r.message || '保存成功', { icon: 1 });
|
||||
} else {
|
||||
layer.msg(r.message || '保存失败', { icon: 2 });
|
||||
}
|
||||
}, 'json');
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,394 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>插件性能监控</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/assets/layui/css/layui.css">
|
||||
<style>
|
||||
body { background: #f2f3f5; padding: 15px; }
|
||||
.stat-card {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
padding: 20px;
|
||||
margin-bottom: 15px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
}
|
||||
.stat-card .value {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
color: #1e9fff;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.stat-card .label {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
.stat-card.warning .value { color: #ffb800; }
|
||||
.stat-card.danger .value { color: #ff5722; }
|
||||
.stat-card.success .value { color: #5fb878; }
|
||||
|
||||
.chart-container {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
padding: 20px;
|
||||
margin-bottom: 15px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.addon-list-item {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.addon-status {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.addon-status.healthy { background: #5fb878; }
|
||||
.addon-status.warning { background: #ffb800; }
|
||||
.addon-status.danger { background: #ff5722; }
|
||||
|
||||
.performance-bar {
|
||||
height: 8px;
|
||||
background: #f0f0f0;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.performance-bar-fill {
|
||||
height: 100%;
|
||||
background: #1e9fff;
|
||||
transition: width 0.3s;
|
||||
}
|
||||
.performance-bar-fill.warning { background: #ffb800; }
|
||||
.performance-bar-fill.danger { background: #ff5722; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-fluid">
|
||||
<!-- 统计卡片 -->
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md3">
|
||||
<div class="stat-card">
|
||||
<div class="label">总插件数</div>
|
||||
<div class="value" id="totaladdon">-</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="stat-card success">
|
||||
<div class="label">健康插件</div>
|
||||
<div class="value" id="healthyaddon">-</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="stat-card warning">
|
||||
<div class="label">问题插件</div>
|
||||
<div class="value" id="problematicaddon">-</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="stat-card">
|
||||
<div class="label">平均执行时间</div>
|
||||
<div class="value"><span id="avgExecutionTime">-</span> ms</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 性能图表 -->
|
||||
<div class="layui-row layui-col-space15" style="margin-top: 15px;">
|
||||
<div class="layui-col-md6">
|
||||
<div class="chart-container">
|
||||
<div style="margin-bottom: 15px;">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" data-type="execution_time">执行时间</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" data-type="memory_usage">内存使用</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" data-type="success_rate">成功率</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" data-type="call_count">调用次数</button>
|
||||
</div>
|
||||
<div id="performanceChart" style="height: 350px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md6">
|
||||
<div class="chart-container">
|
||||
<div style="margin-bottom: 15px;">
|
||||
<span style="font-weight: bold;">插件性能列表</span>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" id="refreshBtn" style="float: right;">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 刷新
|
||||
</button>
|
||||
</div>
|
||||
<div id="addonList" style="height: 350px; overflow-y: auto;">
|
||||
<div style="text-align: center; color: #999; padding-top: 100px;">
|
||||
加载中...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 热重载统计 -->
|
||||
<div class="layui-row layui-col-space15" style="margin-top: 15px;">
|
||||
<div class="layui-col-md12">
|
||||
<div class="stat-card">
|
||||
<div style="margin-bottom: 15px;">
|
||||
<span style="font-weight: bold;">热重载统计</span>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" id="clearPerfBtn" style="float: right;">
|
||||
<i class="layui-icon layui-icon-delete"></i> 清除性能数据
|
||||
</button>
|
||||
</div>
|
||||
<div id="reloadStats">
|
||||
<div style="text-align: center; color: #999; padding: 20px;">
|
||||
加载中...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
|
||||
<script>
|
||||
layui.use(['jquery', 'layer', 'http'], function() {
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
var http = layui.http;
|
||||
var performanceChart = null;
|
||||
var currentChartType = 'execution_time';
|
||||
|
||||
// 初始化图表
|
||||
function initChart() {
|
||||
performanceChart = echarts.init(document.getElementById('performanceChart'));
|
||||
loadChartData(currentChartType);
|
||||
}
|
||||
|
||||
// 加载图表数据
|
||||
function loadChartData(type) {
|
||||
currentChartType = type;
|
||||
http.get('/backend/addon_monitor/chart', { type: type }).then(function(res) {
|
||||
if (res.code === 0) {
|
||||
updateChart(res.data.chart_data, type);
|
||||
} else {
|
||||
layer.msg('加载图表数据失败', {icon: 2});
|
||||
}
|
||||
}).catch(function() { layer.msg('请求失败', {icon: 2}); });
|
||||
}
|
||||
|
||||
// 更新图表
|
||||
function updateChart(data, type) {
|
||||
var names = data.map(item => item.name);
|
||||
var values = data.map(item => item.value);
|
||||
var title = '';
|
||||
var unit = '';
|
||||
|
||||
switch(type) {
|
||||
case 'execution_time':
|
||||
title = '执行时间 (ms)';
|
||||
unit = 'ms';
|
||||
break;
|
||||
case 'memory_usage':
|
||||
title = '内存使用 (KB)';
|
||||
unit = 'KB';
|
||||
break;
|
||||
case 'success_rate':
|
||||
title = '成功率 (%)';
|
||||
unit = '%';
|
||||
break;
|
||||
case 'call_count':
|
||||
title = '调用次数';
|
||||
unit = '次';
|
||||
break;
|
||||
}
|
||||
|
||||
var option = {
|
||||
title: {
|
||||
text: title,
|
||||
left: 'center'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: function(params) {
|
||||
return params[0].name + ': ' + params[0].value + ' ' + unit;
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: names,
|
||||
axisLabel: {
|
||||
rotate: 45,
|
||||
interval: 0
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: unit
|
||||
},
|
||||
series: [{
|
||||
data: values,
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
color: '#1e9fff'
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
performanceChart.setOption(option);
|
||||
}
|
||||
|
||||
// 加载概览数据
|
||||
function loadOverview() {
|
||||
http.get('/backend/addon_monitor', { action: 'overview' }).then(function(res) {
|
||||
if (res.code === 0) {
|
||||
var data = res.data;
|
||||
$('#totaladdon').text(data.total_addon);
|
||||
$('#healthyaddon').text(data.healthy_addon);
|
||||
$('#problematicaddon').text(data.problematic_addon);
|
||||
$('#avgExecutionTime').text(data.avg_execution_time);
|
||||
|
||||
// 更新重载统计
|
||||
updateReloadStats(data.reload_stats);
|
||||
} else {
|
||||
layer.msg('加载概览数据失败', {icon: 2});
|
||||
}
|
||||
}).catch(function() { layer.msg('请求失败', {icon: 2}); });
|
||||
}
|
||||
|
||||
// 更新重载统计
|
||||
function updateReloadStats(stats) {
|
||||
if (!stats || stats.total_reloads === 0) {
|
||||
$('#reloadStats').html('<div style="text-align: center; color: #999; padding: 20px;">暂无重载数据</div>');
|
||||
return;
|
||||
}
|
||||
|
||||
var html = '<div class="layui-row">';
|
||||
html += '<div class="layui-col-md3"><div class="label">总重载次数</div><div class="value">' + stats.total_reloads + '</div></div>';
|
||||
html += '<div class="layui-col-md3"><div class="label">成功次数</div><div class="value success">' + stats.successful_reloads + '</div></div>';
|
||||
html += '<div class="layui-col-md3"><div class="label">失败次数</div><div class="value danger">' + stats.failed_reloads + '</div></div>';
|
||||
html += '<div class="layui-col-md3"><div class="label">成功率</div><div class="value">' + (stats.total_reloads > 0 ? ((stats.successful_reloads / stats.total_reloads) * 100).toFixed(2) : 0) + '%</div></div>';
|
||||
html += '</div>';
|
||||
|
||||
if (stats.addon && Object.keys(stats.addon).length > 0) {
|
||||
html += '<div style="margin-top: 20px;"><strong>各插件重载状态:</strong></div>';
|
||||
html += '<div style="margin-top: 10px;">';
|
||||
|
||||
for (var addon in stats.addon) {
|
||||
var status = stats.addon[addon];
|
||||
var statusClass = status.status === 'success' ? 'success' : 'danger';
|
||||
var statusText = status.status === 'success' ? '成功' : '失败';
|
||||
var lastReload = status.reload_time ? new Date(status.reload_time * 1000).toLocaleString() : '未重载';
|
||||
|
||||
html += '<div style="padding: 8px 0; border-bottom: 1px solid #f0f0f0;">';
|
||||
html += '<span class="layui-badge layui-bg-' + statusClass + '">' + addon + '</span>';
|
||||
html += ' <span style="color: #666;">' + lastReload + '</span>';
|
||||
html += ' <span style="color: ' + (status.status === 'success' ? '#5fb878' : '#ff5722') + ';">' + statusText + '</span>';
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
$('#reloadStats').html(html);
|
||||
}
|
||||
|
||||
// 加载插件列表
|
||||
function loadAddonList() {
|
||||
http.get('/backend/addon_monitor', { action: 'performance' }).then(function(res) {
|
||||
if (res.code === 0) {
|
||||
renderAddonList(res.data);
|
||||
} else {
|
||||
layer.msg('加载插件列表失败', {icon: 2});
|
||||
}
|
||||
}).catch(function() { layer.msg('请求失败', {icon: 2}); });
|
||||
}
|
||||
|
||||
// 渲染插件列表
|
||||
function renderAddonList(addon) {
|
||||
if (!addon || Object.keys(addon).length === 0) {
|
||||
$('#addonList').html('<div style="text-align: center; color: #999; padding-top: 100px;">暂无插件数据</div>');
|
||||
return;
|
||||
}
|
||||
|
||||
var html = '';
|
||||
for (var addon in addon) {
|
||||
var stats = addon[addon];
|
||||
var statusClass = 'healthy';
|
||||
var statusText = '健康';
|
||||
|
||||
if (stats.success_rate < 90 || stats.avg_execution_time > 1.0) {
|
||||
statusClass = 'danger';
|
||||
statusText = '异常';
|
||||
} else if (stats.avg_execution_time > 0.5 || stats.success_rate < 95) {
|
||||
statusClass = 'warning';
|
||||
statusText = '警告';
|
||||
}
|
||||
|
||||
var execTimePercent = Math.min((stats.avg_execution_time / 2.0) * 100, 100);
|
||||
var execTimeClass = stats.avg_execution_time > 1.0 ? 'danger' : (stats.avg_execution_time > 0.5 ? 'warning' : '');
|
||||
|
||||
html += '<div class="addon-list-item">';
|
||||
html += '<div style="display: flex; justify-content: space-between; align-items: center;">';
|
||||
html += '<div><span class="addon-status ' + statusClass + '"></span><strong>' + addon + '</strong></div>';
|
||||
html += '<span style="font-size: 12px; color: #666;">' + statusText + '</span>';
|
||||
html += '</div>';
|
||||
html += '<div style="margin-top: 10px; font-size: 12px; color: #666;">';
|
||||
html += '<div>调用次数: ' + stats.total_calls + ' | 成功率: ' + stats.success_rate.toFixed(2) + '%</div>';
|
||||
html += '<div style="margin-top: 5px;">平均执行时间: ' + (stats.avg_execution_time * 1000).toFixed(2) + ' ms</div>';
|
||||
html += '<div class="performance-bar">';
|
||||
html += '<div class="performance-bar-fill ' + execTimeClass + '" style="width: ' + execTimePercent + '%;"></div>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
$('#addonList').html(html);
|
||||
}
|
||||
|
||||
// 绑定事件
|
||||
$('button[data-type]').on('click', function() {
|
||||
var type = $(this).data('type');
|
||||
$('button[data-type]').removeClass('layui-btn-normal').addClass('layui-btn-primary');
|
||||
$(this).removeClass('layui-btn-primary').addClass('layui-btn-normal');
|
||||
loadChartData(type);
|
||||
});
|
||||
|
||||
$('#refreshBtn').on('click', function() {
|
||||
loadOverview();
|
||||
loadAddonList();
|
||||
loadChartData(currentChartType);
|
||||
layer.msg('数据已刷新', {icon: 1});
|
||||
});
|
||||
|
||||
$('#clearPerfBtn').on('click', function() {
|
||||
layer.confirm('确定要清除所有性能数据吗?', function(index) {
|
||||
http.get('/backend/addon_monitor', { action: 'clear_performance' }).then(function(res) {
|
||||
layer.close(index);
|
||||
if (res.code === 0) {
|
||||
layer.msg('性能数据已清除', {icon: 1});
|
||||
loadOverview();
|
||||
loadAddonList();
|
||||
} else {
|
||||
layer.msg('清除失败', {icon: 2});
|
||||
}
|
||||
}).catch(function() { layer.msg('请求失败', {icon: 2}); });
|
||||
});
|
||||
});
|
||||
|
||||
// 初始化
|
||||
initChart();
|
||||
loadOverview();
|
||||
loadAddonList();
|
||||
|
||||
// 定时刷新
|
||||
setInterval(function() {
|
||||
loadOverview();
|
||||
}, 30000); // 30秒刷新一次
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,130 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"> </div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="新建节点" lay-event="dataCreate"> <i class="layui-icon layui-icon-add-1"></i> </a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="删除资源" lay-event="dataDelete"><i class="layui-icon layui-icon-delete"></i> </a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="资源回收站" lay-event="dataRecybin"><i class="layui-icon layui-icon-home"></i> </a>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="dataBar">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="编辑节点" lay-event="update" data-perm="admin:edit"><i class="layui-icon layui-icon-edit"></i> </a>
|
||||
{{# if(!d.is_super) { }}
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="删除节点" lay-event="delete" data-perm="admin:delete"><i class="layui-icon layui-icon-delete"></i> </a>
|
||||
{{# } }}
|
||||
</div>
|
||||
</script>
|
||||
<!-- 表格回收站 -->
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"> </div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="dataRecybinTable" lay-filter="dataRecybinTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 回收站数据工具条 -->
|
||||
<script type="text/html" id="dataRecybinBarTpl">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="恢复数据" lay-event="update"><i class="layui-icon layui-icon-edit"></i> </a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="删除节点" lay-event="delete"><i class="layui-icon layui-icon-delete"></i> </a>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 状态开关 -->
|
||||
<script type="text/html" id="statusTpl">
|
||||
<input type="checkbox" name="status" value="{{d.id}}" lay-skin="switch" lay-text="启用|禁用" lay-filter="statusSwitch" {{ d.status == 1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
<!-- 角色显示 -->
|
||||
<script type="text/html" id="roleTpl">
|
||||
{{# if(d.is_super == 1) { }}
|
||||
<span class="role-super">超级管理员</span>
|
||||
{{# } else if(d.role_id == 1) { }}
|
||||
<span class="role-super">超级管理员</span>
|
||||
{{# } else if(d.role_id == 2) { }}
|
||||
<span>普通管理员</span>
|
||||
{{# } else { }}
|
||||
<span>未知角色</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
<!-- 登录信息 -->
|
||||
<script type="text/html" id="loginInfoTpl">
|
||||
<div>登录次数:{{d.login_count}}</div>
|
||||
<div>最后登录:{{ d.login_time }}</div>
|
||||
</script>
|
||||
|
||||
|
||||
<!-- 添加/编辑管理员表单 -->
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form" style="padding: 20px 20px 0;">
|
||||
<input type="hidden" name="id" value="{{d.id||''}}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">账户</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="account" required lay-verify="required|account" placeholder="请输入用户名" autocomplete="off" class="layui-input" value="{{d.account||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">昵称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="nickname" required lay-verify="required" placeholder="请输入真实姓名" autocomplete="off" class="layui-input" value="{{d.nickname||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">角色</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="role_id" lay-verify="required">
|
||||
<option value="">请选择角色</option>
|
||||
<option value="1" {{ (d.role_id==1||d.is_super==1) ? 'selected' : '' }}>超级管理员</option>
|
||||
<option value="2" {{ d.role_id==2 ? 'selected' : '' }}>普通管理员</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">邮箱</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="email" lay-verify="email" placeholder="请输入邮箱" autocomplete="off" class="layui-input" value="{{d.email||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">手机号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="mobile" lay-verify="phone" placeholder="请输入手机号" autocomplete="off" class="layui-input" value="{{d.mobile||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="status" value="1" title="启用" {{ d.status==undefined || d.status==1 ? 'checked' : '' }}>
|
||||
<input type="radio" name="status" value="0" title="禁用" {{ d.status==0 ? 'checked' : '' }}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="passwordGroup" {{ d.id ? 'style="display:none;"' : '' }}>
|
||||
<label class="layui-form-label">密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="password" name="password" required lay-verify="required|pass" placeholder="请输入密码" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-hide" id="resetPwdGroup">
|
||||
<label class="layui-form-label">新密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="password" name="new_password" required lay-verify="required|pass" placeholder="请输入新密码" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">备注</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="remark" placeholder="请输入备注信息" class="layui-textarea">{{d.remark||''}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.use('admin', function () { });
|
||||
</script>
|
||||
@@ -0,0 +1,126 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">充值卡密管理</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="data-search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="cardno" placeholder="卡号" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<select name="status">
|
||||
<option value="">全部状态</option>
|
||||
<option value="0">未售</option>
|
||||
<option value="1">已售</option>
|
||||
<option value="2">已兑换</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="data-search-btn"><i class="layui-icon"></i> 搜索</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="btn-reset">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataCreate" data-perm="card:add"><i class="layui-icon"></i> 新增</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-event="dataBatch" data-perm="card:add"><i class="layui-icon"></i> 批量生成</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="dataDelete" data-perm="card:del"><i class="layui-icon"></i> 删除</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataRecybin" data-perm="card:restore"><i class="layui-icon"></i> 回收站</button>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="dataBar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="update" data-perm="card:edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete" data-perm="card:del">删除</a>
|
||||
</script>
|
||||
<script type="text/html" id="statusTpl">
|
||||
<input type="checkbox" name="status" value="{{ d.id }}" lay-skin="switch" lay-text="开|关" lay-filter="statusSwitch" {{ d.status == 1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form" id="wxapp-form" lay-filter="wxapp-form" style="padding:15px;">
|
||||
<input type="hidden" name="id" value="{{ d.id || '' }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">卡号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="cardno" placeholder="请输入卡号" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="password" placeholder="请输入密码" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">面值</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="amount" placeholder="请输入面值" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="status" lay-skin="switch" lay-text="启用|禁用" value="1" checked>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="sort" placeholder="请输入排序" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="batchFormTpl">
|
||||
<form class="layui-form" id="wxapp-batch-form" lay-filter="wxapp-batch-form" style="padding:15px;">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">生成数量</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="count" value="10" min="1" max="200" class="layui-input" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">面值(元)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="amount" value="10" step="0.01" min="0.01" class="layui-input" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">卡号前缀</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="prefix" placeholder="可选,如 YX" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="batchResultTpl">
|
||||
<div class="layui-form" style="padding:10px;">
|
||||
<blockquote class="layui-elem-quote">已生成 {{ d.list.length }} 张卡密,请妥善保管:</blockquote>
|
||||
<table class="layui-table">
|
||||
<thead><tr><th>卡号</th><th>密码</th><th>面值</th></tr></thead>
|
||||
<tbody>
|
||||
{{# layui.each(d.list, function(i, item){ }}
|
||||
<tr><td>{{ item.cardno }}</td><td>{{ item.password }}</td><td>{{ d.amount }}</td></tr>
|
||||
{{# }); }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<table class="layui-hide" id="dataRecybinTable" lay-filter="dataRecybinTable"></table>
|
||||
<script type="text/html" id="dataRecybinBarTpl">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="restore" data-perm="card:restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="forcedelete" data-perm="card:destroy">彻底删除</a>
|
||||
</script>
|
||||
</script>
|
||||
<script>
|
||||
layui.use('card', layui.factory('card'));
|
||||
</script>
|
||||
@@ -0,0 +1,11 @@
|
||||
<div class="layui-card" style="margin:15px;">
|
||||
<div class="layui-card-header">聊天管理</div>
|
||||
<div class="layui-card-body">
|
||||
<p>聊天功能由 <b>wxchat</b> 插件(基于 GatewayWorker)提供,本页为后台入口占位说明。</p>
|
||||
<ul class="layui-text" style="line-height:2;">
|
||||
<li>实时聊天、好友 / 群组、消息记录由 wxchat 插件服务承载;</li>
|
||||
<li>相关配置请在「插件管理 → 配置」中维护 <b>wxchat</b> 插件;</li>
|
||||
<li>若需查看在线连接 / 消息吞吐,请前往 MQTT 代理(<b>mqttbroker</b> 插件)后台。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,81 @@
|
||||
<!--
|
||||
* @Author: YwxApp <ywx@ywxapp.cn>
|
||||
* @Date: 2026-08-06 22:05:38
|
||||
* @LastEditors: YwxApp <ywx@ywxapp.cn>
|
||||
* @LastEditTime: 2026-08-07 09:12:10
|
||||
* @Description:
|
||||
* @FilePath: \ywxapp_dev\app\backend\view\common\layout.html
|
||||
* @CustomString: Copyright (c) 2026 YwxApp
|
||||
-->
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>{$title | default='YwxApp'}</title>
|
||||
<meta name="renderer" content="webkit" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||
<link href="/assets/layui/css/layui.css" rel="stylesheet" />
|
||||
<link href="/assets/ywxapp/css/ywxapp.css" rel="stylesheet" />
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.layui-fluid {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.layui-card {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.layui-card-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.layui-table-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.layui-table-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.layui-table-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<script type="text/javascript">
|
||||
layui.app = {
|
||||
root: "{$site.root|default=''}",
|
||||
assetUrl: "/assets",
|
||||
module: "{$site.module}",
|
||||
app: "{$site.app}",
|
||||
routeBase: "{$route_base}",
|
||||
controller: "{$site.controller}",
|
||||
action: "{$site.action}"
|
||||
};
|
||||
</script>
|
||||
<script src="/assets/ywxapp/ywxapp.js" module="{$site.app}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{__CONTENT__}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,127 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"></div>
|
||||
<div class="layui-card-header">
|
||||
<div class="form-container">
|
||||
<div id="formView"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表单模板 -->
|
||||
<script type="text/html" id="formTpl">
|
||||
<div class="layui-tab layui-tab-brief" lay-filter="formTab">
|
||||
<ul class="layui-tab-title">
|
||||
{{# layui.each(d.groups, function(index, group){ }}
|
||||
<li class="{{# if(index === 0){ }}layui-this{{# } }}">{{ group }}</li>
|
||||
{{# }); }}
|
||||
</ul>
|
||||
|
||||
<div class="layui-tab-content">
|
||||
{{# layui.each(d.groups, function(groupIndex, group){ }}
|
||||
<div class="layui-tab-item {{# if(groupIndex === 0){ }}layui-show{{# } }}">
|
||||
<form class="layui-form" lay-filter="form-{{ group }}">
|
||||
<div class="form-group-title">{{ group }} 设置</div>
|
||||
|
||||
{{# layui.each(d.data[group], function(fieldIndex, field){ }}
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">{{ field.title }}</label>
|
||||
<div class="layui-input-block">
|
||||
{{# if(field.type === 'string' || field.type === 'text'){ }}
|
||||
<!-- 文本输入框 -->
|
||||
<input type="text"
|
||||
name="{{ field.name }}"
|
||||
value="{{ field.value || '' }}"
|
||||
placeholder="{{ field.tip || '请输入' + field.title }}"
|
||||
class="layui-input"
|
||||
{{# if(field.rule === 'required'){ }}lay-verify="required"{{# } }}>
|
||||
|
||||
{{# } else if(field.type === 'textarea'){ }}
|
||||
<!-- 文本域 -->
|
||||
<textarea name="{{ field.name }}"
|
||||
placeholder="{{ field.tip || '请输入' + field.title }}"
|
||||
class="layui-textarea"
|
||||
{{# if(field.rule === 'required'){ }}lay-verify="required"{{# } }}>{{ field.value || '' }}</textarea>
|
||||
|
||||
{{# } else if(field.type === 'select'){ }}
|
||||
<!-- 下拉选择框 -->
|
||||
<select name="{{ field.name }}"
|
||||
{{# if(field.rule === 'required'){ }}lay-verify="required"{{# } }}>
|
||||
<option value="">请选择{{ field.title }}</option>
|
||||
{{#
|
||||
var options = field.content ? field.content.split(',') : [];
|
||||
layui.each(options, function(optIndex, option){
|
||||
}}
|
||||
<option value="{{ option }}" {{# if(field.value == option){ }}selected{{# } }}>{{ option }}</option>
|
||||
{{# }); }}
|
||||
</select>
|
||||
|
||||
{{# } else if(field.type === 'checkbox'){ }}
|
||||
<!-- 复选框 -->
|
||||
{{#
|
||||
var checkboxes = field.content ? field.content.split(',') : [];
|
||||
layui.each(checkboxes, function(cbIndex, cbValue){
|
||||
}}
|
||||
<input type="checkbox"
|
||||
name="{{ field.name }}"
|
||||
title="{{ cbValue }}"
|
||||
value="{{ cbValue }}"
|
||||
{{# if(field.value && field.value.indexOf(cbValue) !== -1){ }}checked{{# } }}
|
||||
lay-skin="primary">
|
||||
{{# }); }}
|
||||
|
||||
{{# } else if(field.type === 'radio'){ }}
|
||||
<!-- 单选框 -->
|
||||
{{#
|
||||
var radios = field.content ? field.content.split(',') : [];
|
||||
layui.each(radios, function(rdIndex, rdValue){
|
||||
}}
|
||||
<input type="radio"
|
||||
name="{{ field.name }}"
|
||||
title="{{ rdValue }}"
|
||||
value="{{ rdValue }}"
|
||||
{{# if(field.value == rdValue){ }}checked{{# } }}>
|
||||
{{# }); }}
|
||||
|
||||
{{# } else if(field.type === 'number'){ }}
|
||||
<!-- 数字输入框 -->
|
||||
<input type="number"
|
||||
name="{{ field.name }}"
|
||||
value="{{ field.value || '' }}"
|
||||
placeholder="{{ field.tip || '请输入' + field.title }}"
|
||||
class="layui-input"
|
||||
{{# if(field.rule === 'required'){ }}lay-verify="required|number"{{# } }}>
|
||||
|
||||
{{# } else if(field.type === 'date'){ }}
|
||||
<!-- 日期选择器 -->
|
||||
<input type="text"
|
||||
name="{{ field.name }}"
|
||||
value="{{ field.value || '' }}"
|
||||
placeholder="{{ field.tip || '请选择日期' }}"
|
||||
class="layui-input"
|
||||
id="date-{{ field.id }}">
|
||||
{{# } }}
|
||||
|
||||
{{# if(field.tip){ }}
|
||||
<div class="form-item-tip">{{ field.tip }}</div>
|
||||
{{# } }}
|
||||
</div>
|
||||
</div>
|
||||
{{# }); }}
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button type="button" class="layui-btn" lay-submit lay-filter="submit-{{ group }}">保存设置</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{# }); }}
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
layui.use('configure')
|
||||
</script>
|
||||
@@ -0,0 +1,302 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row layui-col-space15">
|
||||
|
||||
<div class="layui-col-sm6 layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
访问量
|
||||
<span class="layui-badge layui-bg-blue layuiadmin-badge">周</span>
|
||||
</div>
|
||||
<div class="layui-card-body layuiadmin-card-list">
|
||||
<p class="layuiadmin-big-font">9,999,888</p>
|
||||
<p>
|
||||
总计访问量
|
||||
<span class="layuiadmin-span-color">88万 <i class="layui-inline layui-icon layui-icon-flag"></i></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm6 layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
下载
|
||||
<span class="layui-badge layui-bg-cyan layuiadmin-badge">月</span>
|
||||
</div>
|
||||
<div class="layui-card-body layuiadmin-card-list">
|
||||
<p class="layuiadmin-big-font">33,555</p>
|
||||
<p>
|
||||
新下载
|
||||
<span class="layuiadmin-span-color">10% <i class="layui-inline layui-icon layui-icon-face-smile-b"></i></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm6 layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
点赞
|
||||
<span class="layui-badge layui-bg-green layuiadmin-badge">年</span>
|
||||
</div>
|
||||
<div class="layui-card-body layuiadmin-card-list">
|
||||
|
||||
<p class="layuiadmin-big-font">999,888</p>
|
||||
<p>
|
||||
总赞
|
||||
<span class="layuiadmin-span-color">*** <i class="layui-inline layui-icon layui-icon-heart"></i></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm6 layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
活跃用户
|
||||
<span class="layui-badge layui-bg-orange layuiadmin-badge">月</span>
|
||||
</div>
|
||||
<div class="layui-card-body layuiadmin-card-list">
|
||||
|
||||
<p class="layuiadmin-big-font">66,888</p>
|
||||
<p>
|
||||
最近一个月
|
||||
<span class="layuiadmin-span-color">15% <i class="layui-inline layui-icon layui-icon-user"></i></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
访问量
|
||||
<div class="layui-btn-group layuiadmin-btn-group">
|
||||
<a href="javascript:;" class="layui-btn layui-btn-primary layui-btn-xs">去年</a>
|
||||
<a href="javascript:;" class="layui-btn layui-btn-primary layui-btn-xs">今年</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-sm8">
|
||||
<div class="layui-carousel layadmin-carousel layadmin-dataview" data-anim="fade" lay-filter="LAY-index-pagetwo">
|
||||
<div carousel-item id="LAY-index-pagetwo">
|
||||
<div><i class="layui-icon layui-icon-loading1 layadmin-loading"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm4">
|
||||
<div class="layuiadmin-card-list">
|
||||
<p class="layuiadmin-normal-font">月访问数</p>
|
||||
<span>同上期增长</span>
|
||||
<div class="layui-progress layui-progress-big" lay-showPercent="yes">
|
||||
<div class="layui-progress-bar" lay-percent="30%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layuiadmin-card-list">
|
||||
<p class="layuiadmin-normal-font">月下载数</p>
|
||||
<span>同上期增长</span>
|
||||
<div class="layui-progress layui-progress-big" lay-showPercent="yes">
|
||||
<div class="layui-progress-bar" lay-percent="20%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layuiadmin-card-list">
|
||||
<p class="layuiadmin-normal-font">月点赞数</p>
|
||||
<span>同上期增长</span>
|
||||
<div class="layui-progress layui-progress-big" lay-showPercent="yes">
|
||||
<div class="layui-progress-bar" lay-percent="25%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm4">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">用户留言</div>
|
||||
<div class="layui-card-body">
|
||||
<ul class="layuiadmin-card-status layuiadmin-home2-usernote">
|
||||
<li>
|
||||
<h3>张三</h3>
|
||||
<p>哦好吧</p>
|
||||
<span>5月30日 00:00</span>
|
||||
<a href="javascript:;" layadmin-event="replyNote" data-id="7" class="layui-btn layui-btn-xs layuiadmin-reply">回复</a>
|
||||
</li>
|
||||
<li>
|
||||
<h3>李白</h3>
|
||||
<p>应是天仙狂醉,乱把白云揉碎</p>
|
||||
<span>5月02日 00:00</span>
|
||||
<a href="javascript:;" layadmin-event="replyNote" data-id="5" class="layui-btn layui-btn-xs layuiadmin-reply">回复</a>
|
||||
</li>
|
||||
<li>
|
||||
<h3>张三</h3>
|
||||
<p>嗯嗯</p>
|
||||
<span>5月11日 00:00</span>
|
||||
<a href="javascript:;" layadmin-event="replyNote" data-id="6" class="layui-btn layui-btn-xs layuiadmin-reply">回复</a>
|
||||
</li>
|
||||
<li>
|
||||
<h3>杜甫</h3>
|
||||
<p>人才虽高,不务学问,不能致圣。刘向十日画一水,五日画一石。</p>
|
||||
<span>4月11日 00:00</span>
|
||||
<a href="javascript:;" layadmin-event="replyNote" data-id="2" class="layui-btn layui-btn-xs layuiadmin-reply">回复</a>
|
||||
</li>
|
||||
<li>
|
||||
<h3>鲁迅</h3>
|
||||
<p>路本是无所谓有和无的,走的人多了,就没路了。。</p>
|
||||
<span>4月28日 00:00</span>
|
||||
<a href="javascript:;" layadmin-event="replyNote" data-id="4" class="layui-btn layui-btn-xs layuiadmin-reply">回复</a>
|
||||
</li>
|
||||
<li>
|
||||
<h3>张爱玲</h3>
|
||||
<p>于千万人之中遇到你所要遇到的人,于千万年之中,时间的无涯的荒野中,没有早一步,也没有晚一步,刚巧赶上了,那也没有别的话好说,唯有轻轻的问一声:“噢,原来你也在这里?”</p>
|
||||
<span>4月11日 00:00</span>
|
||||
<a href="javascript:;" layadmin-event="replyNote" data-id="1" class="layui-btn layui-btn-xs layuiadmin-reply">回复</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm8">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-sm6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">本周活跃用户列表</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table layuiadmin-page-table" lay-skin="line">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>用户名</th>
|
||||
<th>最后登录时间</th>
|
||||
<th>状态</th>
|
||||
<th>获得赞</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><span class="first">张三</span></td>
|
||||
<td><i class="layui-icon layui-icon-log"> 11:20</i></td>
|
||||
<td><span>在线</span></td>
|
||||
<td>22 <i class="layui-icon layui-icon-praise"></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="second">张三</span></td>
|
||||
<td><i class="layui-icon layui-icon-log"> 10:40</i></td>
|
||||
<td><span>在线</span></td>
|
||||
<td>21 <i class="layui-icon layui-icon-praise"></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="third">李四</span></td>
|
||||
<td><i class="layui-icon layui-icon-log"> 01:30</i></td>
|
||||
<td><i>离线</i></td>
|
||||
<td>66 <i class="layui-icon layui-icon-praise"></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>王五</td>
|
||||
<td><i class="layui-icon layui-icon-log"> 21:18</i></td>
|
||||
<td><i>离线</i></td>
|
||||
<td>45 <i class="layui-icon layui-icon-praise"></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>许上进</td>
|
||||
<td><i class="layui-icon layui-icon-log"> 09:30</i></td>
|
||||
<td><span>在线</span></td>
|
||||
<td>21 <i class="layui-icon layui-icon-praise"></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>小蚊子</td>
|
||||
<td><i class="layui-icon layui-icon-log"> 21:18</i></td>
|
||||
<td><i>在线</i></td>
|
||||
<td>45 <i class="layui-icon layui-icon-praise"></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>张三</td>
|
||||
<td><i class="layui-icon layui-icon-log"> 09:30</i></td>
|
||||
<td><span>在线</span></td>
|
||||
<td>21 <i class="layui-icon layui-icon-praise"></i></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">项目进展</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<table id="LAY-index-prograss"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">访客地区分布</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-sm4">
|
||||
<table class="layui-table layuiadmin-page-table" lay-skin="line">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>排名</th>
|
||||
<th>地区</th>
|
||||
<th>人数</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>浙江</td>
|
||||
<td>62310</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>上海</td>
|
||||
<td>59190</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>广东</td>
|
||||
<td>55891</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>4</td>
|
||||
<td>北京</td>
|
||||
<td>51919</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>5</td>
|
||||
<td>山东</td>
|
||||
<td>39231</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>6</td>
|
||||
<td>湖北</td>
|
||||
<td>37109</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="layui-col-sm8">
|
||||
|
||||
<div class="layui-carousel layadmin-carousel layadmin-dataview" data-anim="fade" lay-filter="LAY-index-pagethree">
|
||||
<div carousel-item id="LAY-index-pagethree">
|
||||
<div><i class="layui-icon layui-icon-loading1 layadmin-loading"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/assets/layui/layui.js?t=1"></script>
|
||||
<script src="/assets/ywxapp/ywxapp.js" module="backend"></script>
|
||||
<script>
|
||||
layui.use('console');
|
||||
</script>
|
||||
@@ -0,0 +1,136 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"></div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 表格顶部工具条 -->
|
||||
<script type="text/html" id="tableBarTpl">
|
||||
<div class="layui-btn-group">
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="新建数据"
|
||||
lay-event="dataCreate"
|
||||
data-perm="group:add">
|
||||
<i class="layui-icon layui-icon-add-1"></i>
|
||||
</a>
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="删除资源"
|
||||
lay-event="dataDelete"
|
||||
data-perm="group:delete"
|
||||
><i class="layui-icon layui-icon-delete"></i>
|
||||
</a>
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="资源回收站"
|
||||
lay-event="dataRecybin"
|
||||
data-perm="group:recyclebin"
|
||||
><i class="layui-icon layui-icon-home"></i>
|
||||
</a>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 表格数据工具条 -->
|
||||
<script type="text/html" id="dataBarTpl">
|
||||
<div class="layui-btn-group">
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="编辑数据"
|
||||
lay-event="update"
|
||||
data-perm="group:edit"
|
||||
><i class="layui-icon layui-icon-edit"></i>
|
||||
</a>
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="权限分配"
|
||||
lay-event="permission"
|
||||
data-perm="group:*"
|
||||
><i class="layui-icon layui-icon-auz"></i>
|
||||
</a>
|
||||
{{# if(d.id > 1) { }}
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="删除数据"
|
||||
lay-event="delete"
|
||||
data-perm="group:delete"
|
||||
><i class="layui-icon layui-icon-delete"></i>
|
||||
</a>
|
||||
{{# } }}
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 表格回收站 -->
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"></div>
|
||||
<div class="layui-card-body">
|
||||
<table
|
||||
class="layui-hide"
|
||||
id="dataRecybinTable"
|
||||
lay-filter="dataRecybinTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 角色状态 -->
|
||||
<script type="text/html" id="statusTpl">
|
||||
{{# if(d.status == 1) { }}
|
||||
<span class="layui-badge layui-bg-green">正常</span>
|
||||
{{# } else { }}
|
||||
<span class="layui-badge layui-bg-orange">禁用</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<!-- 添加/编辑角色表单 -->
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form layui-form-pane" lay-filter="wxapp-form" id="wxapp-form">
|
||||
<input type="hidden" name="id" value="{{d.id||''}}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">角色名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" required lay-verify="required" placeholder="请输入角色名称" autocomplete="off" class="layui-input" value="{{d.title||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">编码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" required lay-verify="required" placeholder="请输入分组编码" autocomplete="off" class="layui-input" value="{{d.name||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">角色描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="description" placeholder="请输入角色描述" class="layui-textarea">{{d.description||''}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="status" value="1" title="启用" {{ d.status==undefined || d.status==1 ? 'checked' : '' }}>
|
||||
<input type="radio" name="status" value="0" title="禁用" {{ d.status==0 ? 'checked' : '' }}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-hide">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="wxapp-form-submit" id="wxapp-form-submit">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<!-- 权限分配弹窗 -->
|
||||
<script type="text/html" id="permissionFormTpl">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
角色:{{d.name}}
|
||||
<span style="color:#999;font-weight:normal;">(ID: {{d.id}})</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<div id="permissionTree"></div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
layui.use(["group"], function () {});
|
||||
</script>
|
||||
@@ -0,0 +1,93 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">站点帮助管理</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="data-search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="title" placeholder="标题" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="category" placeholder="分类" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="data-search-btn"><i class="layui-icon"></i> 搜索</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="btn-reset">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataCreate" data-perm="help:add"><i class="layui-icon"></i> 新增</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="dataDelete" data-perm="help:del"><i class="layui-icon"></i> 删除</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataRecybin" data-perm="help:restore"><i class="layui-icon"></i> 回收站</button>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="dataBar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="update" data-perm="help:edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete" data-perm="help:del">删除</a>
|
||||
</script>
|
||||
<script type="text/html" id="categoryTpl">
|
||||
{{# if(d.category){ }}
|
||||
<span class="layui-badge layui-bg-cyan">{{ d.category }}</span>
|
||||
{{# } else { }}
|
||||
<span style="color:#ccc;">未分类</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
<script type="text/html" id="statusTpl">
|
||||
<input type="checkbox" name="status" value="{{ d.id }}" lay-skin="switch" lay-text="开|关" lay-filter="statusSwitch" {{ d.status == 1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form" id="wxapp-form" lay-filter="wxapp-form" style="padding:15px;">
|
||||
<input type="hidden" name="id" value="{{ d.id || '' }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分类</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="category" placeholder="如:新手指南、常见问题、使用说明" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标题</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" placeholder="请输入标题" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">内容</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="content" placeholder="请输入帮助内容" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="sort" placeholder="请输入排序(越大越靠前)" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="status" lay-skin="switch" lay-text="启用|禁用" value="1" checked>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-hide">
|
||||
<button class="layui-btn" id="wxapp-form-submit" lay-submit lay-filter="wxapp-form-submit">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<table class="layui-hide" id="dataRecybinTable" lay-filter="dataRecybinTable"></table>
|
||||
<script type="text/html" id="dataRecybinBarTpl">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="restore" data-perm="help:restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="forcedelete" data-perm="help:destroy">彻底删除</a>
|
||||
</script>
|
||||
</script>
|
||||
<script>
|
||||
layui.use('help', layui.factory('help'));
|
||||
</script>
|
||||
@@ -0,0 +1,175 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<script>
|
||||
/^http(s*):\/\//.test(location.href) || alert('请通过 localhost 访问');;
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link href="/assets/layui/css/layui.css" rel="stylesheet">
|
||||
<link href="/assets/ywxapp/css/ywxapp.css" rel="stylesheet">
|
||||
|
||||
|
||||
|
||||
<body class="layui-layout-body" id="LAY_home_iframe">
|
||||
|
||||
<div id="LAY_app">
|
||||
<div class="layui-layout layui-layout-admin">
|
||||
<div class="layui-header">
|
||||
<!-- 头部区域 -->
|
||||
<ul class="layui-nav layui-layout-left">
|
||||
<li class="layui-nav-item layadmin-flexible" lay-unselect>
|
||||
<a href="javascript:;" layadmin-event="flexible" title="侧边伸缩">
|
||||
<i class="layui-icon layui-icon-shrink-right" id="LAY_app_flexible"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-nav-item layui-hide-xs" lay-unselect>
|
||||
<a href="/" target="_blank" title="前台">
|
||||
<i class="layui-icon layui-icon-website"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-nav-item" lay-unselect>
|
||||
<a href="javascript:;" layadmin-event="refresh" title="刷新">
|
||||
<i class="layui-icon layui-icon-refresh-3"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-nav-item layui-hide-xs" lay-unselect>
|
||||
<input type="text" placeholder="搜索..." autocomplete="off" class="layui-input layui-input-search" layadmin-event="serach" lay-action="template/search.html?keywords=">
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="layui-nav layui-layout-right" lay-filter="layadmin-layout-right">
|
||||
|
||||
<li class="layui-nav-item" lay-unselect>
|
||||
<a lay-href="app/message/index.html" layadmin-event="message" lay-text="消息中心">
|
||||
<i class="layui-icon layui-icon-notice"></i>
|
||||
|
||||
<!-- 如果有新消息,则显示小圆点 -->
|
||||
<span class="layui-badge-dot"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-nav-item layui-hide-xs" lay-unselect>
|
||||
<a href="javascript:;" layadmin-event="note">
|
||||
<i class="layui-icon layui-icon-note"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-nav-item layui-hide-xs" lay-unselect>
|
||||
<a href="javascript:;" layadmin-event="theme">
|
||||
<i class="layui-icon layui-icon-theme"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-nav-item layui-hide-xs" lay-unselect>
|
||||
<a href="javascript:;" layadmin-event="fullscreen">
|
||||
<i class="layui-icon layui-icon-screen-full"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-nav-item" lay-unselect>
|
||||
<a href="javascript:;">
|
||||
<img src="{$user.avatar|default='/static/common/images/avatar.jpg'}" class="layui-nav-img">
|
||||
<cite>{$user.nickname|default='管理员'}</cite>
|
||||
</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a href="javascript:;" lay-href="{:url('Profile/index')}" lay-text="设置用户信息">设置用户信息</a></dd>
|
||||
<dd><a href="javascript:;" lay-href="{:url('Profile/avatar')}" lay-text="设置头像">设置头像</a></dd>
|
||||
<dd><a href="javascript:;" lay-href="{:url('Profile/password')}" lay-text="设置密码">设置密码</a></dd>
|
||||
<hr>
|
||||
<dd layadmin-event="logout" style="text-align: center;"><a>退出</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
|
||||
<li class="layui-nav-item layui-hide-xs" lay-unselect>
|
||||
<a href="javascript:;" layadmin-event="about"><i class="layui-icon layui-icon-more-vertical"></i></a>
|
||||
</li>
|
||||
<li class="layui-nav-item layui-show-xs-inline-block layui-hide-sm" lay-unselect>
|
||||
<a href="javascript:;" layadmin-event="more"><i class="layui-icon layui-icon-more-vertical"></i></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- 侧边菜单 -->
|
||||
<div class="layui-side layui-side-menu">
|
||||
<div class="layui-side-scroll">
|
||||
<div class="layui-logo" lay-href="home/console.html">
|
||||
<span>YwxApp</span>
|
||||
</div>
|
||||
|
||||
<ul class="layui-nav layui-nav-tree" lay-accordion id="LAY-system-side-menu" lay-filter="layadmin-system-side-menu">
|
||||
<li data-name="home" class="layui-nav-item layui-nav-itemed">
|
||||
<a href="javascript:;" lay-tips="主页" lay-direction="2">
|
||||
<i class="layui-icon layui-icon-home"></i>
|
||||
<cite>主页</cite>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
<li data-name="get" class="layui-nav-item">
|
||||
<a href="javascript:;" layadmin-event="about" lay-tips="授权" lay-direction="2">
|
||||
<i class="layui-icon layui-icon-auz"></i>
|
||||
<cite>关于</cite>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 页面标签 -->
|
||||
<div class="layadmin-pagetabs" id="LAY_app_tabs">
|
||||
<div class="layui-icon layadmin-tabs-control layui-icon-prev" layadmin-event="leftPage"></div>
|
||||
<div class="layui-icon layadmin-tabs-control layui-icon-next" layadmin-event="rightPage"></div>
|
||||
<div class="layui-icon layadmin-tabs-control layui-icon-down">
|
||||
<ul class="layui-nav layadmin-tabs-select" lay-filter="layadmin-pagetabs-nav">
|
||||
<li class="layui-nav-item" lay-unselect>
|
||||
<a href="javascript:;"></a>
|
||||
<dl class="layui-nav-child layui-anim-fadein">
|
||||
<dd layadmin-event="closeThisTabs"><a href="javascript:;">关闭当前标签页</a></dd>
|
||||
<dd layadmin-event="closeOtherTabs"><a href="javascript:;">关闭其它标签页</a></dd>
|
||||
<dd layadmin-event="closeRightTabs"><a href="javascript:;">关闭右侧标签页</a></dd>
|
||||
<dd layadmin-event="closeAllTabs"><a href="javascript:;">关闭全部标签页</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="layui-tab" lay-unauto lay-allowClose="true" lay-filter="layadmin-layout-tabs">
|
||||
<ul class="layui-tab-title" id="LAY_app_tabsheader">
|
||||
<li lay-id="/admin/console/index.html" lay-attr="/admin/console/index.html" class="layui-this"><i class="layui-icon layui-icon-home"></i></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 主体内容 -->
|
||||
<div class="layui-body" id="LAY_app_body">
|
||||
<div class="layadmin-tabsbody-item layui-show">
|
||||
<iframe src="/admin/console/index.html" frameborder="0" class="layadmin-iframe"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 辅助元素,一般用于移动设备下遮罩 -->
|
||||
<div class="layadmin-body-shade" layadmin-event="shade"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<script type="text/javascript">
|
||||
layui.app = {
|
||||
root: "{$site.root|default=''}",
|
||||
assetUrl: "/assets",
|
||||
module: "{$site.module}",
|
||||
app: "{$site.app}",
|
||||
routeBase: "{$route_base}",
|
||||
controller: "{$site.controller}",
|
||||
action: "{$site.action}"
|
||||
};
|
||||
</script>
|
||||
<script src="/assets/ywxapp/ywxapp.js" module="{$site.app}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
layui.use(['index']);
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,114 @@
|
||||
<div class="layui-fluid"><div class="layui-card">
|
||||
<div class="layui-card-header">友情链接管理</div>
|
||||
<div class="layui-card-header">
|
||||
<!-- 搜索栏 -->
|
||||
<div class="layui-form layui-card-header-boxed" lay-filter="search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="title" placeholder="请输入网站标题" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="data-search-btn">
|
||||
<i class="layui-icon layui-icon-search"></i>
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-primary" id="btn-reset">
|
||||
<i class="layui-icon layui-icon-refresh"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<!-- 表格容器 -->
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
</div>
|
||||
</div></div>
|
||||
<!-- 顶部工具条 -->
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="新建链接" lay-event="dataCreate" data-perm="links:add"> <i class="layui-icon layui-icon-add-1"></i> </a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="删除资源" lay-event="dataDelete" data-perm="links:delete"><i class="layui-icon layui-icon-delete"></i> </a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="资源回收站" lay-event="dataRecybin" data-perm="links:recyclebin"><i class="layui-icon layui-icon-home"></i> </a>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 操作列模板 -->
|
||||
<script type="text/html" id="dataBar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="update" data-perm="links:edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="delete" data-perm="links:delete">删除</a>
|
||||
</script>
|
||||
|
||||
<!-- 状态开关模板 -->
|
||||
<script type="text/html" id="statusTpl">
|
||||
<input type="checkbox" name="status" value="{{d.id}}" lay-skin="switch" lay-text="启用|禁用" lay-filter="statusSwitch" {{ d.status == 1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<!-- 添加/编辑友链表单(抽屉) -->
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form" style="padding: 20px 20px 0;">
|
||||
<input type="hidden" name="id" value="{{d.id||''}}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标题</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" required lay-verify="required" placeholder="网站标题" autocomplete="off" class="layui-input" value="{{d.title||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">链接</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="url" required lay-verify="required|url" placeholder="链接地址" autocomplete="off" class="layui-input" value="{{d.url||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">logo</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="logo" placeholder="请输入logo地址" autocomplete="off" class="layui-input" value="{{d.logo||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="description" placeholder="请输入网站描述" class="layui-textarea">{{d.description||''}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="sort" lay-verify="required|number" placeholder="请输入排序" autocomplete="off" class="layui-input" value="{{d.sort||'0'}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="status" value="1" title="启用" {{ d.status==undefined || d.status==1 ? 'checked' : '' }}>
|
||||
<input type="radio" name="status" value="0" title="禁用" {{ d.status==0 ? 'checked' : '' }}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-hide">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="wxapp-form-submit" id="wxapp-form-submit">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<!-- 回收站抽屉 -->
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">已删除的友链(可恢复)</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="dataRecybinTable" lay-filter="dataRecybinTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 回收站行操作 -->
|
||||
<script type="text/html" id="dataRecybinBarTpl">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="恢复" lay-event="restore" data-perm="links:restore"><i class="layui-icon layui-icon-edit"></i></a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="彻底删除" lay-event="forcedelete" data-perm="links:delete"><i class="layui-icon layui-icon-delete"></i></a>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
layui.use('links', function () { });
|
||||
</script>
|
||||
@@ -0,0 +1,105 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{$title | default='登录'}</title>
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link href="/assets/layui/css/layui.css" rel="stylesheet">
|
||||
<link href="/assets/ywxapp/css/template.css" rel="stylesheet">
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<style>
|
||||
body {
|
||||
background-color: #f2f3f5;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
|
||||
// 全局路径配置:仅注入部署参数,路由方法来自 layui 的 route 模块。
|
||||
// app 为 ThinkPHP 真实应用目录名(backend/member/frontend/home),对应 public/static/<app> 目录。
|
||||
layui.app = {
|
||||
root: "{$site.root|default=''}",
|
||||
assetUrl: "/assets",
|
||||
module: "{$site.module}",
|
||||
realModule: "{$site.app}",
|
||||
routeBase: "{$route_base}",
|
||||
controller: "{$site.controller}",
|
||||
action: "{$site.action}",
|
||||
devToken: "{$site.devToken}",
|
||||
devAddon: "{$site.devAddon}",
|
||||
};
|
||||
</script>
|
||||
<script src="/assets/ywxapp/ywxapp.js" module="{$site.app}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="layadmin-user-login layadmin-user-display-show" id="LAY-user-login">
|
||||
<div class="layadmin-user-login-main">
|
||||
<div class="layadmin-user-login-box layadmin-user-login-header">
|
||||
<h2>YwxApp后台管理系统</h2>
|
||||
<p> </p>
|
||||
</div>
|
||||
<div class="layadmin-user-login-box layadmin-user-login-body layui-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layadmin-user-login-icon layui-icon layui-icon-username" for="LAY-user-login-username"></label>
|
||||
<input type="text" name="username" id="LAY-user-login-username" lay-verify="required" placeholder="用户名" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layadmin-user-login-icon layui-icon layui-icon-password" for="LAY-user-login-password"></label>
|
||||
<input type="password" name="password" id="LAY-user-login-password" lay-verify="required" placeholder="密码" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-xs7">
|
||||
<label class="layadmin-user-login-icon layui-icon layui-icon-vercode" for="LAY-user-login-vercode"></label>
|
||||
<input type="text" name="captcha" id="LAY-user-login-vercode" lay-verify="required" placeholder="图形验证码" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-col-xs5">
|
||||
<div style="margin-left: 10px;">
|
||||
<img class="layadmin-user-login-codeimg verification-img" lay-filter="verifyCode" src="{:url('ajax/verify')}" alt="点击刷新验证码" style="cursor:pointer;transition:opacity 0.3s" title="点击刷新验证码" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" style="margin-bottom: 20px;">
|
||||
<input type="checkbox" name="remember" lay-skin="primary" title="记住密码">
|
||||
<a href="forget.html" class="layadmin-user-jump-change layadmin-link" style="margin-top: 7px;">忘记密码?</a>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<button class="layui-btn layui-btn-fluid" lay-submit lay-filter="dataSubmit">登 入</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-trans layadmin-user-login-footer">
|
||||
|
||||
<p>© All Rights Reserved</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!--<div class="ladmin-user-login-theme">
|
||||
<script type="text/html" template>
|
||||
<ul>
|
||||
<li data-theme=""><img src="{{ layui.setter.paths.base }}style/imgs/bg-none.jpg"></li>
|
||||
<li data-theme="#03152A" style="background-color: #03152A;"></li>
|
||||
<li data-theme="#2E241B" style="background-color: #2E241B;"></li>
|
||||
<li data-theme="#50314F" style="background-color: #50314F;"></li>
|
||||
<li data-theme="#344058" style="background-color: #344058;"></li>
|
||||
<li data-theme="#20222A" style="background-color: #20222A;"></li>
|
||||
</ul>
|
||||
</script>
|
||||
</div>-->
|
||||
|
||||
</div>
|
||||
<!-- 资 源 引 入 -->
|
||||
|
||||
<script>
|
||||
layui.use('login', function () { });
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,81 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">勋章中心管理</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="data-search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="title" placeholder="标题" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="data-search-btn"><i class="layui-icon"></i> 搜索</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="btn-reset">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataCreate" data-perm="medal:add"><i class="layui-icon"></i> 新增</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="dataDelete" data-perm="medal:del"><i class="layui-icon"></i> 删除</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataRecybin" data-perm="medal:restore"><i class="layui-icon"></i> 回收站</button>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="dataBar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="update" data-perm="medal:edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="grant" data-perm="medal:grant">授予</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete" data-perm="medal:del">删除</a>
|
||||
</script>
|
||||
<script type="text/html" id="statusTpl">
|
||||
<input type="checkbox" name="status" value="{{ d.id }}" lay-skin="switch" lay-text="开|关" lay-filter="statusSwitch" {{ d.status == 1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form" id="wxapp-form" lay-filter="wxapp-form" style="padding:15px;">
|
||||
<input type="hidden" name="id" value="{{ d.id || '' }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">勋章名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" placeholder="请输入勋章名称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">图片</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="image" placeholder="请输入图片" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="description" placeholder="请输入描述" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="sort" placeholder="请输入排序" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="status" lay-skin="switch" lay-text="启用|禁用" value="1" checked>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<table class="layui-hide" id="dataRecybinTable" lay-filter="dataRecybinTable"></table>
|
||||
<script type="text/html" id="dataRecybinBarTpl">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="restore" data-perm="medal:restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="forcedelete" data-perm="medal:destroy">彻底删除</a>
|
||||
</script>
|
||||
</script>
|
||||
<script>
|
||||
layui.use('medal', layui.factory('medal'));
|
||||
</script>
|
||||
@@ -0,0 +1,114 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">主导航菜单管理(前台官网顶部导航,支持两级下拉)</div>
|
||||
<div class="layui-card-header">
|
||||
<div class="layui-form layui-card-header-boxed" lay-filter="search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="title" placeholder="请输入菜单名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="data-search-btn">
|
||||
<i class="layui-icon layui-icon-search"></i>
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-primary" id="btn-reset">
|
||||
<i class="layui-icon layui-icon-refresh"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 顶部工具条 -->
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="新建菜单" lay-event="dataCreate" data-perm="nav:add"> <i class="layui-icon layui-icon-add-1"></i> </a>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 操作列模板 -->
|
||||
<script type="text/html" id="dataBar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="update" data-perm="nav:edit">编辑</a>
|
||||
{{# if(d.parent_id == 0) { }}
|
||||
<a class="layui-btn layui-btn-xs" lay-event="addChild" data-perm="nav:add">加子项</a>
|
||||
{{# } }}
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="delete" data-perm="nav:delete">删除</a>
|
||||
</script>
|
||||
|
||||
<!-- 状态开关模板 -->
|
||||
<script type="text/html" id="statusTpl">
|
||||
<input type="checkbox" name="status" value="{{d.id}}" lay-skin="switch" lay-text="显示|隐藏" lay-filter="statusSwitch" {{ d.status == 1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
|
||||
<!-- 父级标识 -->
|
||||
<script type="text/html" id="parentTpl">
|
||||
{{# if(d.parent_id == 0) { }}
|
||||
<span class="layui-badge layui-bg-blue">一级</span>
|
||||
{{# } else { }}
|
||||
<span class="layui-badge-rim">二级</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<!-- 添加/编辑表单(抽屉) -->
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form" style="padding: 20px 20px 0;">
|
||||
<input type="hidden" name="id" value="{{d.id||''}}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">所属上级</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="parent_id">
|
||||
<option value="0">顶级菜单</option>
|
||||
{{# layui.each(d.parents || [], function(idx, p){ }}
|
||||
<option value="{{p.id}}" {{ d.parent_id == p.id ? 'selected' : '' }}>{{p.title}}</option>
|
||||
{{# }); }}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">菜单名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" required lay-verify="required" placeholder="如:首页 / 产品 / 案例" autocomplete="off" class="layui-input" value="{{d.title||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">链接</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="url" placeholder="controller/action 或 外链 http(s)://" autocomplete="off" class="layui-input" value="{{d.url||''}}">
|
||||
<div class="layui-form-mid layui-word-aux">留空表示仅作为含有子项的父菜单(下拉)。</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">图标</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="icon" placeholder="layui-icon 类名(可选)" autocomplete="off" class="layui-input" value="{{d.icon||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" placeholder="数字越小越靠前" autocomplete="off" class="layui-input" value="{{d.sort||0}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="status" value="1" title="显示" {{ d.status==undefined || d.status==1 ? 'checked' : '' }}>
|
||||
<input type="radio" name="status" value="0" title="隐藏" {{ d.status==0 ? 'checked' : '' }}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-hide">
|
||||
<button class="layui-btn" lay-submit lay-filter="wxapp-form-submit" id="wxapp-form-submit">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
console.log('nav index');
|
||||
layui.use('navbar', function () { });
|
||||
console.log(layui.nav);
|
||||
</script>
|
||||
@@ -0,0 +1,145 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">站点公告管理</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="data-search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="title" placeholder="标题" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<select name="type" lay-search="">
|
||||
<option value="">全部类型</option>
|
||||
<option value="1">系统维护</option>
|
||||
<option value="2">活动公告</option>
|
||||
<option value="3">版本更新</option>
|
||||
<option value="4">其他</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="data-search-btn"><i class="layui-icon"></i> 搜索</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="btn-reset">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataCreate" data-perm="notice:add"><i class="layui-icon"></i> 新增</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="dataDelete" data-perm="notice:del"><i class="layui-icon"></i> 删除</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataRecybin" data-perm="notice:restore"><i class="layui-icon"></i> 回收站</button>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="dataBar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="update" data-perm="notice:edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete" data-perm="notice:del">删除</a>
|
||||
</script>
|
||||
<script type="text/html" id="statusTpl">
|
||||
<input type="checkbox" name="status" value="{{ d.id }}" lay-skin="switch" lay-text="开|关" lay-filter="statusSwitch" {{ d.status == 1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
<script type="text/html" id="typeTpl">
|
||||
{{# if(d.type == 1){ }}
|
||||
<span class="layui-badge layui-bg-blue">系统维护</span>
|
||||
{{# } else if(d.type == 2){ }}
|
||||
<span class="layui-badge layui-bg-orange">活动公告</span>
|
||||
{{# } else if(d.type == 3){ }}
|
||||
<span class="layui-badge layui-bg-green">版本更新</span>
|
||||
{{# } else { }}
|
||||
<span class="layui-badge">其他</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
<script type="text/html" id="topTpl">
|
||||
{{# if(d.is_top == 1){ }}
|
||||
<span class="layui-badge layui-bg-red">置顶</span>
|
||||
{{# } else { }}
|
||||
<span style="color:#ccc;">-</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
<script type="text/html" id="startTpl">
|
||||
{{# if(d.start_time > 0){ }}
|
||||
{{ layui.util.toDateString(d.start_time*1000, 'yyyy-MM-dd HH:mm') }}
|
||||
{{# } else { }}
|
||||
<span style="color:#ccc;">长期</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
<script type="text/html" id="endTpl">
|
||||
{{# if(d.end_time > 0){ }}
|
||||
{{ layui.util.toDateString(d.end_time*1000, 'yyyy-MM-dd HH:mm') }}
|
||||
{{# } else { }}
|
||||
<span style="color:#ccc;">长期</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form" id="wxapp-form" lay-filter="wxapp-form" style="padding:15px;">
|
||||
<input type="hidden" name="id" value="{{ d.id || '' }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标题</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" placeholder="请输入标题" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">类型</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="type" lay-search="">
|
||||
<option value="1">系统维护</option>
|
||||
<option value="2">活动公告</option>
|
||||
<option value="3">版本更新</option>
|
||||
<option value="4">其他</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">内容</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="content" placeholder="请输入内容" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">发布人</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="author" placeholder="留空则取当前管理员" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">置顶</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="is_top" lay-skin="switch" lay-text="置顶|普通" value="1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">展示有效期</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="start_time" id="start_time" placeholder="开始时间(留空=长期)" autocomplete="off" class="layui-input" style="margin-bottom:8px;">
|
||||
<input type="text" name="end_time" id="end_time" placeholder="结束时间(留空=长期)" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="sort" placeholder="请输入排序" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="status" lay-skin="switch" lay-text="启用|禁用" value="1" checked>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<table class="layui-hide" id="dataRecybinTable" lay-filter="dataRecybinTable"></table>
|
||||
<script type="text/html" id="dataRecybinBarTpl">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="restore" data-perm="notice:restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="forcedelete" data-perm="notice:destroy">彻底删除</a>
|
||||
</script>
|
||||
</script>
|
||||
<script>
|
||||
layui.use('notice', layui.factory('notice'));
|
||||
</script>
|
||||
@@ -0,0 +1,12 @@
|
||||
<div class="layui-card" style="margin:15px;">
|
||||
<div class="layui-card-header">关于系统</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table">
|
||||
<tbody>
|
||||
<tr><td>系统名称</td><td>YwxApp</td></tr>
|
||||
<tr><td>框架版本</td><td>{:think\facade\App::version()}</td></tr>
|
||||
<tr><td>PHP 版本</td><td>{:PHP_VERSION}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,41 @@
|
||||
<div class="layui-card" style="margin:15px;">
|
||||
<div class="layui-card-header">全局搜索(文章标题)</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="searchForm">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-inline" style="width:320px;">
|
||||
<input type="text" name="q" placeholder="输入文章标题关键词" class="layui-input">
|
||||
</div>
|
||||
<button class="layui-btn" lay-submit lay-filter="searchBtn"><i class="layui-icon layui-icon-search"></i> 搜索</button>
|
||||
</div>
|
||||
</form>
|
||||
<table class="layui-table" style="margin-top:10px;">
|
||||
<thead>
|
||||
<tr><th>ID</th><th>标题</th><th>创建时间</th></tr>
|
||||
</thead>
|
||||
<tbody id="resultBody">
|
||||
<tr><td colspan="3" style="text-align:center;color:#999;">请输入关键词搜索</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<script>
|
||||
layui.use(['form', 'jquery'], function () {
|
||||
var form = layui.form, $ = layui.jquery;
|
||||
form.on('submit(searchBtn)', function (data) {
|
||||
$.get('/backend/other/search', { q: data.field.q }, function (res) {
|
||||
var html = '';
|
||||
if (res.code === 0 && res.data && res.data.length) {
|
||||
res.data.forEach(function (r) {
|
||||
html += '<tr><td>' + (r.id || '') + '</td><td>' + (r.title || '') + '</td><td>' + (r.create_at || '') + '</td></tr>';
|
||||
});
|
||||
} else {
|
||||
html = '<tr><td colspan="3" style="text-align:center;color:#999;">无结果</td></tr>';
|
||||
}
|
||||
$('#resultBody').html(html);
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,111 @@
|
||||
<!--
|
||||
* @Author: YwxApp <ywx@ywxapp.cn>
|
||||
* @Date: 2026-04-29 02:32:33
|
||||
* @LastEditors: YwxApp <ywx@ywxapp.cn>
|
||||
* @LastEditTime: 2026-08-03 13:02:39
|
||||
* @Description:
|
||||
* @FilePath: \ywxapp_dev\app\backend\view\power\index.html
|
||||
* @CustomString: Copyright (c) 2026 YwxApp
|
||||
-->
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"> </div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/html" id="tableBarTpl">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="新建节点" lay-event="dataCreate" data-perm="power:add"> <i class="layui-icon layui-icon-add-1"></i> </a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="删除资源" lay-event="dataDelete" data-perm="power:delete"><i class="layui-icon layui-icon-delete"></i> </a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="资源回收站" lay-event="dataRecybin" data-perm="power:recyclebin"><i class="layui-icon layui-icon-home"></i> </a>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="dataBarTpl">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="编辑节点" lay-event="update" data-perm="power:edit"><i class="layui-icon layui-icon-edit"></i> </a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="添加子节点" lay-event="create" data-perm="power:add"><i class="layui-icon layui-icon-add-1"></i> </a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="删除节点" lay-event="delete" data-perm="power:delete"><i class="layui-icon layui-icon-delete"></i> </a>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 添加/编辑菜单表单模板 -->
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form layui-form-pane" lay-filter="wxapp-form" id="wxapp-form">
|
||||
<input type="hidden" name="id" value="{{= d.id || '' }}">
|
||||
<input type="hidden" name="pid" value="{{= d.pid || 0 }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" required lay-verify="required" placeholder="请输入菜单名称" value="{{ d.title || '' }}" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标识</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" required lay-verify="required" placeholder="请输入菜单标识" value="{{ d.name || '' }}" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">菜单类型</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="type" lay-filter="menuType" lay-verify="required">
|
||||
<option value="1" {{ (d.type == 1 || !d.type) ? 'selected' : '' }}>目录</option>
|
||||
<option value="2" {{ d.type == 2 ? 'selected' : '' }}>菜单</option>
|
||||
<option value="3" {{ d.type == 3 ? 'selected' : '' }}>按钮</option>
|
||||
<option value="4" {{ d.type == 4 ? 'selected' : '' }}>API</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-item-url {{ d.type == 3 ? 'layui-hide' : '' }}" id="urlField">
|
||||
<label class="layui-form-label">路由</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="route" placeholder="请输入路由路径" value="{{ d.route || '' }}" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">图标</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="icon" id="iconPicker" placeholder="请输入图标类名" value="{{ d.icon || '' }}" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" value="{{ d.sort || 0 }}" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="status" lay-skin="switch" lay-text="启用|禁用" {{ d.status != 0 ? 'checked' : (!d.id ? 'checked' : '') }}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-hide">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="wxapp-form-submit" id="wxapp-form-submit">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<!-- 状态开关 -->
|
||||
<script type="text/html" id="statusTpl">
|
||||
<input type="checkbox" name="status" value="{{d.id}}" lay-skin="switch" lay-text="启用|禁用" lay-filter="statusSwitch" {{ d.status == 1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"> </div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="dataRecybinTable" lay-filter="dataRecybinTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
</script>
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="恢复数据" lay-event="update"><i class="layui-icon layui-icon-edit"></i> </a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="删除节点" lay-event="delete"><i class="layui-icon layui-icon-delete"></i> </a>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
layui.use('power', function () { });
|
||||
</script>
|
||||
@@ -0,0 +1,130 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>头像设置 - 后台管理</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/assets/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="/assets/ywxapp/modules/cropper/cropper.css">
|
||||
<style>
|
||||
body { background: #f2f3f5; }
|
||||
.uc-head { background: #fff; border-bottom: 1px solid #eee; padding: 12px 20px; display: flex; align-items: center; justify-content: space-between; }
|
||||
.uc-head .title { font-size: 16px; font-weight: 700; }
|
||||
.uc-wrap { max-width: 960px; margin: 16px auto; padding: 0 14px; }
|
||||
.readyimg { background: #f7f7f7; height: 420px; display: flex; align-items: center; justify-content: center; overflow: hidden; }
|
||||
.readyimg img { max-width: 100%; max-height: 100%; display: block; }
|
||||
.img-preview { width: 150px; height: 150px; overflow: hidden; border-radius: 50%; border: 1px solid #eee; background: #f7f7f7; }
|
||||
.img-preview img { width: 100%; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="uc-wrap">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">设置头像</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-form-item">
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="pickBtn">
|
||||
<i class="layui-icon"></i> 选择图片
|
||||
</button>
|
||||
<input id="avatarImgUpload" type="file" accept="image/*" name="file" style="display:none">
|
||||
<div class="layui-form-mid layui-word-aux">支持 jpg / png / gif,建议尺寸 150x150 以上,大小 4M 以内</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md9">
|
||||
<div class="readyimg"><img id="cropImage" src=""></div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-form-mid">预览:</div>
|
||||
<div class="img-preview" style="margin-top:8px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-row layui-col-space15" style="margin-top:14px;">
|
||||
<div class="layui-col-md9">
|
||||
<button type="button" class="layui-btn" id="rotateLeft"><i class="layui-icon layui-icon-left"></i> 向左旋转</button>
|
||||
<button type="button" class="layui-btn" id="rotateRight"><i class="layui-icon layui-icon-right"></i> 向右旋转</button>
|
||||
<button type="button" class="layui-btn" id="resetImg"><i class="layui-icon layui-icon-refresh"></i> 重置</button>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<button type="button" class="layui-btn layui-btn-fluid" id="confirmSave">保存修改</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<script>
|
||||
layui.config({ base: '/assets/ywxapp/modules/' }).extend({ cropper: 'cropper/cropper' });
|
||||
|
||||
layui.use(['jquery', 'layer', 'cropper', 'http'], function () {
|
||||
var $ = layui.$;
|
||||
var layer = layui.layer;
|
||||
var http = layui.http;
|
||||
var $image = $('#cropImage');
|
||||
var options = { aspectRatio: 1 / 1, preview: '.img-preview', viewMode: 1 };
|
||||
var cropped = false;
|
||||
|
||||
$('#pickBtn').on('click', function () { $('#avatarImgUpload').click(); });
|
||||
$('#avatarImgUpload').on('change', function () {
|
||||
var file = this.files[0];
|
||||
if (!file) return;
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
$image.attr('src', e.target.result);
|
||||
$image.off('load.crop').on('load.crop', function () {
|
||||
if (cropped) { $image.cropper('destroy'); }
|
||||
$image.cropper(options);
|
||||
cropped = true;
|
||||
});
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
this.value = '';
|
||||
});
|
||||
|
||||
$('#rotateLeft').on('click', function () { if (cropped) $image.cropper('rotate', -15); });
|
||||
$('#rotateRight').on('click', function () { if (cropped) $image.cropper('rotate', 15); });
|
||||
$('#resetImg').on('click', function () { if (cropped) $image.cropper('reset'); });
|
||||
|
||||
$('#confirmSave').on('click', function () {
|
||||
if (!cropped) { layer.msg('请先选择图片', { icon: 2 }); return; }
|
||||
var canvas = $image.cropper('getCroppedCanvas', { width: 300, height: 300 });
|
||||
if (!canvas) { layer.msg('裁剪失败,请重试', { icon: 2 }); return; }
|
||||
layer.load(1, { shade: [0.3, '#fff'] });
|
||||
canvas.toBlob(function (blob) {
|
||||
var fd = new FormData();
|
||||
fd.append('file', blob, 'avatar.png');
|
||||
fd.append('type', 'avatar');
|
||||
http.post("{:url('Profile/avatar')}", fd).then(function (res) {
|
||||
layer.closeAll('loading');
|
||||
if (res.code === 0 && res.data && res.data.src) {
|
||||
layer.msg(res.msg || '头像上传成功', { icon: 1 });
|
||||
refreshTopAvatar(res.data.src);
|
||||
} else {
|
||||
layer.msg(res.msg || '上传失败', { icon: 2 });
|
||||
}
|
||||
}).catch(function () {
|
||||
layer.closeAll('loading');
|
||||
layer.msg('网络错误,上传失败', { icon: 2 });
|
||||
});
|
||||
}, 'image/png');
|
||||
});
|
||||
|
||||
function refreshTopAvatar(src) {
|
||||
try {
|
||||
if (window !== top && parent.layui && parent.layui.ywxapp) {
|
||||
var ts = '?t=' + Date.now();
|
||||
parent.document.querySelectorAll('img.layui-nav-img').forEach(function (im) {
|
||||
im.src = src + ts;
|
||||
});
|
||||
setTimeout(function () { parent.layui.ywxapp.closeThisTabs(); }, 700);
|
||||
return;
|
||||
}
|
||||
} catch (e) { /* 跨域等情况忽略 */ }
|
||||
setTimeout(function () { location.href = '/admin/index/index'; }, 700);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,82 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">设置我的资料</div>
|
||||
<div class="layui-card-body" pad15>
|
||||
|
||||
<div class="layui-form" lay-filter="">
|
||||
<!-- <div class="layui-form-item">
|
||||
<label class="layui-form-label">我的角色</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="role" lay-verify="">
|
||||
<option value="1" selected>超级管理员</option>
|
||||
<option value="2" disabled>普通管理员</option>
|
||||
<option value="3" disabled>审核员</option>
|
||||
<option value="4" disabled>编辑人员</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">当前角色不可更改为其它角色</div>
|
||||
</div> -->
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" disabled name="account" value="{$info.account|default=" 这家伙很懒,什么也没留下"}" readonly class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">昵称</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="nickname" value="{$info.nickname|default=" 这家伙很懒,什么也没留下"}" lay-verify="nickname" autocomplete="off" placeholder="请输入昵称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="layui-form-item">
|
||||
<label class="layui-form-label">性别</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="sex" value="男" title="男" checked>
|
||||
<input type="radio" name="sex" value="女" title="女">
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">头像</label>
|
||||
<div class="layui-input-inline">
|
||||
<input name="avatar" lay-verify="required" id="LAY_avatarSrc" placeholder="图片地址" value="{$info.avatar|default=" https://unpkg.com/outeres@0.0.5/demo/000.jpg"}" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-input-inline layui-btn-container" style="width: auto;">
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="LAY_avatarUpload">
|
||||
<i class="layui-icon"></i>上传图片
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-primary" layadmin-event="avartatPreview">查看图片</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">手机</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="mobile" value="{$info.mobile|default=""}" lay-verify="phone" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">邮箱</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="email" value="{$info.email|default=""}" lay-verify="email" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">备注</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="remarks" placeholder="请输入内容" class="layui-textarea">{$info.remarks|default=""}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="setmyinfo">确认修改</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重新填写</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,84 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>修改密码 - 后台管理</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/assets/layui/css/layui.css">
|
||||
<style>
|
||||
body { background: #f2f3f5; }
|
||||
.uc-wrap { max-width: 520px; margin: 20px auto; padding: 0 14px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="uc-wrap">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">重置登录密码</div>
|
||||
<div class="layui-card-body" pad15>
|
||||
<div class="layui-form" lay-filter="passForm">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">当前密码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="password" name="old_password" lay-verify="required" placeholder="请输入当前密码" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">新密码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="password" name="password" id="LAY_password" lay-verify="pass" placeholder="6-12 位,不含空格" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">确认新密码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="password" name="password_confirm" lay-verify="repass" placeholder="再次输入新密码" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="setmypass">确认修改</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<script>
|
||||
layui.use(['form', 'layer'], function () {
|
||||
var form = layui.form, layer = layui.layer, $ = layui.$;
|
||||
|
||||
form.verify({
|
||||
pass: [/^[\S]{6,12}$/, '密码必须 6 到 12 位,且不能出现空格'],
|
||||
repass: function (value) {
|
||||
if (value !== $('#LAY_password').val()) {
|
||||
return '两次密码输入不一致';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
form.on('submit(setmypass)', function (obj) {
|
||||
$.post('{:url("Profile/passwordSave")}', obj.field, function (res) {
|
||||
if (res.code === 1 || res.code === 0) {
|
||||
layer.msg(res.msg || '修改成功', { icon: 1 });
|
||||
setTimeout(function () {
|
||||
if (window !== top && parent.layui && parent.layui.ywxapp) {
|
||||
parent.layui.ywxapp.closeThisTabs();
|
||||
} else {
|
||||
location.href = '/admin/index/index';
|
||||
}
|
||||
}, 800);
|
||||
} else {
|
||||
layer.msg(res.msg || '修改失败', { icon: 2 });
|
||||
}
|
||||
}, 'json').fail(function () {
|
||||
layer.msg('请求失败', { icon: 2 });
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,86 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">道具中心管理</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="data-search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="title" placeholder="标题" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="data-search-btn"><i class="layui-icon"></i> 搜索</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="btn-reset">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataCreate" data-perm="prop:add"><i class="layui-icon"></i> 新增</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="dataDelete" data-perm="prop:del"><i class="layui-icon"></i> 删除</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataRecybin" data-perm="prop:restore"><i class="layui-icon"></i> 回收站</button>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="dataBar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="update" data-perm="prop:edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete" data-perm="prop:del">删除</a>
|
||||
</script>
|
||||
<script type="text/html" id="statusTpl">
|
||||
<input type="checkbox" name="status" value="{{ d.id }}" lay-skin="switch" lay-text="开|关" lay-filter="statusSwitch" {{ d.status == 1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form" id="wxapp-form" lay-filter="wxapp-form" style="padding:15px;">
|
||||
<input type="hidden" name="id" value="{{ d.id || '' }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">道具名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" placeholder="请输入道具名称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">图标</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="icon" placeholder="请输入图标" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">价格</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="price" placeholder="请输入价格" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="description" placeholder="请输入描述" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="sort" placeholder="请输入排序" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="status" lay-skin="switch" lay-text="启用|禁用" value="1" checked>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<table class="layui-hide" id="dataRecybinTable" lay-filter="dataRecybinTable"></table>
|
||||
<script type="text/html" id="dataRecybinBarTpl">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="restore" data-perm="prop:restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="forcedelete" data-perm="prop:destroy">彻底删除</a>
|
||||
</script>
|
||||
</script>
|
||||
<script>
|
||||
layui.use('prop', layui.factory('prop'));
|
||||
</script>
|
||||
@@ -0,0 +1,450 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"></div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 表格顶部工具条 -->
|
||||
<script type="text/html" id="tableBarTpl">
|
||||
<div class="layui-btn-group">
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="新建数据"
|
||||
lay-event="dataCreate"
|
||||
data-perm="role:add">
|
||||
<i class="layui-icon layui-icon-add-1"></i>
|
||||
</a>
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="删除资源"
|
||||
lay-event="dataDelete"
|
||||
data-perm="role:delete"
|
||||
><i class="layui-icon layui-icon-delete"></i>
|
||||
</a>
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="资源回收站"
|
||||
lay-event="dataRecybin"
|
||||
data-perm="role:recyclebin"
|
||||
><i class="layui-icon layui-icon-home"></i>
|
||||
</a>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 表格数据工具条 -->
|
||||
<script type="text/html" id="dataBarTpl">
|
||||
<div class="layui-btn-group">
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="编辑数据"
|
||||
lay-event="update"
|
||||
data-perm="role:edit"
|
||||
><i class="layui-icon layui-icon-edit"></i>
|
||||
</a>
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="权限分配"
|
||||
lay-event="permission"
|
||||
data-perm="role:*"
|
||||
><i class="layui-icon layui-icon-auz"></i>
|
||||
</a>
|
||||
{{# if(d.id > 1) { }}
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="删除数据"
|
||||
lay-event="delete"
|
||||
data-perm="role:delete"
|
||||
><i class="layui-icon layui-icon-delete"></i>
|
||||
</a>
|
||||
{{# } }}
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 表格回收站 -->
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"></div>
|
||||
<div class="layui-card-body">
|
||||
<table
|
||||
class="layui-hide"
|
||||
id="dataRecybinTable"
|
||||
lay-filter="dataRecybinTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 角色状态 -->
|
||||
<script type="text/html" id="statusTpl">
|
||||
{{# if(d.status == 1) { }}
|
||||
<span class="layui-badge layui-bg-green">正常</span>
|
||||
{{# } else { }}
|
||||
<span class="layui-badge layui-bg-orange">禁用</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<!-- 添加/编辑角色表单 -->
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form layui-form-pane" lay-filter="wxapp-form" id="wxapp-form">
|
||||
<input type="hidden" name="id" value="{{d.id||''}}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">角色名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" required lay-verify="required" placeholder="请输入角色名称" autocomplete="off" class="layui-input" value="{{d.title||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">编码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" required lay-verify="required" placeholder="请输入分组编码" autocomplete="off" class="layui-input" value="{{d.name||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">角色描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="description" placeholder="请输入角色描述" class="layui-textarea">{{d.description||''}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="status" value="1" title="启用" {{ d.status==undefined || d.status==1 ? 'checked' : '' }}>
|
||||
<input type="radio" name="status" value="0" title="禁用" {{ d.status==0 ? 'checked' : '' }}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-hide">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="wxapp-form-submit" id="wxapp-form-submit">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<!-- 权限分配弹窗 -->
|
||||
<script type="text/html" id="permissionFormTpl">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
角色:{{d.name}}
|
||||
<span style="color:#999;font-weight:normal;">(ID: {{d.id}})</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<div id="permissionTree"></div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
layui.use(
|
||||
["table", "form", "layer", "jquery", "tree", "laytpl"],
|
||||
function () {
|
||||
var table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
$ = layui.jquery,
|
||||
tree = layui.tree,
|
||||
laytpl = layui.laytpl;
|
||||
|
||||
function api(url, data, type) {
|
||||
return $.ajax({
|
||||
url: url,
|
||||
type: type || "POST",
|
||||
data: data || {},
|
||||
dataType: "json",
|
||||
});
|
||||
}
|
||||
|
||||
function load() {
|
||||
api("index").then(
|
||||
function (res) {
|
||||
if (res.code !== 0) {
|
||||
layer.msg(res.message || "加载失败", { icon: 2 });
|
||||
return;
|
||||
}
|
||||
renderTable(res.data || []);
|
||||
},
|
||||
function () {
|
||||
layer.msg("请求失败", { icon: 2 });
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function renderTable(list) {
|
||||
table.render({
|
||||
elem: "#dataTable",
|
||||
data: list,
|
||||
page: false,
|
||||
cols: [
|
||||
[
|
||||
{ type: "checkbox", width: 40 },
|
||||
{ field: "id", title: "ID", width: 60 },
|
||||
{ field: "name", title: "编码", width: 140 },
|
||||
{ field: "title", title: "角色名称", minWidth: 140 },
|
||||
{ field: "description", title: "描述", minWidth: 160 },
|
||||
{
|
||||
field: "status",
|
||||
title: "状态",
|
||||
width: 90,
|
||||
templet: "#statusTpl",
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
width: 200,
|
||||
templet: "#dataBarTpl",
|
||||
fixed: "right",
|
||||
},
|
||||
],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
// 新建 / 编辑角色
|
||||
function openForm(row) {
|
||||
laytpl($("#dataFormTpl").html()).render(row || {}, function (html) {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: row ? "编辑角色" : "新建角色",
|
||||
area: ["480px", "auto"],
|
||||
content: html,
|
||||
btn: ["保存", "取消"],
|
||||
success: function () {
|
||||
form.render("radio");
|
||||
},
|
||||
yes: function (index, layero) {
|
||||
var params = $(layero).find("#wxapp-form").serialize();
|
||||
if (row) {
|
||||
params += "&_method=PUT";
|
||||
}
|
||||
api(row ? "update" : "save", params, "POST").then(
|
||||
function (res) {
|
||||
if (res.code !== 0) {
|
||||
layer.msg(res.message || "保存失败", { icon: 2 });
|
||||
return;
|
||||
}
|
||||
layer.msg(res.message || "已保存", { icon: 1 });
|
||||
layer.close(index);
|
||||
load();
|
||||
},
|
||||
function () {
|
||||
layer.msg("保存失败", { icon: 2 });
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 权限分配(树形勾选 + 保存),后端 Role::permission 提供树与持久化
|
||||
function openPermission(row) {
|
||||
laytpl($("#permissionFormTpl").html()).render(row, function (html) {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: "权限分配",
|
||||
area: ["360px", "80%"],
|
||||
content: html,
|
||||
btn: ["保存", "取消"],
|
||||
success: function (layero, index) {
|
||||
api("permission?id=" + row.id, null, "GET").then(
|
||||
function (res) {
|
||||
if (res.code !== 0) {
|
||||
layer.msg(res.message || "加载失败", { icon: 2 });
|
||||
return;
|
||||
}
|
||||
tree.render({
|
||||
elem: "#permissionTree",
|
||||
data: convertTree(res.data || []),
|
||||
showCheckbox: true,
|
||||
id: "permTree",
|
||||
});
|
||||
// 超级管理员恒为 *,禁用保存
|
||||
if (res.message && res.message.indexOf("超级管理员") >= 0) {
|
||||
$(layero)
|
||||
.find(".layui-layer-btn0")
|
||||
.addClass("layui-btn-disabled");
|
||||
layer.msg("超级管理员拥有全部权限(*),无需分配", {
|
||||
icon: 0,
|
||||
});
|
||||
}
|
||||
},
|
||||
function () {
|
||||
layer.msg("权限树加载失败", { icon: 2 });
|
||||
},
|
||||
);
|
||||
},
|
||||
yes: function (index) {
|
||||
var ids = collectIds(tree.getChecked("permTree"), []);
|
||||
api(
|
||||
"permission?id=" + row.id,
|
||||
{ permissions: ids, _method: "PUT" },
|
||||
"POST",
|
||||
).then(
|
||||
function (res) {
|
||||
if (res.code !== 0) {
|
||||
layer.msg(res.message || "保存失败", { icon: 2 });
|
||||
return;
|
||||
}
|
||||
layer.msg(res.message || "权限已保存", { icon: 1 });
|
||||
layer.close(index);
|
||||
},
|
||||
function () {
|
||||
layer.msg("保存失败", { icon: 2 });
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Role::permission 返回树节点用 name 展示,转换为 layui tree 的 title 字段
|
||||
function convertTree(nodes) {
|
||||
return (nodes || []).map(function (n) {
|
||||
return {
|
||||
title: n.name,
|
||||
id: n.id,
|
||||
checked: !!n.checked,
|
||||
spread: !!n.spread,
|
||||
children: convertTree(n.children),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// 递归收集勾选节点(含父子)的 id,前端去重
|
||||
function collectIds(nodes, acc) {
|
||||
(nodes || []).forEach(function (n) {
|
||||
if (n.id && acc.indexOf(n.id) < 0) {
|
||||
acc.push(n.id);
|
||||
}
|
||||
if (n.children) {
|
||||
collectIds(n.children, acc);
|
||||
}
|
||||
});
|
||||
return acc;
|
||||
}
|
||||
|
||||
// 回收站
|
||||
function openRecycle() {
|
||||
api("recyclebin").then(
|
||||
function (res) {
|
||||
if (res.code !== 0) {
|
||||
layer.msg(res.message || "加载失败", { icon: 2 });
|
||||
return;
|
||||
}
|
||||
var rows = (res.data || [])
|
||||
.map(function (r) {
|
||||
return (
|
||||
"<tr><td>" +
|
||||
r.id +
|
||||
"</td><td>" +
|
||||
(r.title || "") +
|
||||
"</td>" +
|
||||
'<td><button type="button" class="layui-btn layui-btn-xs" onclick="restoreRole(' +
|
||||
r.id +
|
||||
')">恢复</button></td></tr>'
|
||||
);
|
||||
})
|
||||
.join("");
|
||||
if (!rows) {
|
||||
rows =
|
||||
'<tr><td colspan="3" style="color:#999;text-align:center;">回收站为空</td></tr>';
|
||||
}
|
||||
var html =
|
||||
'<div style="padding:15px;"><table class="layui-table"><thead><tr>' +
|
||||
"<th>ID</th><th>名称</th><th>操作</th></tr></thead><tbody>" +
|
||||
rows +
|
||||
"</tbody></table></div>";
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: "角色回收站",
|
||||
area: ["420px", "70%"],
|
||||
content: html,
|
||||
});
|
||||
},
|
||||
function () {
|
||||
layer.msg("加载失败", { icon: 2 });
|
||||
},
|
||||
);
|
||||
}
|
||||
window.restoreRole = function (id) {
|
||||
api("restore", { ids: id, _method: "PUT" }, "POST").then(
|
||||
function (res) {
|
||||
if (res.code !== 0) {
|
||||
layer.msg(res.message || "恢复失败", { icon: 2 });
|
||||
return;
|
||||
}
|
||||
layer.msg(res.message || "已恢复", { icon: 1 });
|
||||
load();
|
||||
},
|
||||
function () {
|
||||
layer.msg("恢复失败", { icon: 2 });
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
// 行内操作
|
||||
table.on("tool(dataTable)", function (obj) {
|
||||
var row = obj.data;
|
||||
if (obj.event === "update") {
|
||||
openForm(row);
|
||||
} else if (obj.event === "permission") {
|
||||
openPermission(row);
|
||||
} else if (obj.event === "delete") {
|
||||
layer.confirm(
|
||||
"确认删除角色「" + (row.title || row.name) + "」?",
|
||||
function () {
|
||||
api("delete", { ids: row.id, _method: "DELETE" }, "POST").then(
|
||||
function (res) {
|
||||
if (res.code !== 0) {
|
||||
layer.msg(res.message || "删除失败", { icon: 2 });
|
||||
return;
|
||||
}
|
||||
layer.msg(res.message || "已删除", { icon: 1 });
|
||||
load();
|
||||
},
|
||||
function () {
|
||||
layer.msg("删除失败", { icon: 2 });
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// 顶部工具条
|
||||
table.on("toolbar(dataTable)", function (obj) {
|
||||
if (obj.event === "dataCreate") {
|
||||
openForm(null);
|
||||
} else if (obj.event === "dataDelete") {
|
||||
var check = table.checkStatus("dataTable").data;
|
||||
if (!check.length) {
|
||||
layer.msg("请先选择角色", { icon: 2 });
|
||||
return;
|
||||
}
|
||||
var ids = check
|
||||
.map(function (r) {
|
||||
return r.id;
|
||||
})
|
||||
.join(",");
|
||||
layer.confirm(
|
||||
"确认删除选中的 " + check.length + " 个角色?",
|
||||
function () {
|
||||
api("delete", { ids: ids, _method: "DELETE" }, "POST").then(
|
||||
function (res) {
|
||||
if (res.code !== 0) {
|
||||
layer.msg(res.message || "删除失败", { icon: 2 });
|
||||
return;
|
||||
}
|
||||
layer.msg(res.message || "已删除", { icon: 1 });
|
||||
load();
|
||||
},
|
||||
function () {
|
||||
layer.msg("删除失败", { icon: 2 });
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
} else if (obj.event === "dataRecybin") {
|
||||
openRecycle();
|
||||
}
|
||||
});
|
||||
|
||||
load();
|
||||
},
|
||||
);
|
||||
</script>
|
||||
@@ -0,0 +1,119 @@
|
||||
<!--
|
||||
* @Author: YwxApp <ywx@ywxapp.cn>
|
||||
* @Date: 2026-04-29 02:32:33
|
||||
* @LastEditors: YwxApp <ywx@ywxapp.cn>
|
||||
* @LastEditTime: 2026-08-03 12:25:11
|
||||
* @Description:
|
||||
* @FilePath: \ywxapp_dev\app\backend\view\rule\index.html
|
||||
* @CustomString: Copyright (c) 2026 YwxApp
|
||||
-->
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"> </div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/html" id="tableBarTpl">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="新建节点" lay-event="dataCreate" data-perm="rule:add"> <i class="layui-icon layui-icon-add-1"></i> </a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="删除资源" lay-event="dataDelete" data-perm="rule:delete"><i class="layui-icon layui-icon-delete"></i> </a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="资源回收站" lay-event="dataRecybin" data-perm="rule:recyclebin"><i class="layui-icon layui-icon-home"></i> </a>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="dataBarTpl">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="编辑节点" lay-event="update" data-perm="rule:edit"><i class="layui-icon layui-icon-edit"></i> </a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="添加子节点" lay-event="create" data-perm="rule:add"><i class="layui-icon layui-icon-add-1"></i> </a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="删除节点" lay-event="delete" data-perm="rule:delete"><i class="layui-icon layui-icon-delete"></i> </a>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 添加/编辑菜单表单模板 -->
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form layui-form-pane" lay-filter="wxapp-form" id="wxapp-form">
|
||||
<input type="hidden" name="id" value="{{= d.id || '' }}">
|
||||
<input type="hidden" name="pid" value="{{= d.pid || 0 }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" required lay-verify="required" placeholder="请输入菜单名称" value="{{ d.title || '' }}" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标识</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" required lay-verify="required" placeholder="请输入菜单标识" value="{{ d.name || '' }}" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">菜单类型</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="module" lay-filter="menuModule" lay-verify="required">
|
||||
<option value="frontend" {{ d.module == 'frontend' ? 'selected' : '' }}>Frontend</option>
|
||||
<option value="member" {{ d.module == 'member' ? 'selected' : '' }}>Member</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">菜单类型</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="type" lay-filter="menuType" lay-verify="required">
|
||||
<option value="1" {{ (d.type == 1 || !d.type) ? 'selected' : '' }}>目录</option>
|
||||
<option value="2" {{ d.type == 2 ? 'selected' : '' }}>菜单</option>
|
||||
<option value="3" {{ d.type == 3 ? 'selected' : '' }}>按钮</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-item-url {{ d.type == 3 ? 'layui-hide' : '' }}" id="urlField">
|
||||
<label class="layui-form-label">路由</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="route" placeholder="请输入路由路径" value="{{ d.route || '' }}" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">图标</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="icon" id="iconPicker" placeholder="请输入图标类名" value="{{ d.icon || '' }}" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="sort" value="{{ d.sort || 0 }}" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="status" lay-skin="switch" lay-text="启用|禁用" {{ d.status != 0 ? 'checked' : (!d.id ? 'checked' : '') }}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-hide">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="wxapp-form-submit" id="wxapp-form-submit">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"> </div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="dataRecybinTable" lay-filter="dataRecybinTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
</script>
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="恢复数据" lay-event="update"><i class="layui-icon layui-icon-edit"></i> </a>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="删除节点" lay-event="delete"><i class="layui-icon layui-icon-delete"></i> </a>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
layui.use(['rule'], function () { });
|
||||
</script>
|
||||
<script>
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,95 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">积分规则管理</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="data-search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="name" placeholder="规则名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="data-search-btn"><i class="layui-icon"></i> 搜索</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="btn-reset">重置</button>
|
||||
<a class="layui-btn layui-btn-warm" href="{:url('score/log')}"><i class="layui-icon"></i> 积分流水</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataCreate" data-perm="score:add"><i class="layui-icon"></i> 新增</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="dataDelete" data-perm="score:del"><i class="layui-icon"></i> 删除</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataRecybin" data-perm="score:restore"><i class="layui-icon"></i> 回收站</button>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="dataBar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="update" data-perm="score:edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete" data-perm="score:del">删除</a>
|
||||
</script>
|
||||
<script type="text/html" id="typeTpl">
|
||||
{{# if(d.type == 1){ }}
|
||||
<span class="layui-badge layui-bg-green">获取</span>
|
||||
{{# } else { }}
|
||||
<span class="layui-badge layui-bg-orange">消费</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
<script type="text/html" id="statusTpl">
|
||||
<input type="checkbox" name="status" value="{{ d.id }}" lay-skin="switch" lay-text="开|关" lay-filter="statusSwitch" {{ d.status == 1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form" id="wxapp-form" lay-filter="wxapp-form" style="padding:15px;">
|
||||
<input type="hidden" name="id" value="{{ d.id || '' }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">规则名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" placeholder="请输入规则名称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">触发动作</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="action" placeholder="如 task_complete/signin/register" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">规则类型</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="type" value="1" title="获取" checked>
|
||||
<input type="radio" name="type" value="2" title="消费">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">变动值</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="value" placeholder="请输入积分变动值(正数)" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="sort" placeholder="请输入排序" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="status" lay-skin="switch" lay-text="启用|禁用" value="1" checked>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<table class="layui-hide" id="dataRecybinTable" lay-filter="dataRecybinTable"></table>
|
||||
<script type="text/html" id="dataRecybinBarTpl">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="restore" data-perm="score:restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="forcedelete" data-perm="score:destroy">彻底删除</a>
|
||||
</script>
|
||||
</script>
|
||||
<script>
|
||||
layui.use('score', layui.factory('score'));
|
||||
</script>
|
||||
@@ -0,0 +1,67 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">积分流水</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="data-search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="uid" placeholder="用户ID" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="data-search-btn"><i class="layui-icon"></i> 搜索</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="btn-reset">重置</button>
|
||||
<a class="layui-btn" href="{:url('score/index')}"><i class="layui-icon"></i> 返回规则</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="typeTpl">
|
||||
{{# if(d.type == 2){ }}
|
||||
<span class="layui-badge layui-bg-orange">支出</span>
|
||||
{{# } else { }}
|
||||
<span class="layui-badge layui-bg-green">收入</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
<script>
|
||||
layui.use(['table', 'form'], function () {
|
||||
var table = layui.table, form = layui.form, $ = layui.jquery;
|
||||
|
||||
function renderTable() {
|
||||
var where = form.val('data-search-form');
|
||||
table.render({
|
||||
elem: '#dataTable',
|
||||
url: "{:url('score/log')}",
|
||||
method: 'post',
|
||||
where: where,
|
||||
page: true,
|
||||
cols: [[
|
||||
{field: 'id', title: 'ID', width: 70},
|
||||
{field: 'uid', title: '用户ID', width: 90},
|
||||
{field: 'type_text', title: '类型', width: 90, templet: '#typeTpl'},
|
||||
{field: 'value', title: '变动值', width: 90},
|
||||
{field: 'balance', title: '余额', width: 90},
|
||||
{field: 'remark', title: '备注'},
|
||||
{field: 'create_at', title: '时间', width: 170, templet: function (d) {
|
||||
return layui.util.toDateString(d.create_at * 1000);
|
||||
}}
|
||||
]]
|
||||
});
|
||||
}
|
||||
|
||||
renderTable();
|
||||
|
||||
form.on('submit(data-search-btn)', function () {
|
||||
renderTable();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#btn-reset').on('click', function () {
|
||||
form.val('data-search-form', {uid: ''});
|
||||
renderTable();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,86 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">电子商务管理</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="data-search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="title" placeholder="标题" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="data-search-btn"><i class="layui-icon"></i> 搜索</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="btn-reset">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataCreate" data-perm="shop:add"><i class="layui-icon"></i> 新增</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="dataDelete" data-perm="shop:del"><i class="layui-icon"></i> 删除</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataRecybin" data-perm="shop:restore"><i class="layui-icon"></i> 回收站</button>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="dataBar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="update" data-perm="shop:edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete" data-perm="shop:del">删除</a>
|
||||
</script>
|
||||
<script type="text/html" id="statusTpl">
|
||||
<input type="checkbox" name="status" value="{{ d.id }}" lay-skin="switch" lay-text="开|关" lay-filter="statusSwitch" {{ d.status == 1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form" id="wxapp-form" lay-filter="wxapp-form" style="padding:15px;">
|
||||
<input type="hidden" name="id" value="{{ d.id || '' }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">商品名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" placeholder="请输入商品名称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">价格</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="price" placeholder="请输入价格" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">库存</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="stock" placeholder="请输入库存" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="description" placeholder="请输入描述" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="sort" placeholder="请输入排序" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="status" lay-skin="switch" lay-text="启用|禁用" value="1" checked>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<table class="layui-hide" id="dataRecybinTable" lay-filter="dataRecybinTable"></table>
|
||||
<script type="text/html" id="dataRecybinBarTpl">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="restore" data-perm="shop:restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="forcedelete" data-perm="shop:destroy">彻底删除</a>
|
||||
</script>
|
||||
</script>
|
||||
<script>
|
||||
layui.use('shop', layui.factory('shop'));
|
||||
</script>
|
||||
@@ -0,0 +1,80 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">短信服务管理</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="data-search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="title" placeholder="标题" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="data-search-btn"><i class="layui-icon"></i> 搜索</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="btn-reset">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataCreate" data-perm="sms:add"><i class="layui-icon"></i> 新增</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="dataDelete" data-perm="sms:del"><i class="layui-icon"></i> 删除</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataRecybin" data-perm="sms:restore"><i class="layui-icon"></i> 回收站</button>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="dataBar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="update" data-perm="sms:edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete" data-perm="sms:del">删除</a>
|
||||
</script>
|
||||
<script type="text/html" id="statusTpl">
|
||||
<input type="checkbox" name="status" value="{{ d.id }}" lay-skin="switch" lay-text="开|关" lay-filter="statusSwitch" {{ d.status == 1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form" id="wxapp-form" lay-filter="wxapp-form" style="padding:15px;">
|
||||
<input type="hidden" name="id" value="{{ d.id || '' }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">模板名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" placeholder="请输入模板名称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">模板标识</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="code" placeholder="请输入模板标识" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">模板内容</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="content" placeholder="请输入模板内容" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="sort" placeholder="请输入排序" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="status" lay-skin="switch" lay-text="启用|禁用" value="1" checked>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<table class="layui-hide" id="dataRecybinTable" lay-filter="dataRecybinTable"></table>
|
||||
<script type="text/html" id="dataRecybinBarTpl">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="restore" data-perm="sms:restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="forcedelete" data-perm="sms:destroy">彻底删除</a>
|
||||
</script>
|
||||
</script>
|
||||
<script>
|
||||
layui.use('sms', layui.factory('sms'));
|
||||
</script>
|
||||
@@ -0,0 +1,67 @@
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">蜘蛛汇总(今日 / 近7日 / 近30日 / 总量)</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table" id="summaryTable" lay-size="sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>搜索引擎</th>
|
||||
<th>今日</th>
|
||||
<th>近7日</th>
|
||||
<th>近30日</th>
|
||||
<th>总量</th>
|
||||
<th style="min-width:220px;">近30日趋势</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="summaryBody">
|
||||
<tr><td colspan="6" style="text-align:center;color:#999;">加载中…</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">抓取明细</div>
|
||||
<div class="layui-card-body">
|
||||
<!-- 搜索栏 -->
|
||||
<div class="layui-form layui-card-header-boxed" lay-filter="search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<select name="spider" id="spiderSelect">
|
||||
<option value="">全部蜘蛛</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="ip" placeholder="来源IP" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="url" placeholder="URL 关键词" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="date" id="dateInput" placeholder="日期" autocomplete="off" class="layui-input" readonly>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="data-search-btn">
|
||||
<i class="layui-icon layui-icon-search"></i>
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-primary" id="btn-reset">
|
||||
<i class="layui-icon layui-icon-refresh"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表格容器 -->
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
|
||||
<!-- 顶部工具条 -->
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="清理30天前明细" lay-event="dataClear" data-perm="spider:clear"><i class="layui-icon layui-icon-delete"></i> 清理旧日志</a>
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
layui.use('spider', function () { });
|
||||
</script>
|
||||
@@ -0,0 +1,126 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">站点任务管理</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="data-search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="title" placeholder="标题" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="data-search-btn"><i class="layui-icon"></i> 搜索</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="btn-reset">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataCreate" data-perm="task:add"><i class="layui-icon"></i> 新增</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="dataDelete" data-perm="task:del"><i class="layui-icon"></i> 删除</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="dataRecybin" data-perm="task:restore"><i class="layui-icon"></i> 回收站</button>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="dataBar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="update" data-perm="task:edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete" data-perm="task:del">删除</a>
|
||||
</script>
|
||||
<script type="text/html" id="statusTpl">
|
||||
<input type="checkbox" name="status" value="{{ d.id }}" lay-skin="switch" lay-text="开|关" lay-filter="statusSwitch" {{ d.status == 1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
<script type="text/html" id="rewardTypeTpl">
|
||||
{{# if(d.reward_type == 1){ }}
|
||||
<span class="layui-badge layui-bg-blue">积分</span>
|
||||
{{# } else if(d.reward_type == 2){ }}
|
||||
<span class="layui-badge layui-bg-orange">金币</span>
|
||||
{{# } else if(d.reward_type == 3){ }}
|
||||
<span class="layui-badge layui-bg-green">道具</span>
|
||||
{{# } else { }}
|
||||
<span class="layui-badge">未知</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form" id="wxapp-form" lay-filter="wxapp-form" style="padding:15px;">
|
||||
<input type="hidden" name="id" value="{{ d.id || '' }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">任务标题</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" placeholder="请输入任务标题" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">任务描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="description" placeholder="请输入任务描述" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">奖励类型</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="reward_type" lay-verify="required">
|
||||
<option value="1">积分</option>
|
||||
<option value="2">金币</option>
|
||||
<option value="3">道具</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="rewardNumItem">
|
||||
<label class="layui-form-label">奖励数量</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="reward_num" placeholder="请输入数量" class="layui-input" lay-verify="required|number">
|
||||
<div class="layui-form-mid layui-word-aux">积分/金币奖励填写数量</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="rewardPropItem" style="display:none;">
|
||||
<label class="layui-form-label">奖励道具</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="reward_num" id="rewardPropSelect" lay-verify="required">
|
||||
<option value="">请选择道具</option>
|
||||
{volist name="propList" id="pt"}
|
||||
<option value="{$pt.id}">{$pt.title}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
<div class="layui-form-mid layui-word-aux">选择要发放的道具</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="propNumItem" style="display:none;">
|
||||
<label class="layui-form-label">道具数量</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="prop_num" placeholder="请输入道具数量" value="1" class="layui-input" lay-verify="required|number">
|
||||
<div class="layui-form-mid layui-word-aux">用户领取后获得的该道具数量</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="sort" placeholder="请输入排序" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="status" lay-skin="switch" lay-text="启用|禁用" value="1" checked>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="wxapp-form-submit" id="wxapp-form-submit">立即提交</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<table class="layui-hide" id="dataRecybinTable" lay-filter="dataRecybinTable"></table>
|
||||
<script type="text/html" id="dataRecybinBarTpl">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="restore" data-perm="task:restore">恢复</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="forcedelete" data-perm="task:destroy">彻底删除</a>
|
||||
</script>
|
||||
</script>
|
||||
<script>
|
||||
layui.use('task', layui.factory('task'));
|
||||
</script>
|
||||
@@ -0,0 +1,239 @@
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">已安装模板 <span id="gdTip" class="layui-badge layui-bg-blue" style="margin-left:8px;"></span></div>
|
||||
<div class="layui-card-body">
|
||||
<table id="tplTable" lay-filter="tplTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">插件模板绑定(整站皮肤按插件独立选择)</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table">
|
||||
<thead>
|
||||
<tr><th>插件</th><th>当前激活</th><th>选择模板</th><th>操作</th></tr>
|
||||
</thead>
|
||||
<tbody id="bindBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">安装新模板(上传 zip 包)</div>
|
||||
<div class="layui-card-body">
|
||||
<button type="button" class="layui-btn" id="uploadBtn"><i class="layui-icon"></i>上传模板包</button>
|
||||
<div style="color:#999;margin-top:8px;line-height:1.6;">
|
||||
zip 内须含 <code>templates/<name>/template.json</code> 与 <code>static/</code> 资源,安装后落到
|
||||
<code>templates/<name>/</code> 与 <code>public/static/templates/<name>/</code>。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">配置备份(导入 / 导出)</div>
|
||||
<div class="layui-card-body">
|
||||
<button type="button" class="layui-btn layui-btn-normal" id="exportBtn"><i class="layui-icon"></i>导出配置</button>
|
||||
<button type="button" class="layui-btn" id="importBtn"><i class="layui-icon"></i>导入配置</button>
|
||||
<div style="color:#999;margin-top:8px;line-height:1.6;">
|
||||
导出含「插件模板绑定 + 界面设置 + 配色覆盖」的 JSON;导入会安全跳过未安装模板的绑定,可跨站点克隆皮肤方案。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/html" id="tplOperate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="setDefault">设默认</a>
|
||||
<a class="layui-btn layui-btn-xs {{d.enabled ? 'layui-btn-warm' : 'layui-btn-normal'}}" lay-event="toggle">{{d.enabled ? '禁用' : '启用'}}</a>
|
||||
{{# if (d.variable_defs && Object.keys(d.variable_defs).length > 0) { }}
|
||||
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="vars">配色</a>
|
||||
{{# } }}
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="uninstall">卸载</a>
|
||||
</script>
|
||||
<script>
|
||||
layui.use(['table', 'form', 'layer', 'upload', 'jquery'], function () {
|
||||
var table = layui.table, form = layui.form, layer = layui.layer, upload = layui.upload, $ = layui.jquery;
|
||||
var state = { installed: [], addon: [], active_map: {} };
|
||||
|
||||
function api(url, data) {
|
||||
return $.ajax({ url: url, type: 'POST', data: data || {}, dataType: 'json' });
|
||||
}
|
||||
|
||||
function load() {
|
||||
api('index').then(function (res) {
|
||||
if (res.code !== 0) { layer.msg(res.message || '加载失败', { icon: 2 }); return; }
|
||||
state.installed = res.data.installed || [];
|
||||
state.addon = res.data.addon || [];
|
||||
state.active_map = res.data.active_map || {};
|
||||
state.global_default = res.data.global_default || 'default';
|
||||
$('#gdTip').text('全站默认:' + (state.global_default === 'default' ? '自带视图' : state.global_default));
|
||||
renderTpl();
|
||||
renderBind();
|
||||
}, function () { layer.msg('请求失败', { icon: 2 }); });
|
||||
}
|
||||
|
||||
function renderTpl() {
|
||||
table.render({
|
||||
elem: '#tplTable',
|
||||
data: state.installed,
|
||||
page: false,
|
||||
cols: [[
|
||||
{ field: 'preview', title: '预览', width: 90, templet: function (d) {
|
||||
if (! d.preview_url) { return '<span style="color:#999">无</span>'; }
|
||||
var badge = (d.preview_urls && d.preview_urls.length > 1)
|
||||
? ' <span class="layui-badge layui-bg-orange" style="vertical-align:top;">' + d.preview_urls.length + '图</span>' : '';
|
||||
return '<img src="' + d.preview_url + '" style="max-height:40px;cursor:zoom-in;" onclick="openPreview(\'' + d.name + '\')">' + badge;
|
||||
} },
|
||||
{ field: 'name', title: '标识', width: 120 },
|
||||
{ field: 'title', title: '名称', minWidth: 140 },
|
||||
{ field: 'version', title: '版本', width: 80 },
|
||||
{ field: 'target_addon', title: '适用插件', minWidth: 120, templet: function (d) {
|
||||
return (d.target_addon || []).join(', ');
|
||||
} },
|
||||
{ field: 'applied_to', title: '已应用', minWidth: 120, templet: function (d) {
|
||||
return (d.applied_to || []).join(', ') || '<span style="color:#999">未绑定</span>';
|
||||
} },
|
||||
{ field: 'enabled', title: '状态', width: 80, templet: function (d) {
|
||||
return d.enabled
|
||||
? '<span class="layui-badge layui-bg-green">启用</span>'
|
||||
: '<span class="layui-badge layui-bg-gray">禁用</span>';
|
||||
} },
|
||||
{ title: '操作', width: 260, toolbar: '#tplOperate', fixed: 'right' }
|
||||
]]
|
||||
});
|
||||
}
|
||||
|
||||
function renderBind() {
|
||||
var html = '';
|
||||
state.addon.forEach(function (a) {
|
||||
var cur = state.active_map[a.name] || 'default';
|
||||
var opts = '<option value="default">默认(自带视图)</option>';
|
||||
state.installed.forEach(function (t) {
|
||||
if ((t.target_addon || []).indexOf(a.name) >= 0) {
|
||||
var sel = (cur === t.name) ? 'selected' : '';
|
||||
opts += '<option value="' + t.name + '" ' + sel + '>' + t.title + ' (' + t.version + ')</option>';
|
||||
}
|
||||
});
|
||||
html += '<tr>'
|
||||
+ '<td>' + a.title + ' <span style="color:#999">' + a.name + '</span></td>'
|
||||
+ '<td>' + (cur === 'default' ? '默认' : cur) + '</td>'
|
||||
+ '<td><select class="layui-input-inline" data-addon="' + a.name + '" style="width:220px;">' + opts + '</select></td>'
|
||||
+ '<td><button type="button" class="layui-btn layui-btn-xs" onclick="saveBind(\'' + a.name + '\', this)">保存</button></td>'
|
||||
+ '</tr>';
|
||||
});
|
||||
$('#bindBody').html(html);
|
||||
form.render('select');
|
||||
}
|
||||
|
||||
window.saveBind = function (addon, btn) {
|
||||
var sel = $(btn).closest('tr').find('select').val();
|
||||
api('setActive', { addon: addon, template: sel }).then(function (res) {
|
||||
layer.msg(res.message || '已保存', { icon: 1 });
|
||||
load();
|
||||
}, function () { layer.msg('保存失败', { icon: 2 }); });
|
||||
};
|
||||
|
||||
// 预览灯箱:多图走 layer.photos 画廊,单图直接放大
|
||||
window.openPreview = function (name) {
|
||||
var tpl = null;
|
||||
for (var i = 0; i < state.installed.length; i++) {
|
||||
if (state.installed[i].name === name) { tpl = state.installed[i]; break; }
|
||||
}
|
||||
if (! tpl || ! tpl.preview_urls || ! tpl.preview_urls.length) { return; }
|
||||
if (tpl.preview_urls.length === 1) {
|
||||
layer.open({ type: 1, title: tpl.title || name, area: 'auto',
|
||||
content: '<img src="' + tpl.preview_urls[0] + '" style="max-width:90vw;max-height:80vh;">' });
|
||||
} else {
|
||||
var data = tpl.preview_urls.map(function (u) { return { src: u, thumb: u, alt: tpl.title || name }; });
|
||||
layer.photos({ photos: { title: tpl.title || name, data: data }, anim: 5 });
|
||||
}
|
||||
};
|
||||
|
||||
table.on('tool(tplTable)', function (obj) {
|
||||
if (obj.event === 'setDefault') {
|
||||
api('setDefault', { template: obj.data.name }).then(function (res) {
|
||||
layer.msg(res.message || '已设默认', { icon: 1 });
|
||||
load();
|
||||
}, function () { layer.msg('操作失败', { icon: 2 }); });
|
||||
} else if (obj.event === 'toggle') {
|
||||
var enabled = obj.data.enabled ? 0 : 1;
|
||||
api('toggle', { name: obj.data.name, enabled: enabled }).then(function (res) {
|
||||
layer.msg(res.message || '已更新', { icon: 1 });
|
||||
load();
|
||||
}, function () { layer.msg('操作失败', { icon: 2 }); });
|
||||
} else if (obj.event === 'vars') {
|
||||
openVarsModal(obj.data);
|
||||
} else if (obj.event === 'uninstall') {
|
||||
layer.confirm('确认卸载模板「' + obj.data.name + '」?将删除其文件并解除绑定。', function (i) {
|
||||
api('uninstall', { name: obj.data.name }).then(function (res) {
|
||||
layer.msg(res.message || '已卸载', { icon: 1 });
|
||||
load();
|
||||
}, function () { layer.msg('卸载失败', { icon: 2 }); });
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function openVarsModal(tpl) {
|
||||
var defs = tpl.variable_defs || {};
|
||||
var overrides = tpl.variable_overrides || {};
|
||||
var rows = '';
|
||||
Object.keys(defs).forEach(function (k) {
|
||||
var d = defs[k];
|
||||
var cur = overrides[k] != null ? overrides[k] : (d.default || '');
|
||||
rows += '<div class="layui-form-item">'
|
||||
+ '<label class="layui-form-label">' + (d.label || k) + '</label>'
|
||||
+ '<div class="layui-input-block">'
|
||||
+ '<input type="text" class="layui-input" data-k="' + k + '" value="' + cur + '" placeholder="默认:' + (d.default || '') + '">'
|
||||
+ (d.type === 'color' ? ' <span style="color:#999;font-size:12px;">颜色填 #xxxxxx</span>' : '')
|
||||
+ '</div></div>';
|
||||
});
|
||||
if (rows === '') { rows = '<div style="padding:10px;color:#999;">该模板未声明可配置变量</div>'; }
|
||||
var html = '<form class="layui-form" style="padding:15px;" id="varsForm">'
|
||||
+ '<div style="color:#999;margin-bottom:10px;">模板:' + tpl.title + '(' + tpl.name + ')— 保存后无需改 HTML 即生效</div>'
|
||||
+ rows + '</form>';
|
||||
layer.open({
|
||||
type: 1, title: '风格配色 - ' + tpl.title, area: ['520px', 'auto'], content: html,
|
||||
btn: ['保存', '取消'],
|
||||
yes: function (idx) {
|
||||
var data = {};
|
||||
$('#varsForm input[data-k]').each(function () {
|
||||
data[$(this).data('k')] = $(this).val();
|
||||
});
|
||||
api('saveVariables', { name: tpl.name, vars: data }).then(function (res) {
|
||||
layer.msg(res.message || '已保存', { icon: 1 });
|
||||
layer.close(idx);
|
||||
load();
|
||||
}, function () { layer.msg('保存失败', { icon: 2 }); });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
upload.render({
|
||||
elem: '#uploadBtn',
|
||||
url: 'upload',
|
||||
accept: 'file',
|
||||
exts: 'zip',
|
||||
done: function (res) {
|
||||
if (res.code === 0) { layer.msg('安装成功', { icon: 1 }); load(); }
|
||||
else { layer.msg(res.message || '安装失败', { icon: 2 }); }
|
||||
},
|
||||
error: function () { layer.msg('上传失败', { icon: 2 }); }
|
||||
});
|
||||
|
||||
// 导出配置:直接触发浏览器下载
|
||||
$('#exportBtn').on('click', function () {
|
||||
window.location.href = 'exportConfig';
|
||||
});
|
||||
|
||||
// 导入配置:复用 upload 组件,仅接受 .json
|
||||
upload.render({
|
||||
elem: '#importBtn',
|
||||
url: 'importConfig',
|
||||
accept: 'file',
|
||||
exts: 'json',
|
||||
done: function (res) {
|
||||
if (res.code === 0) { layer.msg(res.message || '导入成功', { icon: 1 }); load(); }
|
||||
else { layer.msg(res.message || '导入失败', { icon: 2 }); }
|
||||
},
|
||||
error: function () { layer.msg('上传失败', { icon: 2 }); }
|
||||
});
|
||||
|
||||
load();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,63 @@
|
||||
<div class="layui-card" style="margin:15px;">
|
||||
<div class="layui-card-header">界面设置</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" id="settingForm">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">全站默认模板</label>
|
||||
<div class="layui-input-inline" style="width:320px;">
|
||||
<select name="default_template" id="defaultTemplate">
|
||||
<option value="default">默认(自带视图)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">未单独绑定模板的插件,统一使用此默认模板</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">会员自选风格</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="checkbox" name="allow_member_select" id="allowSelect" lay-skin="switch" lay-text="开启|关闭">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">允许前台会员切换风格(开启后,已安装模板提供覆盖视图的插件页面右下角自动出现切换器,按访客 cookie 生效,无需登录)</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="saveSetting">保存设置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
layui.use(['form', 'layer', 'jquery'], function () {
|
||||
var form = layui.form, layer = layui.layer, $ = layui.jquery;
|
||||
|
||||
// 拉取已安装模板填充下拉 + 当前设置
|
||||
$.ajax({
|
||||
url: 'index', type: 'POST', dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code !== 0) { return; }
|
||||
var inst = res.data.installed || [];
|
||||
var gd = res.data.global_default || 'default';
|
||||
var sel = $('#defaultTemplate');
|
||||
inst.forEach(function (t) {
|
||||
sel.append('<option value="' + t.name + '">' + t.title + ' (' + t.version + ')</option>');
|
||||
});
|
||||
sel.val(gd);
|
||||
$('#allowSelect').prop('checked', !!res.data.allow_member_select);
|
||||
form.render('select');
|
||||
form.render('checkbox');
|
||||
}
|
||||
});
|
||||
|
||||
form.on('submit(saveSetting)', function (data) {
|
||||
$.ajax({
|
||||
url: 'setting', type: 'POST', data: data.field, dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code === 0) { layer.msg('已保存', { icon: 1 }); }
|
||||
else { layer.msg(res.message || '保存失败', { icon: 2 }); }
|
||||
},
|
||||
error: function () { layer.msg('请求失败', { icon: 2 }); }
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,113 @@
|
||||
<div class="layui-container" style="margin-top:20px;">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">主框架在线升级</div>
|
||||
<div class="layui-card-body">
|
||||
<p>当前版本:<span class="layui-badge layui-bg-blue" id="current">{$current}</span></p>
|
||||
<div id="status" class="layui-text" style="margin:12px 0;min-height:24px;"></div>
|
||||
|
||||
<div id="pkgTypeBox" style="display:none;margin:12px 0;padding:10px 12px;background:#fafafa;border:1px solid #eee;border-radius:4px;">
|
||||
<div style="margin-bottom:8px;color:#555;">升级包类型:</div>
|
||||
<div class="layui-btn-group" id="pkgTypeGroup">
|
||||
<button type="button" class="layui-btn layui-btn-sm layui-btn-normal pkg-opt" data-type="auto">自动(推荐)</button>
|
||||
<button type="button" class="layui-btn layui-btn-sm layui-btn-primary pkg-opt" data-type="full">完整包</button>
|
||||
<button type="button" class="layui-btn layui-btn-sm layui-btn-primary pkg-opt" data-type="patch">增量小包</button>
|
||||
</div>
|
||||
<div id="pkgTypeTip" style="margin-top:8px;color:#e67700;font-size:13px;"></div>
|
||||
</div>
|
||||
|
||||
<button class="layui-btn layui-btn-normal" id="btnCheck">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 检查更新
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-danger" id="btnUpgrade" style="display:none;">
|
||||
<i class="layui-icon layui-icon-release"></i> 立即升级
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
layui.use(['jquery', 'layer'], function () {
|
||||
var $ = layui.jquery, layer = layui.layer;
|
||||
var selectedType = 'auto';
|
||||
|
||||
function setDisabled($el, dis) {
|
||||
if (dis) {
|
||||
$el.addClass('layui-btn-disabled').prop('disabled', true);
|
||||
} else {
|
||||
$el.removeClass('layui-btn-disabled').prop('disabled', false);
|
||||
}
|
||||
}
|
||||
|
||||
$('#pkgTypeGroup').on('click', '.pkg-opt', function () {
|
||||
if ($(this).prop('disabled')) return;
|
||||
selectedType = $(this).data('type');
|
||||
$('#pkgTypeGroup .pkg-opt').removeClass('layui-btn-normal').addClass('layui-btn-primary');
|
||||
$(this).removeClass('layui-btn-primary').addClass('layui-btn-normal');
|
||||
});
|
||||
|
||||
function check() {
|
||||
$('#status').html('<i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate"></i> 正在检查...');
|
||||
$.get('{:url("framework/check")}', function (res) {
|
||||
if (res.code === 0) {
|
||||
var d = res.data;
|
||||
if (d.has_update) {
|
||||
var autoMode = d.use_patch ? '增量补丁' : '整包';
|
||||
var html = '发现新版本:<b>' + d.latest + '</b>'
|
||||
+ ' <span class="layui-badge layui-bg-orange">自动模式将使用' + autoMode + '</span>';
|
||||
if (d.use_patch && d.patch_from) html += '(基于 ' + d.patch_from + ')';
|
||||
if (d.has_full && d.has_patch) html += ' <span class="layui-badge layui-bg-gray">已同时发布完整包与增量小包</span>';
|
||||
if (d.title) html += '(' + d.title + ')';
|
||||
if (d.error) {
|
||||
html += '<br><span style="color:#dc2626;">' + d.error + '</span>';
|
||||
}
|
||||
html += '<br>更新内容:<pre style="margin-top:6px;">' + (d.changelog || '') + '</pre>';
|
||||
$('#status').html(html);
|
||||
|
||||
if (d.error) {
|
||||
$('#btnUpgrade').hide();
|
||||
$('#pkgTypeBox').hide();
|
||||
} else {
|
||||
$('#btnUpgrade').show();
|
||||
// 显示升级包类型选择(按钮组,不依赖 layui.form)
|
||||
$('#pkgTypeBox').show();
|
||||
selectedType = 'auto';
|
||||
$('#pkgTypeGroup .pkg-opt').removeClass('layui-btn-normal').addClass('layui-btn-primary');
|
||||
$('#pkgTypeGroup .pkg-opt[data-type=auto]').removeClass('layui-btn-primary').addClass('layui-btn-normal');
|
||||
setDisabled($('#pkgTypeGroup .pkg-opt[data-type=full]'), !d.has_full);
|
||||
setDisabled($('#pkgTypeGroup .pkg-opt[data-type=patch]'), !d.use_patch);
|
||||
var tips = [];
|
||||
if (!d.has_full) tips.push('当前无完整包可用');
|
||||
if (!d.use_patch) tips.push('当前版本(' + (d.current || '') + ')不支持增量小包,需基于 ' + (d.patch_from || '?'));
|
||||
$('#pkgTypeTip').text(tips.length ? '提示:' + tips.join(';') + ',建议选「自动」' : '可手动选择完整包或增量小包');
|
||||
}
|
||||
} else {
|
||||
$('#status').html('<span style="color:#16a34a;">✓ 已是最新版本(' + d.current + ')</span>');
|
||||
$('#btnUpgrade').hide();
|
||||
$('#pkgTypeBox').hide();
|
||||
}
|
||||
} else {
|
||||
$('#status').html('<span style="color:#dc2626;">' + (res.message || '检查失败') + '</span>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('#btnCheck').on('click', check);
|
||||
|
||||
$('#btnUpgrade').on('click', function () {
|
||||
var label = {auto: '自动模式', full: '完整包', patch: '增量小包'}[selectedType] || selectedType;
|
||||
layer.confirm('将以【' + label + '】升级,将备份当前核心并覆盖,确定继续?', function () {
|
||||
$('#status').html('<i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate"></i> 正在下载并升级...');
|
||||
$.post('{:url("framework/upgrade")}', {type: selectedType}, function (res) {
|
||||
if (res.code === 0) {
|
||||
$('#status').html('<span style="color:#16a34a;">✓ ' + res.message + '</span>');
|
||||
$('#btnUpgrade').hide();
|
||||
$('#pkgTypeBox').hide();
|
||||
} else {
|
||||
$('#status').html('<span style="color:#dc2626;">' + (res.message || '升级失败') + '</span>');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
check();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,179 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"></div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-group">
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="新建数据"
|
||||
lay-event="dataCreate"
|
||||
data-perm="user:add">
|
||||
<i class="layui-icon layui-icon-add-1"></i>
|
||||
</a>
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="删除资源"
|
||||
lay-event="dataDelete"
|
||||
data-perm="user:delete"
|
||||
><i class="layui-icon layui-icon-delete"></i>
|
||||
</a>
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="资源回收站"
|
||||
lay-event="dataRecybin"
|
||||
data-perm="user:recyclebin"
|
||||
><i class="layui-icon layui-icon-home"></i>
|
||||
</a>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="dataBar">
|
||||
<div class="layui-btn-group">
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="编辑数据"
|
||||
lay-event="update"
|
||||
data-perm="user:edit"
|
||||
><i class="layui-icon layui-icon-edit"></i>
|
||||
</a>
|
||||
{{# if(!d.is_super) { }}
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="删除数据"
|
||||
lay-event="delete"
|
||||
data-perm="user:delete"
|
||||
><i class="layui-icon layui-icon-delete"></i>
|
||||
</a>
|
||||
{{# } }}
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 表格回收站 -->
|
||||
<script type="text/html" id="dataRecybinTpl">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"></div>
|
||||
<div class="layui-card-body">
|
||||
<table
|
||||
class="layui-hide"
|
||||
id="dataRecybinTable"
|
||||
lay-filter="dataRecybinTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 回收站数据工具条 -->
|
||||
<script type="text/html" id="dataRecybinBarTpl">
|
||||
<div class="layui-btn-group">
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="恢复数据"
|
||||
lay-event="update"
|
||||
><i class="layui-icon layui-icon-edit"></i>
|
||||
</a>
|
||||
<a
|
||||
class="layui-btn layui-btn-sm layui-btn-primary"
|
||||
title="删除数据"
|
||||
lay-event="delete"
|
||||
><i class="layui-icon layui-icon-delete"></i>
|
||||
</a>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 状态开关 -->
|
||||
<script type="text/html" id="statusTpl">
|
||||
<input type="checkbox" name="status" value="{{d.id}}" lay-skin="switch" lay-text="启用|禁用" lay-filter="statusSwitch" {{ d.status == 1 ? 'checked' : '' }}>
|
||||
</script>
|
||||
|
||||
<!-- 角色显示 -->
|
||||
<script type="text/html" id="roleTpl">
|
||||
{{# if(d.is_super == 1) { }}
|
||||
<span class="role-super">超级管理员</span>
|
||||
{{# } else if(d.role_id == 1) { }}
|
||||
<span class="role-super">超级管理员</span>
|
||||
{{# } else if(d.role_id == 2) { }}
|
||||
<span>普通管理员</span>
|
||||
{{# } else { }}
|
||||
<span>未知角色</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<!-- 登录信息 -->
|
||||
<script type="text/html" id="loginInfoTpl">
|
||||
<div>登录次数:{{d.login_count}}</div>
|
||||
<div>最后登录:{{ d.login_time }}</div>
|
||||
</script>
|
||||
|
||||
<!-- 添加/编辑管理员表单 -->
|
||||
<script type="text/html" id="dataFormTpl">
|
||||
<form class="layui-form" style="padding: 20px 20px 0;">
|
||||
<input type="hidden" name="uid" value="{{d.uid||''}}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">账户</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="account" required lay-verify="required|account" placeholder="请输入用户名" autocomplete="off" class="layui-input" value="{{d.account||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">昵称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="nickname" required lay-verify="required" placeholder="请输入真实姓名" autocomplete="off" class="layui-input" value="{{d.nickname||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">角色</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="role_id" lay-verify="required">
|
||||
<option value="">请选择角色</option>
|
||||
<option value="1" {{ (d.role_id==1||d.is_super==1) ? 'selected' : '' }}>超级管理员</option>
|
||||
<option value="2" {{ d.role_id==2 ? 'selected' : '' }}>普通管理员</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">邮箱</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="email" lay-verify="email" placeholder="请输入邮箱" autocomplete="off" class="layui-input" value="{{d.email||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">手机号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="mobile" lay-verify="phone" placeholder="请输入手机号" autocomplete="off" class="layui-input" value="{{d.mobile||''}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="status" value="1" title="启用" {{ d.status==undefined || d.status==1 ? 'checked' : '' }}>
|
||||
<input type="radio" name="status" value="0" title="禁用" {{ d.status==0 ? 'checked' : '' }}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="passwordGroup" {{ d.uid ? 'style="display:none;"' : '' }}>
|
||||
<label class="layui-form-label">密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="password" name="password" required lay-verify="required|pass" placeholder="请输入密码" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-hide" id="resetPwdGroup">
|
||||
<label class="layui-form-label">新密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="password" name="new_password" required lay-verify="required|pass" placeholder="请输入新密码" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">备注</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="remark" placeholder="请输入备注信息" class="layui-textarea">{{d.remark||''}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.use(["user"], function () { });
|
||||
</script>
|
||||
Reference in New Issue
Block a user