安全(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(市场 / 开发者中心 / 审核 / 分润)
303 lines
13 KiB
HTML
303 lines
13 KiB
HTML
<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>
|
||
</div>
|
||
<div class="layui-card-body layuiadmin-card-list">
|
||
<p class="layuiadmin-big-font">{$stats.total.member}</p>
|
||
<p>
|
||
近 7 天新增
|
||
<span class="layuiadmin-span-color">{$stats.total.member_week} 人 <i class="layui-inline layui-icon layui-icon-user"></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">{$stats.today.member}</p>
|
||
<p>
|
||
会员表实时统计
|
||
<span class="layuiadmin-span-color">今日 <i class="layui-inline layui-icon layui-icon-friends"></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">{$stats.today.log}</p>
|
||
<p>
|
||
后台操作记录
|
||
<span class="layuiadmin-span-color">累计 {$stats.total.log} <i class="layui-inline layui-icon layui-icon-log"></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">{$stats.today.spider}</p>
|
||
<p>
|
||
搜索引擎抓取
|
||
<span class="layuiadmin-span-color">累计 {$stats.total.spider} <i class="layui-inline layui-icon layui-icon-chart-screen"></i></span>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="layui-col-sm12">
|
||
<div class="layui-card">
|
||
<div class="layui-card-header">
|
||
近 7 天趋势
|
||
<span class="layui-badge layui-bg-blue layuiadmin-badge">会员注册 / 后台操作</span>
|
||
</div>
|
||
<div class="layui-card-body">
|
||
<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-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>
|
||
</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-sm6">
|
||
<div class="layui-row layui-col-space15">
|
||
<div class="layui-col-sm12">
|
||
<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>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>{$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>
|
||
</div>
|
||
|
||
</div>
|
||
</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');
|
||
</script>
|