chore: 重写初始提交(清空历史,整理后全量提交)
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{$title | default='数据概览'}</title>
|
||||
<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>
|
||||
body { padding: 16px; background: #f5f6fa; }
|
||||
.stat-cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 16px; }
|
||||
.stat-card { background: #fff; border-radius: 8px; padding: 16px; box-shadow: 0 1px 6px rgba(0,0,0,.06); }
|
||||
.stat-card .num { font-size: 26px; font-weight: 700; color: #1E9FFF; }
|
||||
.stat-card .lbl { color: #666; font-size: 13px; margin-top: 4px; }
|
||||
.panel { background: #fff; border-radius: 8px; padding: 16px; margin-bottom: 16px; box-shadow: 0 1px 6px rgba(0,0,0,.06); }
|
||||
.panel h3 { font-size: 15px; margin-bottom: 12px; border-left: 3px solid #1E9FFF; padding-left: 8px; }
|
||||
.bar-row { display: flex; align-items: center; margin-bottom: 8px; }
|
||||
.bar-row .name { width: 120px; color: #333; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.bar-row .bar { flex: 1; background: #eef1f6; border-radius: 4px; height: 16px; margin: 0 8px; overflow: hidden; }
|
||||
.bar-row .bar > i { display: block; height: 100%; background: linear-gradient(90deg,#1E9FFF,#5FB878); }
|
||||
.bar-row .val { width: 60px; text-align: right; color: #999; font-size: 12px; }
|
||||
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
||||
@media (max-width: 900px) { .stat-cards { grid-template-columns: repeat(2,1fr); } .grid2 { grid-template-columns: 1fr; } }
|
||||
.heat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px,1fr)); gap: 8px; }
|
||||
.heat-cell { border-radius: 6px; padding: 10px 12px; color: #333; min-height: 54px; box-shadow: 0 1px 3px rgba(0,0,0,.06); line-height: 1.5; }
|
||||
.heat-cell b { font-size: 18px; }
|
||||
.heat-table { border-collapse: collapse; width: 100%; }
|
||||
.heat-table th { font-size: 11px; color: #999; font-weight: normal; padding: 2px 1px; }
|
||||
.heat-table td { height: 16px; border-radius: 2px; }
|
||||
.hh { width: 14px; }
|
||||
.dh { text-align: right; padding-right: 6px; white-space: nowrap; }
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="stat-cards" id="statCards"></div>
|
||||
<div class="grid2">
|
||||
<div class="panel">
|
||||
<h3>Top 分类(按链接数)</h3>
|
||||
<div id="topCategories"></div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<h3>热门点击 Top10</h3>
|
||||
<table class="layui-table" lay-size="sm">
|
||||
<thead><tr><th>网站</th><th style="width:90px">点击</th></tr></thead>
|
||||
<tbody id="topClicks"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<h3>点击热力图 · 星期×小时 <span id="timeMeta" style="font-weight:normal;color:#999;font-size:12px;"></span></h3>
|
||||
<div id="timeHeat"></div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<h3>分类点击热度</h3>
|
||||
<div id="categoryHeat" class="heat-grid"></div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<h3>死链概览 <span id="deadMeta" style="font-weight:normal;color:#999;font-size:12px;"></span></h3>
|
||||
<table class="layui-table" lay-size="sm">
|
||||
<thead><tr><th>网站</th><th style="width:280px">网址</th><th style="width:90px">状态码</th><th style="width:140px">最近检测</th></tr></thead>
|
||||
<tbody id="deadList"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script src="/assets/layui/layui.js"></script>
|
||||
<script src="/assets/ywxapp/ywxapp.js" module="backend"></script>
|
||||
<script>
|
||||
function esc(s){ return String(s==null?'':s).replace(/[&<>"']/g,function(c){return {'&':'&','<':'<','>':'>','"':'"',"'":'''}[c];}); }
|
||||
// 点击密度 -> 颜色(浅米黄=低,深红=高)
|
||||
function heatColor(ratio){
|
||||
ratio = Math.max(0, Math.min(1, ratio));
|
||||
var r = 255, g = Math.round(245 - 200*ratio), b = Math.round(230 - 210*ratio);
|
||||
return 'rgb('+r+','+g+','+b+')';
|
||||
}
|
||||
layui.use(['http'], function () {
|
||||
var http = layui.http;
|
||||
http.get('index').then(function (res) {
|
||||
var d = (res && res.data) || {};
|
||||
renderCards(d.summary || {});
|
||||
renderCategories(d.topCategories || []);
|
||||
renderClicks(d.topClicks || []);
|
||||
renderDead(d.dead || {});
|
||||
if (d.heatmap) {
|
||||
renderTimeHeat(d.heatmap.time || [], d.heatmap.timeRange || '', d.heatmap.timeTotal || 0);
|
||||
renderCategoryHeat(d.heatmap.category || []);
|
||||
}
|
||||
});
|
||||
});
|
||||
function renderCards(s){
|
||||
var cards = [
|
||||
['链接总数', s.links], ['已上架', s.online], ['待审核', s.pending], ['已禁用', s.disabled],
|
||||
['分类数', s.categories], ['热门', s.hot], ['推荐', s.recommend], ['总点击', s.clicks]
|
||||
];
|
||||
document.getElementById('statCards').innerHTML = cards.map(function(c){
|
||||
return '<div class="stat-card"><div class="num">'+(c[1]||0)+'</div><div class="lbl">'+c[0]+'</div></div>';
|
||||
}).join('');
|
||||
}
|
||||
function renderCategories(list){
|
||||
var max = 1; list.forEach(function(c){ if(c.count>max) max=c.count; });
|
||||
document.getElementById('topCategories').innerHTML = list.map(function(c){
|
||||
var pct = Math.round(c.count/max*100);
|
||||
return '<div class="bar-row"><span class="name">'+(c.icon||'')+' '+esc(c.title)+'</span>'+
|
||||
'<span class="bar"><i style="width:'+pct+'%"></i></span><span class="val">'+c.count+'</span></div>';
|
||||
}).join('') || '<p style="color:#999">暂无数据</p>';
|
||||
}
|
||||
function renderClicks(list){
|
||||
document.getElementById('topClicks').innerHTML = list.map(function(it){
|
||||
return '<tr><td><a href="'+esc(it.url)+'" target="_blank">'+esc(it.title)+'</a></td><td>'+(it.click_count||0)+'</td></tr>';
|
||||
}).join('') || '<tr><td colspan="2" style="color:#999">暂无数据</td></tr>';
|
||||
}
|
||||
function renderTimeHeat(heat, meta, total){
|
||||
var days = ['周日','周一','周二','周三','周四','周五','周六'];
|
||||
var max = 1;
|
||||
for (var d = 0; d < 7; d++) { for (var h = 0; h < 24; h++) { var v = (heat[d] && heat[d][h]) || 0; if (v > max) max = v; } }
|
||||
document.getElementById('timeMeta').textContent = '(' + meta + ',共 ' + total + ' 次点击)';
|
||||
if (!heat.length) { document.getElementById('timeHeat').innerHTML = '<p style="color:#999">暂无点击数据(需先有访客点击跳转)</p>'; return; }
|
||||
var html = '<table class="heat-table"><thead><tr><th></th>';
|
||||
for (var h = 0; h < 24; h++) { html += '<th class="hh">' + (h % 24) + '</th>'; }
|
||||
html += '</tr></thead><tbody>';
|
||||
for (var d = 0; d < 7; d++) {
|
||||
html += '<tr><th class="dh">' + days[d] + '</th>';
|
||||
for (var h = 0; h < 24; h++) {
|
||||
var v = (heat[d] && heat[d][h]) || 0;
|
||||
var ratio = v / max;
|
||||
html += '<td style="background:' + heatColor(ratio) + '" title="' + days[d] + ' ' + h + ':00 点击 ' + v + ' 次"></td>';
|
||||
}
|
||||
html += '</tr>';
|
||||
}
|
||||
html += '</tbody></table>';
|
||||
document.getElementById('timeHeat').innerHTML = html;
|
||||
}
|
||||
function renderCategoryHeat(list){
|
||||
if (!list || !list.length) { document.getElementById('categoryHeat').innerHTML = '<p style="color:#999">暂无数据</p>'; return; }
|
||||
var max = 1; list.forEach(function(c){ if (c.clicks > max) max = c.clicks; });
|
||||
document.getElementById('categoryHeat').innerHTML = list.map(function(c){
|
||||
var ratio = c.clicks / max;
|
||||
var txt = ratio > 0.55 ? '#fff' : '#333';
|
||||
return '<div class="heat-cell" style="background:' + heatColor(ratio) + ';color:' + txt + '" title="' + esc(c.title) + ':' + (c.clicks || 0) + ' 次">' +
|
||||
(c.icon ? c.icon + ' ' : '') + esc(c.title) + '<br><b>' + (c.clicks || 0) + '</b></div>';
|
||||
}).join('');
|
||||
}
|
||||
function renderDead(d){
|
||||
document.getElementById('deadMeta').textContent = d.last_check_at ? ('(共 '+ (d.count||0) +' 条,最近检测 '+d.last_check_at+')') : '(尚未执行死链检测)';
|
||||
var list = d.list || [];
|
||||
document.getElementById('deadList').innerHTML = list.map(function(it){
|
||||
var t = it.last_check_at ? new Date(it.last_check_at*1000).toLocaleString() : '-';
|
||||
return '<tr><td>'+esc(it.title)+'</td><td style="word-break:break-all">'+esc(it.url)+'</td><td>'+(it.status_code===0?'无法访问':it.status_code)+'</td><td>'+t+'</td></tr>';
|
||||
}).join('') || '<tr><td colspan="4" style="color:#999">无死链或尚未检测</td></tr>';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user