feat: 上线前安全加固与发布工程化;appmall 由插件迁移为独立应用
安全(P0) - 发布包签名:新增 scripts/package_keygen.php、scripts/package_verify.php、 ywxapp\service\PackageVerifier;FrameworkService::apply() 解压前强制验签 (ywxapp.framework_package_verify,默认开启) - JWT 收紧:config/jwt.php 移除公开默认密钥,JwtService::assertStrongSecret() 校验非空 / 长度≥32 / 已知弱值;.env.production.example 键名由 JWT_SECRET_KEY 修正为 JWT_SECRET - /api/v1/Article:免登录白名单收窄为只读接口,写操作字段白名单 + assertOwner() 越权校验 - 开发者令牌:查找接口不再回显明文、统一失败文案 + 限流 - TemplateInstaller:文件名白名单 + realpath 归一化 + 目录内断言,修复 Zip Slip;补 use ZipArchive - 后台登录:接入验证码、失败锁定与登录限流(config/ratelimit.php) - 缓存 / Session 驱动可由 .env 覆盖(CACHE_DRIVER / SESSION_TYPE),集群部署改 redis - paycenter 支付日志开关改为 PAY_LOG,不再跟随 APP_DEBUG 工程化 / 交付 - 新增 CHANGELOG.md 与 .env.production.example;composer.lock 入库锁定依赖版本 - 插件离线安装 CLI 增加 --uid,后台上传安装透传 uid,付费插件授权校验可通过 - 授权拒绝文案区分「未携带 uid」与「未找到有效授权」,便于排障 - .gitignore 放行 .env.production.example / .env.addon.example / .gitattributes / public/.htaccess 结构 - appmall 由 addon/appmall 迁移为独立应用 app/appmall(市场 / 开发者中心 / 审核 / 分润)
This commit is contained in:
1 parent
1d49e6f5ee
commit
18101cf11a
636 files changed
+58517
-9519
No files matched your search
@@ -68,8 +68,20 @@
|
||||
|
||||
<!-- 右侧操作列模板 (配置/卸载) -->
|
||||
|
||||
<!-- 版本号列:可升级时附带市场最新版本徽章 -->
|
||||
<script type="text/html" id="versionTpl">
|
||||
{{= d.version || '-' }}
|
||||
{{# if(d.upgradable){ }}
|
||||
<span class="layui-badge layui-bg-orange" style="margin-left:4px;"
|
||||
title="市场最新版本 {{= d.latest_version }}">可升级 {{= d.latest_version }}</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="operateTpl">
|
||||
<div class="layui-clear-space">
|
||||
{{# if(d.upgradable){ }}
|
||||
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="upgrade" data-perm="addon:edit">升级</a>
|
||||
{{# } }}
|
||||
{{# 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>
|
||||
{{# } }}
|
||||
|
||||
@@ -97,6 +97,32 @@
|
||||
{/volist}
|
||||
{elseif $f.type == 'number' /}
|
||||
<input type="number" name="{$f.name}" value="{$f.value}" class="layui-input">
|
||||
{elseif $f.type == 'switch' /}
|
||||
<!-- 隐藏域保证「关闭」也能提交 0(layui switch 未勾选时不提交) -->
|
||||
<input type="hidden" name="{$f.name}" value="0">
|
||||
<input type="checkbox" name="{$f.name}" value="1" lay-skin="switch" lay-text="开|关" {if $f.value}checked{/if}>
|
||||
{elseif $f.type == 'array' /}
|
||||
<textarea name="{$f.name}" class="layui-textarea" rows="5"
|
||||
placeholder="每行一条,格式:键=值(不写等号则作为列表项)">{$f.value}</textarea>
|
||||
{elseif $f.type == 'date' /}
|
||||
<input type="text" name="{$f.name}" value="{$f.value}" class="layui-input cfg-date"
|
||||
placeholder="YYYY-MM-DD" autocomplete="off">
|
||||
{elseif $f.type == 'image' /}
|
||||
<input type="text" name="{$f.name}" value="{$f.value}" class="layui-input" placeholder="图片地址">
|
||||
{if $f.value}
|
||||
<div style="margin-top:6px;"><img src="{$f.value}" style="max-height:80px;"></div>
|
||||
{/if}
|
||||
{elseif $f.type == 'file' /}
|
||||
<input type="text" name="{$f.name}" value="{$f.value}" class="layui-input" placeholder="文件路径或 URL">
|
||||
{elseif $f.type == 'color' /}
|
||||
<input type="color" name="{$f.name}" value="{$f.value|default='#1E9FFF'}" class="layui-input"
|
||||
style="width:80px;padding:2px;height:38px;">
|
||||
{elseif $f.type == 'tags' /}
|
||||
<input type="text" name="{$f.name}" value="{$f.value}" class="layui-input" placeholder="多个用逗号分隔">
|
||||
{elseif $f.type == 'password' /}
|
||||
<input type="password" name="{$f.name}" value="{$f.value}" class="layui-input" autocomplete="new-password">
|
||||
{elseif $f.type == 'editor' /}
|
||||
<textarea name="{$f.name}" class="layui-textarea cfg-editor" rows="8" placeholder="支持 HTML">{$f.value}</textarea>
|
||||
{else /}
|
||||
<input type="text" name="{$f.name}" value="{$f.value}" class="layui-input">
|
||||
{/if}
|
||||
@@ -114,12 +140,18 @@
|
||||
</div>
|
||||
</div>
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<!-- 本页是独立页(不走 layout),必须自己引入 ywxapp.js 才能用集成的 http -->
|
||||
<script src="/assets/ywxapp/ywxapp.js" module="backend"></script>
|
||||
<script>
|
||||
layui.use(['form', 'layer'], function () {
|
||||
var form = layui.form, $ = layui.jquery, layer = layui.layer;
|
||||
layui.use(['form', 'layer', 'ywxapp', 'http', 'laydate'], function () {
|
||||
var form = layui.form, $ = layui.jquery, layer = layui.layer, http = layui.http, laydate = layui.laydate;
|
||||
// date 型字段:逐个绑定日期选择(laydate 的 class 选择器只渲染首个,故遍历 DOM)
|
||||
Array.prototype.forEach.call(document.querySelectorAll('input.cfg-date'), function (el) {
|
||||
laydate.render({ elem: el, type: 'date' });
|
||||
});
|
||||
form.on('submit(cfgForm)', function (data) {
|
||||
$.post(window.location.href, data.field, function (r) {
|
||||
if (r.code === 0) {
|
||||
http.post(window.location.href, data.field).then(function (r) {
|
||||
if (r && r.code === 0) {
|
||||
layer.msg(r.message || '保存成功', { icon: 1 });
|
||||
// 保存成功后自动跳回插件列表(兼容 layui admin 的 tab 场景),
|
||||
// 避免停留在配置 tab 需要手动关闭重开才能看到列表。
|
||||
@@ -127,9 +159,11 @@
|
||||
window.location.href = '{:url("addon/index")}';
|
||||
}, 800);
|
||||
} else {
|
||||
layer.msg(r.message || '保存失败', { icon: 2 });
|
||||
layer.msg((r && r.message) || '保存失败', { icon: 2 });
|
||||
}
|
||||
}, 'json');
|
||||
}).catch(function (err) {
|
||||
layer.msg('请求失败:' + (err && err.message ? err.message : '网络异常'), { icon: 2 });
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
</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>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" title="新建节点" lay-event="dataCreate" data-perm="admin:create"> <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="admin: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="admin:index"><i class="layui-icon layui-icon-home"></i> </a>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="dataBar">
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<div class="layui-fluid"><div class="layui-card">
|
||||
<div class="layui-card-header">操作日志</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-form" lay-filter="search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="keyword" placeholder="账号 / 昵称 / IP / 备注" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<select name="action">
|
||||
<option value="">全部动作</option>
|
||||
{foreach $actions as $act}
|
||||
<option value="{$act.action}">{$act.action}({$act.total})</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="start" id="start" placeholder="开始日期" autocomplete="off" class="layui-input" style="width:120px">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="end" id="end" placeholder="结束日期" autocomplete="off" class="layui-input" style="width:120px">
|
||||
</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>
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="deleteSelected" data-perm="adminlog:delete">
|
||||
<i class="layui-icon layui-icon-delete"></i> 删除选中
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-event="clean" data-perm="adminlog:clean">
|
||||
<i class="layui-icon layui-icon-clear"></i> 按天数清理
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="dataBar">
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete" data-perm="adminlog:delete">删除</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['adminlog'], function () {});
|
||||
</script>
|
||||
@@ -0,0 +1,88 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-sm4">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div style="color:#666">附件总数</div>
|
||||
<div style="font-size:26px;font-weight:600">{$stat.total}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm4">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div style="color:#666">占用空间</div>
|
||||
<div style="font-size:26px;font-weight:600">{$stat.size_text}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm4">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div style="color:#666">图片</div>
|
||||
<div style="font-size:26px;font-weight:600">{$stat.image}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">附件管理</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-form" lay-filter="search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="keyword" placeholder="文件名 / 路径" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<select name="module">
|
||||
<option value="">全部模块</option>
|
||||
{foreach $modules as $m}
|
||||
<option value="{$m.module}">{$m.module}({$m.total})</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="checkbox" name="only_image" value="1" title="只看图片" lay-skin="primary">
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="deleteSelected" data-perm="attachment:delete">
|
||||
<i class="layui-icon layui-icon-delete"></i> 删除选中
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="dataBar">
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-xs layui-btn-normal" lay-event="open">查看</button>
|
||||
<button class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete" data-perm="attachment:delete">删除</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="thumbTpl">
|
||||
{{# if (d.is_image == 1) { }}
|
||||
<img src="{{= d.url }}" alt="" style="width:40px;height:40px;object-fit:cover;cursor:pointer" lay-event="open">
|
||||
{{# } else { }}
|
||||
<span class="layui-badge layui-bg-gray">{{= d.ext }}</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['attachment'], function () {});
|
||||
</script>
|
||||
@@ -69,13 +69,17 @@
|
||||
app: "{$site.app}",
|
||||
routeBase: "{$route_base}",
|
||||
controller: "{$site.controller}",
|
||||
action: "{$site.action}"
|
||||
action: "{$site.action}",
|
||||
powers: {:json_encode($powers ?? [])}
|
||||
};
|
||||
</script>
|
||||
<script src="/assets/ywxapp/ywxapp.js" module="{$site.app}"></script>
|
||||
{:hook('backend.layout.head', ['site' => $site ?? []])}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{:hook('backend.layout.body_start', ['site' => $site ?? []])}
|
||||
{__CONTENT__}
|
||||
{:hook('backend.layout.body_end', ['site' => $site ?? []])}
|
||||
</body>
|
||||
</html>
|
||||
+217
-217
@@ -1,17 +1,148 @@
|
||||
<div class="layui-fluid">
|
||||
|
||||
<!-- 系统概览:与「系统信息」页同源(app\backend\library\SystemInfo),控制台只做展示 -->
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-sm6 layui-col-md3">
|
||||
<div class="layui-card"><div class="layui-card-body">
|
||||
<div style="color:#666">管理员</div>
|
||||
<div style="font-size:24px;font-weight:600">{$sys.stat.admin}</div>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="layui-col-sm6 layui-col-md3">
|
||||
<div class="layui-card"><div class="layui-card-body">
|
||||
<div style="color:#666">插件</div>
|
||||
<div style="font-size:24px;font-weight:600">{$sys.stat.addon}</div>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="layui-col-sm6 layui-col-md3">
|
||||
<div class="layui-card"><div class="layui-card-body">
|
||||
<div style="color:#666">附件</div>
|
||||
<div style="font-size:24px;font-weight:600">{$sys.stat.attachment}</div>
|
||||
<div style="color:#999;font-size:12px">占用 {$sys.stat.attach_size_text}</div>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="layui-col-sm6 layui-col-md3">
|
||||
<div class="layui-card"><div class="layui-card-body">
|
||||
<div style="color:#666">数据库</div>
|
||||
<div style="font-size:24px;font-weight:600">{$sys.stat.db_size_text}</div>
|
||||
</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">运行环境</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table layui-table-sm" lay-skin="nob">
|
||||
<tbody>
|
||||
{foreach $sys.env as $row}
|
||||
<tr>
|
||||
<td style="width:120px;color:#666">{$row[0]}</td>
|
||||
<td>{$row[1]}</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">磁盘</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-progress layui-progress-big" lay-showPercent="true">
|
||||
<div class="layui-progress-bar" style="width:{$sys.disk.percent}%"></div>
|
||||
</div>
|
||||
<div style="margin-top:10px;color:#666">
|
||||
已用 {$sys.disk.used_text} / 共 {$sys.disk.total_text},剩余 {$sys.disk.free_text}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-col-md6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">目录权限</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table layui-table-sm" lay-skin="nob">
|
||||
<thead><tr><th>目录</th><th>存在</th><th>可写</th></tr></thead>
|
||||
<tbody>
|
||||
{foreach $sys.dirs as $d}
|
||||
<tr>
|
||||
<td>{$d.name}</td>
|
||||
<td>{if $d.exists}<span class="layui-badge layui-bg-green">是</span>{else}<span class="layui-badge">否</span>{/if}</td>
|
||||
<td>{if $d.writable}<span class="layui-badge layui-bg-green">可写</span>{else}<span class="layui-badge layui-bg-red">不可写</span>{/if}</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="color:#999;font-size:12px">不可写的目录会导致缓存无法生成、上传失败、插件无法安装。</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">维护</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-normal" id="sys-clean-cache" data-perm="console:clean">清理数据缓存</button>
|
||||
<button class="layui-btn" id="sys-clean-temp" data-perm="console:clean">清理模板缓存</button>
|
||||
<button class="layui-btn layui-btn-warm" id="sys-clean-all" data-perm="console:clean">全量清理</button>
|
||||
</div>
|
||||
<div style="margin-top:10px;color:#999;font-size:12px">
|
||||
只清理 runtime/cache 与 runtime/temp;<strong>不会删除 runtime/log</strong>(操作日志与错误日志保留)。
|
||||
</div>
|
||||
<div style="margin-top:12px;color:#666">
|
||||
近 7 天操作 <strong>{$sys.stat.log_week}</strong> 条,其中登录失败 <strong style="color:#ff5722">{$sys.stat.login_fail}</strong> 次。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 框架升级:与「系统管理 → 框架升级」同源,共用 /admin/framework/check|upgrade -->
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">框架升级</div>
|
||||
<div class="layui-card-body">
|
||||
<p style="margin-bottom:8px">当前版本:<span class="layui-badge layui-bg-blue" id="fw-current">{$version}</span></p>
|
||||
<div id="fw-status" class="layui-text" style="margin:10px 0;min-height:24px;"></div>
|
||||
|
||||
<div id="fw-pkg-box" style="display:none;margin:10px 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="fw-pkg-group">
|
||||
<button type="button" class="layui-btn layui-btn-sm layui-btn-normal fw-pkg" data-type="auto">自动(推荐)</button>
|
||||
<button type="button" class="layui-btn layui-btn-sm layui-btn-primary fw-pkg" data-type="full">完整包</button>
|
||||
<button type="button" class="layui-btn layui-btn-sm layui-btn-primary fw-pkg" data-type="patch">增量小包</button>
|
||||
</div>
|
||||
<div id="fw-pkg-tip" style="margin-top:8px;color:#e67700;font-size:13px;"></div>
|
||||
</div>
|
||||
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-normal" id="fw-check" data-perm="framework:check">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 检查更新
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-danger" id="fw-upgrade" data-perm="framework:upgrade" style="display:none;">
|
||||
<i class="layui-icon layui-icon-release"></i> 立即升级
|
||||
</button>
|
||||
</div>
|
||||
<div style="margin-top:10px;color:#999;font-size:12px">
|
||||
升级前会自动备份当前核心文件;本卡片与「系统管理 → 框架升级」是同一套接口与权限。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
会员总数
|
||||
<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 class="layuiadmin-big-font">{$stats.total.member}</p>
|
||||
<p>
|
||||
总计访问量
|
||||
<span class="layuiadmin-span-color">88万 <i class="layui-inline layui-icon layui-icon-flag"></i></span>
|
||||
近 7 天新增
|
||||
<span class="layuiadmin-span-color">{$stats.total.member_week} 人 <i class="layui-inline layui-icon layui-icon-user"></i></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -19,14 +150,14 @@
|
||||
<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>
|
||||
今日新增会员
|
||||
<span class="layui-badge layui-bg-green layuiadmin-badge">日</span>
|
||||
</div>
|
||||
<div class="layui-card-body layuiadmin-card-list">
|
||||
<p class="layuiadmin-big-font">33,555</p>
|
||||
<p class="layuiadmin-big-font">{$stats.today.member}</p>
|
||||
<p>
|
||||
新下载
|
||||
<span class="layuiadmin-span-color">10% <i class="layui-inline layui-icon layui-icon-face-smile-b"></i></span>
|
||||
会员表实时统计
|
||||
<span class="layuiadmin-span-color">今日 <i class="layui-inline layui-icon layui-icon-friends"></i></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -34,15 +165,14 @@
|
||||
<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>
|
||||
今日操作
|
||||
<span class="layui-badge layui-bg-cyan layuiadmin-badge">日</span>
|
||||
</div>
|
||||
<div class="layui-card-body layuiadmin-card-list">
|
||||
|
||||
<p class="layuiadmin-big-font">999,888</p>
|
||||
<p class="layuiadmin-big-font">{$stats.today.log}</p>
|
||||
<p>
|
||||
总赞
|
||||
<span class="layuiadmin-span-color">*** <i class="layui-inline layui-icon layui-icon-heart"></i></span>
|
||||
后台操作记录
|
||||
<span class="layuiadmin-span-color">累计 {$stats.total.log} <i class="layui-inline layui-icon layui-icon-log"></i></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -50,15 +180,14 @@
|
||||
<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>
|
||||
今日蜘蛛来访
|
||||
<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 class="layuiadmin-big-font">{$stats.today.spider}</p>
|
||||
<p>
|
||||
最近一个月
|
||||
<span class="layuiadmin-span-color">15% <i class="layui-inline layui-icon layui-icon-user"></i></span>
|
||||
搜索引擎抓取
|
||||
<span class="layuiadmin-span-color">累计 {$stats.total.spider} <i class="layui-inline layui-icon layui-icon-chart-screen"></i></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -66,229 +195,78 @@
|
||||
<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>
|
||||
近 7 天趋势
|
||||
<span class="layui-badge layui-bg-blue layuiadmin-badge">会员注册 / 后台操作</span>
|
||||
</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 class="layui-carousel layadmin-carousel layadmin-dataview" data-anim="fade" lay-filter="LAY-index-trendview">
|
||||
<div carousel-item id="LAY-index-trend">
|
||||
<div><i class="layui-icon layui-icon-loading1 layadmin-loading"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm4">
|
||||
<div class="layui-col-sm6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">用户留言</div>
|
||||
<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>
|
||||
<table class="layui-table layuiadmin-page-table" lay-skin="line">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>账号</th>
|
||||
<th>昵称</th>
|
||||
<th>注册时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{empty name="stats.members"}
|
||||
<tr><td colspan="3" style="text-align:center;color:#999;">暂无数据</td></tr>
|
||||
{/empty}
|
||||
{foreach $stats.members as $m}
|
||||
<tr>
|
||||
<td>{$m.account}</td>
|
||||
<td>{$m.nickname}</td>
|
||||
<td>{$m.create_at|date='m-d H:i'}</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm8">
|
||||
<div class="layui-col-sm6">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-sm6">
|
||||
<div class="layui-col-sm12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">本周活跃用户列表</div>
|
||||
<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>
|
||||
<th>管理员</th>
|
||||
<th>操作</th>
|
||||
<th>IP</th>
|
||||
<th>时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{empty name="stats.logs"}
|
||||
<tr><td colspan="4" style="text-align:center;color:#999;">暂无数据</td></tr>
|
||||
{/empty}
|
||||
{foreach $stats.logs as $l}
|
||||
<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>
|
||||
<td>{$l.admin}</td>
|
||||
<td>{$l.action}</td>
|
||||
<td>{$l.ip}</td>
|
||||
<td>{$l.time|date='m-d H:i'}</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</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>
|
||||
|
||||
@@ -296,6 +274,28 @@
|
||||
</div>
|
||||
</div>
|
||||
<script src="/assets/layui/layui.js?t=1"></script>
|
||||
<script type="text/javascript">
|
||||
// 本页会再次加载 layui,覆盖掉 layout 里注入的 layui.app(含当前登录者权限集 powers)。
|
||||
// 必须在这里补回来:auth 模块在加载时读 layui.app.powers,拿不到就会把
|
||||
// 所有带 [data-perm] 的按钮当成无权限移除(控制台的清理按钮会消失)。
|
||||
layui.app = {
|
||||
root: "{$site.root|default=''}",
|
||||
assetUrl: "/assets",
|
||||
module: "{$site.module}",
|
||||
app: "{$site.app}",
|
||||
routeBase: "{$route_base}",
|
||||
controller: "{$site.controller}",
|
||||
action: "{$site.action}",
|
||||
powers: {:json_encode($powers ?? [])}
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
// 首页下半区真实统计(Console::collectStats 产出),给 console.js 画趋势图用。
|
||||
// json_encode 带 HEX_* 选项:模板 default_filter 会把 <>&'" 转义成实体,
|
||||
// 先转成 \u003C 这类 unicode 才能保证丢到 JS 里仍是合法 JSON。
|
||||
// 第二个参数 15 = JSON_HEX_TAG|HEX_AMP|HEX_APOS|HEX_QUOT(这里不能写竖线,模板把它当修饰符分隔符)
|
||||
layui.stats = {:json_encode($stats ?? [], 15)};
|
||||
</script>
|
||||
<script src="/assets/ywxapp/ywxapp.js" module="backend"></script>
|
||||
<script>
|
||||
layui.use('console');
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<div class="layui-fluid"><div class="layui-card">
|
||||
<div class="layui-card-header">数据库备份 / 还原</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab layui-tab-brief" lay-filter="dbTab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this" lay-id="table">数据表</li>
|
||||
<li lay-id="backup">备份记录</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content" style="padding:10px 0">
|
||||
<!-- 数据表 -->
|
||||
<div class="layui-tab-item layui-show">
|
||||
<div class="layui-form" lay-filter="search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="keyword" 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>
|
||||
<table class="layui-hide" id="tableList" lay-filter="tableList"></table>
|
||||
</div>
|
||||
|
||||
<!-- 备份记录 -->
|
||||
<div class="layui-tab-item">
|
||||
<table class="layui-hide" id="backupList" lay-filter="backupList"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
<!-- 数据表工具条 -->
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="backupSelected" data-perm="database:backup">
|
||||
<i class="layui-icon layui-icon-template-1"></i> 备份选中
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-event="backupAll" data-perm="database:backup">
|
||||
<i class="layui-icon layui-icon-fonts-code"></i> 备份全部
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-event="optimize" data-perm="database:optimize">
|
||||
<i class="layui-icon layui-icon-set"></i> 优化表
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 备份记录工具条 -->
|
||||
<script type="text/html" id="backupBar">
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" lay-event="reload">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 刷新
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 备份记录行操作 -->
|
||||
<script type="text/html" id="backupAction">
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-xs layui-btn-normal" lay-event="download" data-perm="database:index">下载</button>
|
||||
<button class="layui-btn layui-btn-xs layui-btn-danger" lay-event="recovery" data-perm="database:recovery">还原</button>
|
||||
<button class="layui-btn layui-btn-xs" lay-event="delete" data-perm="database:delete">删除</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['database'], function () {});
|
||||
</script>
|
||||
@@ -0,0 +1,172 @@
|
||||
<div class="layui-fluid"><div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
数据表管理
|
||||
<span class="layui-word-aux" style="margin-left:10px">
|
||||
表前缀:<b>{$prefix}</b> 建表成功后可直接用 addon:crud 生成 CRUD
|
||||
</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-form" lay-filter="search-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="keyword" placeholder="表名 / 表备注" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<select name="unregistered">
|
||||
<option value="0">全部表</option>
|
||||
<option value="1">仅未归档(不在任何 install.sql)</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 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="tableList" lay-filter="tableList"></table>
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
<!-- 顶部工具条 -->
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="create" data-perm="datatable:create">
|
||||
<i class="layui-icon layui-icon-add-1"></i> 新建表
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-event="optimize" data-perm="datatable:optimize">
|
||||
<i class="layui-icon layui-icon-set"></i> 优化选中
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-event="export" data-perm="datatable:export">
|
||||
<i class="layui-icon layui-icon-export"></i> 导出安装 SQL
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" lay-event="reload" data-perm="datatable:index">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 刷新
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 行操作 -->
|
||||
<script type="text/html" id="tableAction">
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-xs layui-btn-normal" lay-event="structure" data-perm="datatable:index">结构</button>
|
||||
<button class="layui-btn layui-btn-xs" lay-event="exportRow" data-perm="datatable:export">导出SQL</button>
|
||||
<button class="layui-btn layui-btn-xs layui-btn-warm" lay-event="optimizeRow" data-perm="datatable:optimize">优化</button>
|
||||
{{# if(!d.protected){ }}
|
||||
<button class="layui-btn layui-btn-xs layui-btn-danger" lay-event="drop" data-perm="datatable:drop">删除</button>
|
||||
{{# } }}
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 新建表弹窗 -->
|
||||
<script type="text/html" id="createTpl">
|
||||
<div style="padding:15px">
|
||||
<form class="layui-form layui-form-pane" lay-filter="create-form" id="create-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label" style="width:70px">表名</label>
|
||||
<div class="layui-input-inline" style="width:150px">
|
||||
<input type="text" name="table" placeholder="demo_item" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label" style="width:70px">表备注</label>
|
||||
<div class="layui-input-inline" style="width:180px">
|
||||
<input type="text" name="comment" placeholder="演示表" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label" style="width:70px">引擎</label>
|
||||
<div class="layui-input-inline" style="width:110px">
|
||||
<select name="engine"><option value="InnoDB">InnoDB</option><option value="MyISAM">MyISAM</option><option value="MEMORY">MEMORY</option></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label" style="width:70px">字符集</label>
|
||||
<div class="layui-input-inline" style="width:120px">
|
||||
<select name="charset"><option value="{$charset}">{$charset}</option><option value="utf8">utf8</option><option value="gbk">gbk</option></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>字段(至少 1 个)</legend>
|
||||
<div class="layui-field-box" id="fieldRows"></div>
|
||||
<button type="button" class="layui-btn layui-btn-xs layui-btn-primary" id="btn-add-field">
|
||||
<i class="layui-icon layui-icon-add-1"></i> 添加字段
|
||||
</button>
|
||||
<button type="button" class="layui-btn layui-btn-xs layui-btn-primary" id="btn-add-id">补一个 id 主键行</button>
|
||||
</fieldset>
|
||||
|
||||
<div class="layui-form-item" style="margin-top:10px">
|
||||
<label class="layui-form-label" style="width:70px">SQL 预览</label>
|
||||
<div class="layui-input-block" style="margin-left:100px">
|
||||
<textarea id="sqlPreview" class="layui-textarea" rows="8" readonly placeholder="点「生成 SQL 预览」后显示,确认无误再执行"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block" style="margin-left:0;text-align:right">
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="btn-preview">
|
||||
<i class="layui-icon layui-icon-fonts-code"></i> 生成 SQL 预览
|
||||
</button>
|
||||
<button type="button" class="layui-btn" id="btn-exec" data-perm="datatable:create">
|
||||
<i class="layui-icon layui-icon-ok"></i> 执行创建
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 导出安装 SQL 弹窗 -->
|
||||
<script type="text/html" id="exportTpl">
|
||||
<div style="padding:15px">
|
||||
<div id="exportSummary" class="layui-word-aux" style="margin-bottom:8px"></div>
|
||||
<table class="layui-table layui-table-sm">
|
||||
<thead><tr><th>表</th><th style="width:120px">归档状态</th><th>建议写入</th></tr></thead>
|
||||
<tbody id="exportBody"></tbody>
|
||||
</table>
|
||||
<textarea id="exportSqlText" class="layui-textarea" rows="14" readonly></textarea>
|
||||
<div style="margin-top:8px;text-align:right">
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="btn-copy-sql">复制</button>
|
||||
<button type="button" class="layui-btn" id="btn-download-sql">下载 .sql</button>
|
||||
</div>
|
||||
<div class="layui-word-aux" style="margin-top:6px">
|
||||
表名已换成 <code>__PREFIX__</code> 占位符,可直接粘进对应 install.sql;
|
||||
若该表还需运行期自愈,记得在对应 Schema 类里登记 ensureTable()。
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 表结构弹窗 -->
|
||||
<script type="text/html" id="structureTpl">
|
||||
<div style="padding:15px">
|
||||
<div class="layui-tab layui-tab-brief">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">字段</li>
|
||||
<li>建表语句</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content" style="padding:10px 0">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<table class="layui-table layui-table-sm" id="columnTable">
|
||||
<thead><tr>
|
||||
<th>字段</th><th>类型</th><th>可空</th><th>默认</th><th>键</th><th>额外</th><th>注释</th>
|
||||
</tr></thead>
|
||||
<tbody id="columnBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<textarea id="createSqlText" class="layui-textarea" rows="16" readonly></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['datatable'], function () {});
|
||||
</script>
|
||||
@@ -0,0 +1,90 @@
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">模板钩子(共 {$total} 个埋点)</div>
|
||||
<div class="layui-card-body">
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
模板里 <code>{:hook('钩子名', $vars)}</code> 是埋点;插件用
|
||||
<code>HookService::mount()</code> / <code>register()</code> 或监听
|
||||
<code>HookRender</code> 事件挂内容。本页只做诊断:埋点是否存在、挂了谁。
|
||||
<br>
|
||||
收集型事件监听:{if $hasListener}<span class="layui-badge layui-bg-green">已注册</span>{else}<span class="layui-badge">无</span>{/if}
|
||||
(事件方式无法枚举到具体插件,排查时优先看「已挂载」列)
|
||||
</blockquote>
|
||||
|
||||
<div style="margin-bottom:12px;">
|
||||
<button class="layui-btn layui-btn-sm {if $devOn}layui-btn-danger{else /}layui-btn-normal{/if}"
|
||||
id="btnDevMode" data-on="{if $devOn}0{else /}1{/if}">
|
||||
<i class="layui-icon layui-icon-template-1"></i>
|
||||
{if $devOn}关闭钩点标注{else /}开启钩点标注{/if}
|
||||
</button>
|
||||
<span class="layui-word-aux" style="margin-left:8px;">
|
||||
开启后打开任意后台页面:每个 hook() 埋点会显示蓝色虚线框 + 「⟡ 钩子名」标签(灰色「(空)」表示尚无插件挂载)。
|
||||
仅在本机浏览器生效(cookie),不会随前台页面暴露给访客。
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<table class="layui-table" lay-skin="line">
|
||||
<colgroup>
|
||||
<col width="240">
|
||||
<col width="240">
|
||||
<col>
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>钩子名</th>
|
||||
<th>已挂载</th>
|
||||
<th>埋点位置</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{empty name="rows"}
|
||||
<tr>
|
||||
<td colspan="3" style="text-align:center;">暂无埋点</td>
|
||||
</tr>
|
||||
{/empty}
|
||||
{volist name="rows" id="row"}
|
||||
<tr>
|
||||
<td><code>{$row.name}</code></td>
|
||||
<td>
|
||||
{empty name="row.mounts"}
|
||||
<span class="layui-badge">未挂载</span>
|
||||
{else /}
|
||||
{volist name="row.mounts" id="m"}
|
||||
<div style="margin-bottom:4px;">
|
||||
<span class="layui-badge layui-bg-cyan">{$m.addon ?: '核心'}</span>
|
||||
<span class="layui-badge layui-bg-gray">w{$m.weight}</span>
|
||||
<span style="font-size:12px;">{$m.target}</span>
|
||||
</div>
|
||||
{/volist}
|
||||
{/empty}
|
||||
</td>
|
||||
<td style="font-size:12px;color:#666;">
|
||||
{volist name="row.files" id="f"}
|
||||
<div>{$f}</div>
|
||||
{/volist}
|
||||
</td>
|
||||
</tr>
|
||||
{/volist}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
layui.use(['jquery', 'layer', 'http'], function () {
|
||||
var $ = layui.jquery, layer = layui.layer, http = layui.http;
|
||||
$('#btnDevMode').on('click', function () {
|
||||
var btn = $(this);
|
||||
http.post('{:url("devMode")}', { on: btn.data('on') }).then(function (r) {
|
||||
if (r && r.code === 0) {
|
||||
layer.msg(r.msg || '已切换', { icon: 1 });
|
||||
setTimeout(function () { location.reload(); }, 800);
|
||||
} else {
|
||||
layer.msg((r && r.msg) || '切换失败', { icon: 2 });
|
||||
}
|
||||
}).catch(function (err) {
|
||||
layer.msg('请求失败:' + (err && err.message ? err.message : '网络异常'), { icon: 2 });
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,23 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<script>
|
||||
/^http(s*):\/\//.test(location.href) || alert('请通过 localhost 访问');;
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<title>YwxApp</title>
|
||||
<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">
|
||||
|
||||
@@ -20,13 +20,15 @@
|
||||
</div>
|
||||
</div>
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<!-- 本页是独立页(不走 layout),必须自己引入 ywxapp.js 才能用集成的 http -->
|
||||
<script src="/assets/ywxapp/ywxapp.js" module="backend"></script>
|
||||
<script>
|
||||
layui.use(['form', 'jquery'], function () {
|
||||
var form = layui.form, $ = layui.jquery;
|
||||
layui.use(['form', 'jquery', 'ywxapp', 'http'], function () {
|
||||
var form = layui.form, $ = layui.jquery, http = layui.http;
|
||||
form.on('submit(searchBtn)', function (data) {
|
||||
$.get('/backend/other/search', { q: data.field.q }, function (res) {
|
||||
http.get('/backend/other/search', { q: data.field.q }).then(function (res) {
|
||||
var html = '';
|
||||
if (res.code === 0 && res.data && res.data.length) {
|
||||
if (res && 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>';
|
||||
});
|
||||
@@ -34,6 +36,8 @@
|
||||
html = '<tr><td colspan="3" style="text-align:center;color:#999;">无结果</td></tr>';
|
||||
}
|
||||
$('#resultBody').html(html);
|
||||
}).catch(function () {
|
||||
$('#resultBody').html('<tr><td colspan="3" style="text-align:center;color:#999;">请求失败</td></tr>');
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -54,10 +54,11 @@
|
||||
<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>
|
||||
<option value="5" {{ d.type == 5 ? 'selected' : '' }}>分组标题</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-item-url {{ d.type == 3 ? 'layui-hide' : '' }}" id="urlField">
|
||||
<div class="layui-form-item layui-form-item-url {{ (d.type == 3 || d.type == 5) ? '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">
|
||||
|
||||
@@ -46,9 +46,11 @@
|
||||
</div>
|
||||
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<!-- 本页是独立页(不走 layout),必须自己引入 ywxapp.js 才能用集成的 http -->
|
||||
<script src="/assets/ywxapp/ywxapp.js" module="backend"></script>
|
||||
<script>
|
||||
layui.use(['form', 'layer'], function () {
|
||||
var form = layui.form, layer = layui.layer, $ = layui.$;
|
||||
layui.use(['form', 'layer', 'ywxapp', 'http'], function () {
|
||||
var form = layui.form, layer = layui.layer, $ = layui.$, http = layui.http;
|
||||
|
||||
form.verify({
|
||||
pass: [/^[\S]{6,12}$/, '密码必须 6 到 12 位,且不能出现空格'],
|
||||
@@ -60,8 +62,8 @@
|
||||
});
|
||||
|
||||
form.on('submit(setmypass)', function (obj) {
|
||||
$.post('{:url("Profile/passwordSave")}', obj.field, function (res) {
|
||||
if (res.code === 1 || res.code === 0) {
|
||||
http.post('{:url("Profile/passwordSave")}', obj.field).then(function (res) {
|
||||
if (res && (res.code === 1 || res.code === 0)) {
|
||||
layer.msg(res.msg || '修改成功', { icon: 1 });
|
||||
setTimeout(function () {
|
||||
if (window !== top && parent.layui && parent.layui.ywxapp) {
|
||||
@@ -71,10 +73,10 @@
|
||||
}
|
||||
}, 800);
|
||||
} else {
|
||||
layer.msg(res.msg || '修改失败', { icon: 2 });
|
||||
layer.msg((res && res.msg) || '修改失败', { icon: 2 });
|
||||
}
|
||||
}, 'json').fail(function () {
|
||||
layer.msg('请求失败', { icon: 2 });
|
||||
}).catch(function (err) {
|
||||
layer.msg('请求失败:' + (err && err.message ? err.message : '网络异常'), { icon: 2 });
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -2,10 +2,22 @@
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">积分规则管理</div>
|
||||
<div class="layui-card-body">
|
||||
<blockquote class="layui-elem-quote layui-quote-nm">
|
||||
规则按「触发动作」命中:业务点或插件调用 <code>ScoreService::trigger('动作标识', $uid)</code> 时,
|
||||
本表所有启用规则按顺序执行。动作可下拉选择,也支持直接输入插件自定义动作。
|
||||
</blockquote>
|
||||
<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">
|
||||
<input type="text" name="title" placeholder="规则名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<select name="action">
|
||||
<option value="">全部动作</option>
|
||||
{volist name="actionList" id="vo" key="k"}
|
||||
<option value="{$k}">{$vo.title}{if condition="!empty($vo['addon'])"}(插件:{$vo.addon}){/if}</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>
|
||||
@@ -20,6 +32,7 @@
|
||||
<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>
|
||||
{:hook('backend.score.toolbar')}
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="dataBar">
|
||||
@@ -36,6 +49,13 @@
|
||||
<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="addonTpl">
|
||||
{{# if(!d.addon){ }}
|
||||
<span class="layui-badge layui-bg-blue">核心</span>
|
||||
{{# } else { }}
|
||||
<span class="layui-badge layui-bg-cyan">{{ d.addon }}</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -46,40 +66,84 @@
|
||||
<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">
|
||||
<input type="text" name="title" value="{{ d.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="action" placeholder="如 task_complete/signin/register" class="layui-input">
|
||||
<input type="text" name="action" value="{{ d.action || '' }}" list="action-list" placeholder="如 user.register / demo.checkin" class="layui-input">
|
||||
<datalist id="action-list"></datalist>
|
||||
<div class="layui-form-mid layui-word-aux">插件可用 ScoreService::registerAction() 注册自己的动作</div>
|
||||
</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="消费">
|
||||
<input type="radio" name="type" value="1" title="获取" {{ d.type == 2 ? '' : 'checked' }}>
|
||||
<input type="radio" name="type" value="2" title="消费" {{ d.type == 2 ? 'checked' : '' }}>
|
||||
</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">
|
||||
<input type="text" name="value" value="{{ d.value || '' }}" placeholder="请输入积分变动值(正数)" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">限次周期</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="limit_type">
|
||||
{volist name="limitTypeList" id="v" key="k"}
|
||||
<option value="{$k}" {{# if(d.limit_type == {$k}){ }}selected{{# } }}>{$v}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">限次次数</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="limit_times" value="{{ d.limit_times || 0 }}" placeholder="周期内最多触发次数,0=不限" class="layui-input">
|
||||
<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">
|
||||
<select name="unique_type">
|
||||
{volist name="uniqueTypeList" id="v" key="k"}
|
||||
<option value="{$k}" {{# if(d.unique_type == {$k}){ }}selected{{# } }}>{$v}</option>
|
||||
{/volist}
|
||||
</select>
|
||||
<div class="layui-form-mid layui-word-aux">按来源业务ID去重可防止回调重试导致重复发放</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">归属插件</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="addon" value="{{ d.addon || '' }}" 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="remark" value="{{ d.remark || '' }}" placeholder="如 完成任务:{title}" class="layui-input">
|
||||
<div class="layui-form-mid layui-word-aux">支持 {key} 占位,取 trigger() 传入的 context</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">
|
||||
<input type="text" name="sort" value="{{ d.sort || 0 }}" 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>
|
||||
<input type="checkbox" name="status" lay-skin="switch" lay-text="启用|禁用" value="1" {{ d.id ? (d.status == 1 ? 'checked' : '') : 'checked' }}>
|
||||
</div>
|
||||
</div>
|
||||
{:hook('backend.score.form')}
|
||||
</form>
|
||||
</script>
|
||||
|
||||
|
||||
@@ -7,6 +7,12 @@
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="uid" placeholder="用户ID" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="action" placeholder="触发动作" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="source" 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>
|
||||
@@ -41,6 +47,9 @@
|
||||
cols: [[
|
||||
{field: 'id', title: 'ID', width: 70},
|
||||
{field: 'uid', title: '用户ID', width: 90},
|
||||
{field: 'action', title: '触发动作', width: 150},
|
||||
{field: 'source', title: '来源', width: 100},
|
||||
{field: 'source_id', title: '来源业务ID', width: 120},
|
||||
{field: 'type_text', title: '类型', width: 90, templet: '#typeTpl'},
|
||||
{field: 'value', title: '变动值', width: 90},
|
||||
{field: 'balance', title: '余额', width: 90},
|
||||
@@ -60,7 +69,7 @@
|
||||
});
|
||||
|
||||
$('#btn-reset').on('click', function () {
|
||||
form.val('data-search-form', {uid: ''});
|
||||
form.val('data-search-form', {uid: '', action: '', source: ''});
|
||||
renderTable();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
<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>
|
||||
@@ -1,5 +1,10 @@
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">蜘蛛汇总(今日 / 近7日 / 近30日 / 总量)</div>
|
||||
<div class="layui-card-header">
|
||||
蜘蛛汇总(今日 / 近7日 / 近30日 / 总量 · 真伪拆分)
|
||||
<span style="float:right;font-weight:400;color:#999;font-size:12px;">
|
||||
真伪由 rDNS 双向验证(PTR 反查 + 官方域名 + A/AAAA 正查)判定
|
||||
</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table" id="summaryTable" lay-size="sm">
|
||||
<thead>
|
||||
@@ -9,13 +14,16 @@
|
||||
<th>近7日</th>
|
||||
<th>近30日</th>
|
||||
<th>总量</th>
|
||||
<th>真蜘蛛</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>
|
||||
<tr><td colspan="8" style="text-align:center;color:#999;">加载中…</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="dnsWarn" style="display:none;margin-top:8px;" class="layui-bg-orange"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -30,6 +38,14 @@
|
||||
<option value="">全部蜘蛛</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<select name="verified" id="verifiedSelect">
|
||||
<option value="">全部真伪</option>
|
||||
<option value="1">仅真蜘蛛</option>
|
||||
<option value="2">仅假蜘蛛</option>
|
||||
<option value="0">待验证</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="ip" placeholder="来源IP" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
@@ -56,6 +72,7 @@
|
||||
<!-- 顶部工具条 -->
|
||||
<script type="text/html" id="tableBar">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm layui-btn-normal" title="对历史「待验证」记录重新做 rDNS 校验" lay-event="dataRecheck"><i class="layui-icon layui-icon-refresh-3"></i> 重新校验真伪</a>
|
||||
<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>
|
||||
|
||||
@@ -47,12 +47,14 @@
|
||||
<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;
|
||||
layui.use(['table', 'form', 'layer', 'upload', 'jquery', 'http'], function () {
|
||||
var table = layui.table, form = layui.form, layer = layui.layer, upload = layui.upload
|
||||
, $ = layui.jquery, http = layui.http;
|
||||
var state = { installed: [], addon: [], active_map: {} };
|
||||
|
||||
// 统一走集成的 http(/assets/ywxapp/ywxapp.js 提供),不再用 $.ajax
|
||||
function api(url, data) {
|
||||
return $.ajax({ url: url, type: 'POST', data: data || {}, dataType: 'json' });
|
||||
return http.post(url, data || {});
|
||||
}
|
||||
|
||||
function load() {
|
||||
|
||||
@@ -26,38 +26,228 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card" style="margin:15px;">
|
||||
<div class="layui-card-header">
|
||||
站点 layui 配色
|
||||
<span class="layui-word-aux" style="margin-left:8px;">全站生效:后台 / 会员中心 / 前台 / 所有插件前台</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md7">
|
||||
<form class="layui-form" id="themeForm">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">启用主题</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="checkbox" id="themeEnable" lay-skin="switch" lay-text="开|关">
|
||||
</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:90px;">
|
||||
<input type="color" id="primaryColor" class="layui-input" style="padding:2px;height:36px;">
|
||||
</div>
|
||||
<div class="layui-input-inline" style="width:150px;">
|
||||
<input type="text" id="primaryText" class="layui-input" placeholder="#16b777">
|
||||
</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:90px;">
|
||||
<input type="color" id="accentColor" class="layui-input" style="padding:2px;height:36px;">
|
||||
</div>
|
||||
<div class="layui-input-inline" style="width:150px;">
|
||||
<input type="text" id="accentText" class="layui-input" placeholder="#16baaa">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">按钮、导航、分页当前页、上传、Logo</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">圆角</label>
|
||||
<div class="layui-input-inline" style="width:150px;">
|
||||
<select id="radiusInput">
|
||||
<option value="0">直角 0</option>
|
||||
<option value="2px">默认 2px</option>
|
||||
<option value="4px">4px</option>
|
||||
<option value="6px">6px</option>
|
||||
<option value="10px">10px</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-block" style="margin-right:15px;">
|
||||
<input type="text" id="fontInput" class="layui-input" placeholder="-apple-system, 'Microsoft YaHei', sans-serif">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="saveTheme">保存配色</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="resetTheme">恢复默认</button>
|
||||
<span class="layui-word-aux">保存后立即全站生效,无需清缓存</span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="layui-col-md5">
|
||||
<fieldset class="layui-elem-field layui-field-title" style="margin-top:0;">
|
||||
<legend style="font-size:14px;">实时预览</legend>
|
||||
</fieldset>
|
||||
<div id="themePreview" style="padding:12px;border:1px dashed #e2e2e2;border-radius:4px;">
|
||||
<button type="button" class="layui-btn">主按钮</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary">次按钮</button>
|
||||
<div style="margin-top:10px;">
|
||||
<span class="layui-form-checkbox layui-form-checked"><i class="layui-icon layui-icon-ok"></i>已选中</span>
|
||||
<span class="layui-form-onswitch" style="margin-left:10px;"><em></em><i></i></span>
|
||||
</div>
|
||||
<div class="layui-progress" style="margin-top:12px;">
|
||||
<div class="layui-progress-bar" style="width:60%;"></div>
|
||||
</div>
|
||||
<div style="margin-top:12px;">
|
||||
<ul class="layui-nav" style="background:none;padding:0;">
|
||||
<li class="layui-nav-item layui-this"><a href="javascript:;" style="color:#333;">选中项</a></li>
|
||||
<li class="layui-nav-item"><a href="javascript:;" style="color:#666;">普通项</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="layui-box layui-laypage layui-laypage-default" style="margin-top:12px;">
|
||||
<span class="layui-laypage-curr"><em class="layui-laypage-em"></em><em>1</em></span>
|
||||
<a href="javascript:;">2</a><a href="javascript:;">3</a>
|
||||
</div>
|
||||
<blockquote class="layui-elem-quote" style="margin-top:12px;">引用区块:主色左边框</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-alert layui-alert-warn" id="menuTip" style="display:none;margin-top:10px;">
|
||||
后台菜单中缺少「界面」入口,
|
||||
<a href="javascript:;" id="syncMenu" style="color:#01AAED;">点此补建</a>
|
||||
(幂等,可重复执行)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
layui.use(['form', 'layer', 'jquery'], function () {
|
||||
var form = layui.form, layer = layui.layer, $ = layui.jquery;
|
||||
layui.use(['form', 'layer', 'jquery', 'http'], function () {
|
||||
var form = layui.form, layer = layui.layer, $ = layui.jquery, http = layui.http;
|
||||
|
||||
// 拉取已安装模板填充下拉 + 当前设置
|
||||
$.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');
|
||||
}
|
||||
http.post('index', {}).then(function (res) {
|
||||
if (!res || 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');
|
||||
}).catch(function () {
|
||||
layer.msg('加载失败', { icon: 2 });
|
||||
});
|
||||
|
||||
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 }); }
|
||||
});
|
||||
http.post('setting', data.field).then(function (res) {
|
||||
if (res && res.code === 0) { layer.msg('已保存', { icon: 1 }); }
|
||||
else { layer.msg((res && res.message) || '保存失败', { icon: 2 }); }
|
||||
}).catch(function () { layer.msg('请求失败', { icon: 2 }); });
|
||||
return false;
|
||||
});
|
||||
|
||||
/* ===== 站点 layui 配色:实时预览 + 保存 ===== */
|
||||
var THEME_DEFAULT = {
|
||||
primary: '#16b777',
|
||||
accent: '#16baaa',
|
||||
radius: '2px',
|
||||
font: "-apple-system, BlinkMacSystemFont, 'Microsoft YaHei', 'PingFang SC', sans-serif"
|
||||
};
|
||||
|
||||
// 预览只写预览容器自身的 CSS 变量,不动全局即可看到效果
|
||||
function applyPreview() {
|
||||
var el = document.getElementById('themePreview');
|
||||
var pick = function (id, key) {
|
||||
var v = (document.getElementById(id).value || '').replace(/^\s+|\s+$/g, '');
|
||||
return v === '' ? THEME_DEFAULT[key] : v;
|
||||
};
|
||||
el.style.setProperty('--ywx-primary', pick('primaryText', 'primary'));
|
||||
el.style.setProperty('--ywx-accent', pick('accentText', 'accent'));
|
||||
el.style.setProperty('--ywx-radius', pick('radiusInput', 'radius'));
|
||||
el.style.setProperty('--ywx-font', pick('fontInput', 'font'));
|
||||
}
|
||||
|
||||
// 色板 <-> 文本框 双向绑定
|
||||
function bindColor(colorId, textId) {
|
||||
$('#' + colorId).on('input change', function () {
|
||||
$('#' + textId).val(this.value);
|
||||
applyPreview();
|
||||
});
|
||||
$('#' + textId).on('input', function () {
|
||||
var v = (this.value || '').replace(/^\s+|\s+$/g, '');
|
||||
if (/^#[0-9a-fA-F]{6}$/.test(v)) { $('#' + colorId).val(v); }
|
||||
applyPreview();
|
||||
});
|
||||
}
|
||||
bindColor('primaryColor', 'primaryText');
|
||||
bindColor('accentColor', 'accentText');
|
||||
$('#radiusInput,#fontInput').on('input change', applyPreview);
|
||||
|
||||
// 载入当前配置
|
||||
http.get('siteTheme').then(function (res) {
|
||||
if (!res || res.code !== 0) { return; }
|
||||
var v = res.data.vars || {};
|
||||
$('#primaryText').val(v.primary || '');
|
||||
$('#primaryColor').val(v.primary || THEME_DEFAULT.primary);
|
||||
$('#accentText').val(v.accent || '');
|
||||
$('#accentColor').val(v.accent || THEME_DEFAULT.accent);
|
||||
$('#radiusInput').val(v.radius || THEME_DEFAULT.radius);
|
||||
$('#fontInput').val(v.font || '');
|
||||
$('#themeEnable').prop('checked', !!res.data.enable);
|
||||
if (!res.data.menu_ok) { $('#menuTip').show(); }
|
||||
form.render('select');
|
||||
form.render('checkbox');
|
||||
applyPreview();
|
||||
}).catch(function () {
|
||||
layer.msg('主题配置加载失败', { icon: 2 });
|
||||
});
|
||||
|
||||
// 保存
|
||||
form.on('submit(saveTheme)', function () {
|
||||
var data = {
|
||||
primary: $('#primaryText').val(),
|
||||
accent: $('#accentText').val(),
|
||||
radius: $('#radiusInput').val(),
|
||||
font: $('#fontInput').val(),
|
||||
enable: $('#themeEnable').prop('checked') ? 1 : 0
|
||||
};
|
||||
http.post('siteTheme', { vars: data }).then(function (res) {
|
||||
if (res && res.code === 0) { layer.msg('已保存,全站生效', { icon: 1 }); }
|
||||
else { layer.msg((res && res.message) || '保存失败', { icon: 2 }); }
|
||||
}).catch(function () { layer.msg('请求失败', { icon: 2 }); });
|
||||
return false;
|
||||
});
|
||||
|
||||
// 恢复默认(清空提交,服务端自动回落默认值)
|
||||
$('#resetTheme').on('click', function () {
|
||||
$('#primaryText,#accentText,#fontInput').val('');
|
||||
$('#radiusInput').val(THEME_DEFAULT.radius);
|
||||
$('#primaryColor').val(THEME_DEFAULT.primary);
|
||||
$('#accentColor').val(THEME_DEFAULT.accent);
|
||||
$('#themeEnable').prop('checked', true);
|
||||
form.render('select');
|
||||
form.render('checkbox');
|
||||
applyPreview();
|
||||
layer.msg('已恢复默认配色,点「保存配色」生效', { icon: 3 });
|
||||
});
|
||||
|
||||
// 补建菜单入口(幂等)
|
||||
$('#syncMenu').on('click', function () {
|
||||
http.post('syncMenu', {}).then(function (res) {
|
||||
layer.msg((res && res.message) || '已同步', { icon: (res && res.code === 0) ? 1 : 2 });
|
||||
if (res && res.code === 0) { $('#menuTip').hide(); }
|
||||
}).catch(function () { layer.msg('请求失败', { icon: 2 }); });
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -25,8 +25,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
layui.use(['jquery', 'layer'], function () {
|
||||
var $ = layui.jquery, layer = layui.layer;
|
||||
layui.use(['jquery', 'layer', 'http'], function () {
|
||||
var $ = layui.jquery, layer = layui.layer, http = layui.http;
|
||||
var selectedType = 'auto';
|
||||
|
||||
function setDisabled($el, dis) {
|
||||
@@ -46,8 +46,8 @@ layui.use(['jquery', 'layer'], function () {
|
||||
|
||||
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) {
|
||||
http.get('{:url("framework/check")}', {}, {timeout: 15000}).then(function (res) {
|
||||
if (res && res.code === 0) {
|
||||
var d = res.data;
|
||||
if (d.has_update) {
|
||||
var autoMode = d.use_patch ? '增量补丁' : '整包';
|
||||
@@ -85,8 +85,11 @@ layui.use(['jquery', 'layer'], function () {
|
||||
$('#pkgTypeBox').hide();
|
||||
}
|
||||
} else {
|
||||
$('#status').html('<span style="color:#dc2626;">' + (res.message || '检查失败') + '</span>');
|
||||
$('#status').html('<span style="color:#dc2626;">' + ((res && res.message) || '检查失败') + '</span>');
|
||||
}
|
||||
}).catch(function (err) {
|
||||
$('#status').html('<span style="color:#dc2626;">请求失败:'
|
||||
+ (err && err.message ? err.message : '网络异常') + '</span>');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -96,14 +99,18 @@ layui.use(['jquery', 'layer'], 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) {
|
||||
// 下载 + 备份 + 覆盖可能很久,放宽到 10 分钟
|
||||
http.post('{:url("framework/upgrade")}', {type: selectedType}, {timeout: 600000}).then(function (res) {
|
||||
if (res && 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>');
|
||||
$('#status').html('<span style="color:#dc2626;">' + ((res && res.message) || '升级失败') + '</span>');
|
||||
}
|
||||
}).catch(function (err) {
|
||||
$('#status').html('<span style="color:#dc2626;">请求失败:'
|
||||
+ (err && err.message ? err.message : '网络异常') + '</span>');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user