feat: initial commit

This commit is contained in:
root
2026-06-14 14:00:24 +08:00
commit 72d388f642
118 changed files with 39015 additions and 0 deletions
Executable
+477
View File
@@ -0,0 +1,477 @@
<?php
require_once("cong.php");
session_start();
if(empty($_SESSION['password']) || $_SESSION['password'] != LOGIN_PASSWORD) {
unset($_SESSION['password']);
unset($_SESSION['check_result']);
echo("<script language=javascript>alert('密码错误!');window.location='ip_check_edit.php'; </script>");
//die("输入的密码不正确,请重新输入。");
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>访问判断日志</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="//cdn.staticfile.org/layui/2.9.2/css/layui.css" rel="stylesheet">
<style>
:root {
--log-primary: #16baaa;
--log-primary-dark: #0e8d81;
--log-bg: #f0f2f5;
--log-card: #ffffff;
--log-border: #e8ecf1;
--log-header-bg: #f4f7fb;
--log-text: #2c3e50;
--log-muted: #8c98a4;
}
* { box-sizing: border-box; }
body {
margin: 0;
background: var(--log-bg);
color: var(--log-text);
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
}
.log-page {
max-width: 1680px;
margin: 0 auto;
padding: 24px 28px 40px;
}
.log-page-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
flex-wrap: wrap;
gap: 12px;
}
.log-page-header h1 {
margin: 0;
font-size: 1.35rem;
font-weight: 600;
color: var(--log-text);
}
.log-page-header p {
margin: 4px 0 0;
font-size: .85rem;
color: var(--log-muted);
}
.log-card {
background: var(--log-card);
border: 1px solid var(--log-border);
border-radius: 10px;
box-shadow: 0 2px 12px rgba(15, 23, 42, .04);
margin-bottom: 16px;
overflow: hidden;
}
.log-card-body { padding: 18px 20px; }
.log-filter-grid .layui-col-md3 { margin-bottom: 12px; }
.log-filter-grid .layui-input,
.log-filter-grid .layui-select-title input {
border-radius: 6px;
border-color: var(--log-border);
}
.log-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
padding: 14px 20px;
border-top: 1px solid var(--log-border);
background: #fafbfc;
}
.log-actions .layui-btn { border-radius: 6px; }
.log-actions .layui-btn-primary { background: #fff; }
.log-count {
margin-left: auto;
font-size: .88rem;
color: var(--log-muted);
}
.log-count strong {
color: var(--log-primary-dark);
font-size: 1rem;
margin: 0 4px;
}
#btn-clear { background: #e74c3c !important; border-color: #e74c3c !important; }
.log-table-wrap { padding: 0; }
.log-table-wrap .layui-table-view {
border: none;
border-radius: 0 0 10px 10px;
margin: 0;
}
/* Sticky header */
.log-table-wrap .layui-table-header {
position: sticky;
top: 0;
z-index: 20;
border-radius: 0;
}
.log-table-wrap .layui-table-header .layui-table {
background: linear-gradient(180deg, #eef3f9 0%, #e4ebf5 100%);
}
.log-table-wrap .layui-table-header th {
color: #3d5167 !important;
font-weight: 600 !important;
font-size: 12.5px;
border-color: #d8e0ea !important;
padding: 11px 10px !important;
}
/* Zebra + hover */
.log-table-wrap .layui-table-body tr:nth-child(even) td {
background-color: #fafbfc;
}
.log-table-wrap .layui-table-body tr:hover td {
background-color: #eef6ff !important;
}
.log-table-wrap .layui-table-body td {
border-color: #eef1f5 !important;
padding: 9px 10px !important;
font-size: 12.5px;
line-height: 1.45;
transition: background-color .15s ease;
}
.log-table-wrap .layui-table-page {
border-top: 1px solid var(--log-border);
padding: 12px 16px;
background: #fafbfc;
}
/* Badges */
.cloak-badge {
display: inline-block;
padding: 2px 9px;
border-radius: 999px;
font-size: 11.5px;
font-weight: 600;
line-height: 1.5;
white-space: nowrap;
letter-spacing: .02em;
}
.badge-success { background: #d4edda; color: #155724; }
.badge-error { background: #f8d7da; color: #721c24; }
.badge-warning { background: #fff3cd; color: #856404; }
.badge-info { background: #d1ecf1; color: #0c5460; }
.badge-muted { background: #e9ecef; color: #495057; }
.reason-badge {
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
}
/* Truncation + mono timestamp */
.cell-ellipsis {
display: block;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: default;
}
.cell-mono {
font-family: 'SF Mono', 'Consolas', 'Monaco', monospace;
font-size: 12px;
color: #4a5568;
letter-spacing: -.02em;
}
.cell-ip { font-family: 'SF Mono', 'Consolas', monospace; font-size: 12px; }
.text-muted { color: #adb5bd; }
@media (max-width: 768px) {
.log-page { padding: 16px 12px 32px; }
.log-count { margin-left: 0; width: 100%; }
}
</style>
</head>
<body>
<div class="log-page">
<div class="log-page-header">
<div>
<h1>访问判断日志</h1>
<p>访客判定记录 · 支持筛选、导出与分页浏览</p>
</div>
<div class="log-nav" style="display:flex;gap:8px;">
<a href="table.php" style="display:inline-block;padding:6px 14px;border-radius:6px;font-size:.85rem;text-decoration:none;border:1px solid #e8ecf1;background:#16baaa;color:#fff;">访问日志</a>
<a href="log_analytics.php" style="display:inline-block;padding:6px 14px;border-radius:6px;font-size:.85rem;text-decoration:none;border:1px solid #e8ecf1;background:#fff;color:#2c3e50;">数据分析</a>
</div>
</div>
<div class="log-card">
<div class="log-card-body">
<form class="layui-form layui-row layui-col-space16 log-filter-grid">
<div class="layui-col-md3">
<div class="layui-input-wrap">
<div class="layui-input-prefix">
<i class="layui-icon layui-icon-username"></i>
</div>
<input type="text" name="domain" value="" placeholder="域名" class="layui-input" lay-affix="clear">
</div>
</div>
<div class="layui-col-md3">
<div class="layui-input-wrap">
<input type="text" name="spage" value="" placeholder="访问页面,可输入配置名称搜索" class="layui-input" lay-affix="clear">
</div>
</div>
<div class="layui-col-md3">
<div class="layui-input-wrap">
<select name="result">
<option value="">全部(不含检测中)</option>
<option value="true">TRUE(通过访问)</option>
<option value="false">FALSE(禁止访问)</option>
<option value="wait">检测中</option>
</select>
</div>
</div>
<div class="layui-col-md3">
<div class="layui-input-wrap">
<input type="text" name="country" placeholder="国家" lay-affix="clear" class="layui-input">
</div>
</div>
<div class="layui-col-md3">
<div class="layui-input-wrap">
<input type="text" name="IP" placeholder="IP" lay-affix="clear" class="layui-input">
</div>
</div>
<div class="layui-col-md3">
<div class="layui-input-wrap">
<div class="layui-input-prefix">
<i class="layui-icon layui-icon-date"></i>
</div>
<input type="text" name="visit_date" readonly placeholder="访问日期" class="layui-input demo-table-search-date">
</div>
</div>
<div class="layui-btn-container layui-col-xs12">
<a class="layui-btn" lay-submit href="javascript:void(0);" id="export" target="_blank">导出</a>
<button class="layui-btn" lay-submit lay-filter="demo-table-search">搜索</button>
<button type="reset" class="layui-btn layui-btn-primary">清除条件</button>
</div>
</form>
</div>
<div class="log-actions">
<button class="layui-btn layui-btn-sm" id="btn-refresh" onclick="resetTable()" lay-event="footerDemoBtn1">刷新</button>
<button class="layui-btn layui-btn-sm layui-btn-normal" id="btn-show-more" type="button">显示更多</button>
<button class="layui-btn layui-btn-sm btn-danger" id="btn-clear" lay-on="confirm" lay-event="footerDemoBtn2">清空数据库</button>
<span class="log-count">当前查询数量:<strong id="total_nums">—</strong></span>
</div>
</div>
<div class="log-card log-table-wrap">
<div id="demo-laypage-all"></div>
<table class="layui-hide" id="ID-table-demo-search" lay-filter="test"></table>
</div>
</div>
<script src="/dist/layui.js"></script>
<script src="/dist/jquery.min.js"></script>
<script>
layui.use(function(){
var table = layui.table;
var form = layui.form;
var laydate = layui.laydate;
var showMoreCols = false;
function escapeHtml(s) {
if (s == null || s === '') return '';
return String(s)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
}
function cellEllipsis(value, maxLen) {
var text = value == null ? '' : String(value);
if (!text) return '<span class="text-muted">—</span>';
var esc = escapeHtml(text);
var display = text.length > maxLen ? escapeHtml(text.slice(0, maxLen)) + '…' : esc;
return '<span class="cell-ellipsis" title="' + esc + '">' + display + '</span>';
}
function badgeResult(val) {
var raw = val == null ? '' : String(val);
var v = raw.toLowerCase();
if (v === 'true' || v === '1') {
return '<span class="cloak-badge badge-success">TRUE</span>';
}
if (v === 'false' || v === '0') {
return '<span class="cloak-badge badge-error">FALSE</span>';
}
if (v === 'wait' || raw.indexOf('检测') !== -1) {
return '<span class="cloak-badge badge-info">检测中</span>';
}
return '<span class="cloak-badge badge-muted">' + escapeHtml(raw) + '</span>';
}
function badgeReason(reason) {
if (reason == null || reason === '') {
return '<span class="text-muted">—</span>';
}
var text = String(reason);
var cls = 'badge-info';
if (text.indexOf('未确定流量来源') !== -1) {
cls = 'badge-warning';
} else if (/过滤|黑名单|无效|代理|VPN|禁止|欺骗|无来源/i.test(text)) {
cls = 'badge-error';
} else if (/白名单|允许|通过/i.test(text)) {
cls = 'badge-success';
}
var esc = escapeHtml(text);
var short = text.length > 26 ? escapeHtml(text.slice(0, 26)) + '…' : esc;
return '<span class="cloak-badge ' + cls + ' reason-badge" title="' + esc + '">' + short + '</span>';
}
function buildCols(showMore) {
return [[
{field:'id', title: 'ID', width:56, fixed: true},
{field:'domain', title: '域名', width:120, templet: function(d){ return cellEllipsis(d.domain, 18); }},
{field:'visit_date', title: '访问日期', width:130, templet: function(d){
return '<span class="cell-mono" title="' + escapeHtml(d.visit_date) + '">' + escapeHtml(d.visit_date) + '</span>';
}},
{field:'country', title: '国家', width:100, templet: function(d){ return cellEllipsis(d.country, 12); }},
{field:'result', title: '是否正常', width:88, templet: function(d){ return badgeResult(d.result); }},
{field:'reason', title: '理由', width:140, templet: function(d){ return badgeReason(d.reason); }},
{field:'judge_timing_text', title: '判断用时', width:240, templet: function(d){ return cellEllipsis(d.judge_timing_text, 36); }},
{field:'vtimes', title: '第几次访问', width:96},
{field:'fp_url', title: '跳转至', width:180, templet: function(d){ return cellEllipsis(d.fp_url, 28); }},
{field:'device', title: '访问设备', width:200, templet: function(d){ return cellEllipsis(d.device, 32); }},
{field:'referer', title: '来源', width:200, templet: function(d){ return cellEllipsis(d.referer, 32); }},
{field:'IP', title: 'IP(支持IPV6)', width:130, templet: function(d){
return '<span class="cell-ip" title="' + escapeHtml(d.IP) + '">' + escapeHtml(d.IP) + '</span>';
}},
{field:'client', title: '客户端', width:80, templet: function(d){ return cellEllipsis(d.client, 10); }},
{field:'language', title: '语言', width:80, templet: function(d){ return cellEllipsis(d.language, 10); }},
{field:'browser', title: '浏览器', width:88, templet: function(d){ return cellEllipsis(d.browser, 10); }},
{field:'page', title: '访问页面', width:200, templet: function(d){ return cellEllipsis(d.page, 32); }},
{field:'campagin_id', title: '广告策略', width:88, templet: function(d){ return cellEllipsis(d.campagin_id, 10); }},
{field:'user_agent', title: 'User-Agent', width:320, hide: !showMore, templet: function(d){ return cellEllipsis(d.user_agent, 48); }},
{field:'http_referer', title: 'HTTP-Referer', width:260, hide: !showMore, templet: function(d){ return cellEllipsis(d.http_referer, 40); }},
{field:'accept_language_raw', title: 'Accept-Language', width:220, hide: !showMore, templet: function(d){ return cellEllipsis(d.accept_language_raw, 32); }},
]];
}
table.render({
elem: '#ID-table-demo-search',
url: 'datatable/datalist.php',
cols: buildCols(false),
page: true,
limit: 50,
height: 800,
size: "sm",
skin: "line",
even: true,
rowStyle: function(row) {
if (row.reason && row.reason.indexOf('未确定流量来源') !== -1) {
return 'color:#856404;background-color:#fff8e6;';
}
},
done: function(res, curr, count, origin){
console.log(res); // 得到当前渲染的数据
console.log(curr); // 得到当前页码
console.log(count); // 得到数据总量
console.log(origin); // 回调函数所执行的来源 --- 2.8.7+
$("#total_nums").text(count);
},
});
$('#btn-show-more').on('click', function() {
showMoreCols = !showMoreCols;
$(this).text(showMoreCols ? '收起更多' : '显示更多');
table.reload('ID-table-demo-search', { cols: buildCols(showMoreCols) });
});
// 日期
laydate.render({
elem: '.demo-table-search-date'
});
// 搜索提交
form.on('submit(demo-table-search)', function(data){
var field = data.field; // 获得表单字段
// 执行搜索重载
table.reload('ID-table-demo-search', {
page: {
curr: 1 // 重新从第 1 页开始
},
where: field // 搜索的字段
});
// layer.msg('搜索成功<br>此处为静态模拟数据,实际使用时换成真实接口即可');
return false; // 阻止默认 form 跳转
});
// table.reload('ID-table-demo-search', {
// page: {
// curr: 1 // 重新从第 1 页开始
// },
// });
var layer = layui.layer;
var util = layui.util;
util.on('lay-on', {
confirm: function(){
layer.confirm('确定清除所有日志数据?', {
btn: ['确定', '关闭'] //按钮
}, function(){
$.get("datatable/datalist.php", {clear: "true"}, function(result){
layer.msg('清除成功', {icon: 1});
window.location.reload();
});
}, function(){
});
},
});
});
// 刷新按钮
function resetTable() {
var table = layui.table;
table.reload('ID-table-demo-search', {
page: {
curr: 1 // 重新从第 1 页开始
},
});
}
$("#export").click(function() {
var visit_date = $("input[name=visit_date]").val();
var domain = $("input[name=domain]").val();
var spage = $("input[name=spage]").val();
var country = $("input[name=country]").val();
var IP = $("input[name=IP]").val();
var result = $("select[name=result]").val();
var url = 'datatable/export.php?';
var args = [];
if(visit_date) {
args.push( "visit_date=" + visit_date );
}
if(domain) {
args.push( "domain=" + domain );
}
if(spage) {
args.push( "spage=" + spage );
}
if(country) {
args.push( "country=" + country );
}
if(IP) {
args.push( "IP=" + IP );
}
if(result) {
args.push( "result=" + encodeURIComponent(result) );
}
window.location.href=url + args.join("&");
});
</script>
</body>
</html>