风险系数判断修复
This commit is contained in:
@@ -179,8 +179,113 @@ if(empty($_SESSION['password']) || $_SESSION['password'] != LOGIN_PASSWORD) {
|
||||
color: #4a5568;
|
||||
letter-spacing: -.02em;
|
||||
}
|
||||
.cell-copy-link { cursor: copy; }
|
||||
.cell-copy-link:hover { color: var(--log-primary-dark); }
|
||||
.cell-ip { font-family: 'SF Mono', 'Consolas', monospace; font-size: 12px; }
|
||||
.text-muted { color: #adb5bd; }
|
||||
.fp-hdata-cell { display: flex; flex-direction: column; gap: 4px; max-width: 100%; }
|
||||
.fp-hdata-summary { font-size: 11.5px; color: #475569; line-height: 1.35; }
|
||||
.fp-hdata-btn {
|
||||
display: inline-block;
|
||||
padding: 1px 8px;
|
||||
font-size: 11px;
|
||||
border-radius: 4px;
|
||||
background: #e8f4fd;
|
||||
color: #0c5460;
|
||||
cursor: pointer;
|
||||
border: 1px solid #bee5eb;
|
||||
width: fit-content;
|
||||
}
|
||||
.fp-hdata-btn:hover { background: #d1ecf1; }
|
||||
.fp-risk-explain { font-size: 13px; line-height: 1.55; color: #2c3e50; }
|
||||
.fp-risk-explain-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
|
||||
.fp-risk-tag { font-size: 12px; padding: 2px 10px; border-radius: 999px; background: #eef2ff; color: #3730a3; font-weight: 600; }
|
||||
.fp-risk-kv { width: 100%; border-collapse: collapse; margin-bottom: 14px; font-size: 12.5px; }
|
||||
.fp-risk-kv th { text-align: left; width: 88px; padding: 6px 8px; background: #f8fafc; border: 1px solid #e2e8f0; vertical-align: top; color: #64748b; }
|
||||
.fp-risk-kv td { padding: 6px 8px; border: 1px solid #e2e8f0; word-break: break-word; }
|
||||
.fp-risk-reason-raw { font-family: 'SF Mono', Consolas, monospace; font-size: 12px; }
|
||||
.fp-risk-section-title { font-weight: 600; margin: 12px 0 8px; font-size: 13px; color: #334155; }
|
||||
.fp-risk-factor-list { margin: 0; padding-left: 1.2rem; }
|
||||
.fp-risk-factor-list > li { margin-bottom: 10px; }
|
||||
.fp-factor-text { font-weight: 500; margin-bottom: 4px; }
|
||||
.fp-factor-fields { margin: 0; padding-left: 1rem; list-style: disc; }
|
||||
.fp-factor-fields mark.fp-field-key { background: #fef3c7; padding: 0 4px; border-radius: 3px; font-weight: 600; }
|
||||
.fp-factor-fields code { font-size: 11.5px; word-break: break-all; }
|
||||
.fp-factor-miss { font-size: 12px; color: #94a3b8; }
|
||||
.fp-hdata-json {
|
||||
max-height: 320px;
|
||||
overflow: auto;
|
||||
background: #0f172a;
|
||||
color: #e2e8f0;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
font-size: 11.5px;
|
||||
line-height: 1.45;
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
.fp-hdata-json .fp-hl-line { background: rgba(250, 204, 21, .18); display: inline-block; width: 100%; }
|
||||
.log-nav { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||
.log-nav a {
|
||||
display: inline-block; padding: 6px 14px; border-radius: 6px; font-size: .85rem;
|
||||
text-decoration: none; border: 1px solid var(--log-border); background: #fff; color: var(--log-text);
|
||||
}
|
||||
.log-nav a.active { background: var(--log-primary); color: #fff; border-color: var(--log-primary); }
|
||||
.fp-risk-conclusions { margin: 0 0 14px; padding: 0; list-style: none; }
|
||||
.fp-risk-conclusions li {
|
||||
padding: 9px 12px; margin-bottom: 8px; border-radius: 8px; font-size: 12.5px; line-height: 1.55;
|
||||
border-left: 3px solid #16baaa; background: #f0faf9;
|
||||
}
|
||||
.fp-risk-conclusions li.warn { background: #fff8e6; border-left-color: #e6a23c; }
|
||||
.fp-risk-conclusions li.alert { background: #fef2f2; border-left-color: #e74c3c; }
|
||||
.fp-risk-conclusions li.ok { background: #f0fdf4; border-left-color: #22c55e; }
|
||||
.fp-risk-conclusions li .fp-conc-action {
|
||||
display: block; margin-top: 4px; font-size: 12px; color: #64748b;
|
||||
}
|
||||
.fp-risk-conclusions li a { color: #0e8d81; text-decoration: none; }
|
||||
.fp-risk-conclusions li a:hover { text-decoration: underline; }
|
||||
.col-settings-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
max-height: 420px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.col-settings-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px 10px;
|
||||
margin-bottom: 6px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 6px;
|
||||
cursor: grab;
|
||||
user-select: none;
|
||||
}
|
||||
.col-settings-item.dragging { opacity: .55; border-style: dashed; }
|
||||
.col-settings-item.drag-over { border-color: var(--log-primary); background: #eefaf8; }
|
||||
.col-settings-handle {
|
||||
color: #94a3b8;
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
cursor: grab;
|
||||
}
|
||||
.col-settings-title { flex: 1; font-size: 13px; color: #334155; }
|
||||
.col-settings-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 14px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid #e8ecf1;
|
||||
}
|
||||
.col-settings-tip {
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
margin: 0 0 10px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.log-page { padding: 16px 12px 32px; }
|
||||
.log-count { margin-left: 0; width: 100%; }
|
||||
@@ -195,9 +300,10 @@ if(empty($_SESSION['password']) || $_SESSION['password'] != LOGIN_PASSWORD) {
|
||||
<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 class="log-nav">
|
||||
<a href="table.php" class="active">访问日志</a>
|
||||
<a href="log_analytics.php">数据分析</a>
|
||||
<a href="dashboard.php">配置中心</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -254,7 +360,7 @@ if(empty($_SESSION['password']) || $_SESSION['password'] != LOGIN_PASSWORD) {
|
||||
</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 layui-btn-normal" id="btn-col-settings" 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>
|
||||
@@ -274,7 +380,12 @@ layui.use(function(){
|
||||
var table = layui.table;
|
||||
var form = layui.form;
|
||||
var laydate = layui.laydate;
|
||||
var showMoreCols = false;
|
||||
var layer = layui.layer;
|
||||
var LINK_CELL_MAX = 150;
|
||||
var COLUMN_STORAGE_KEY = 'cloak_log_table_cols_v1';
|
||||
var TABLE_ID = 'ID-table-demo-search';
|
||||
var colConfig = [];
|
||||
var dragField = null;
|
||||
|
||||
function escapeHtml(s) {
|
||||
if (s == null || s === '') return '';
|
||||
@@ -285,6 +396,13 @@ layui.use(function(){
|
||||
.replace(/"/g, '"');
|
||||
}
|
||||
|
||||
function escapeAttr(s) {
|
||||
return String(s)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<');
|
||||
}
|
||||
|
||||
function cellEllipsis(value, maxLen) {
|
||||
var text = value == null ? '' : String(value);
|
||||
if (!text) return '<span class="text-muted">—</span>';
|
||||
@@ -293,6 +411,15 @@ layui.use(function(){
|
||||
return '<span class="cell-ellipsis" title="' + esc + '">' + display + '</span>';
|
||||
}
|
||||
|
||||
function cellLinkEllipsis(value, maxLen) {
|
||||
maxLen = maxLen || LINK_CELL_MAX;
|
||||
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 cell-copy-link" title="双击复制完整内容" data-full="' + escapeAttr(text) + '">' + display + '</span>';
|
||||
}
|
||||
|
||||
function badgeResult(val) {
|
||||
var raw = val == null ? '' : String(val);
|
||||
var v = raw.toLowerCase();
|
||||
@@ -320,45 +447,284 @@ layui.use(function(){
|
||||
cls = 'badge-error';
|
||||
} else if (/白名单|允许|通过/i.test(text)) {
|
||||
cls = 'badge-success';
|
||||
} else if (/^\d+$/.test(text.trim()) || /风险|WebDriver|Canvas|分辨率|自动化|指纹/i.test(text)) {
|
||||
cls = 'badge-warning';
|
||||
}
|
||||
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); }},
|
||||
]];
|
||||
function cellFpHdata(d) {
|
||||
if (!d.fp_hdata && !d.fp_hdata_text) {
|
||||
return '<span class="text-muted">—</span>';
|
||||
}
|
||||
var summary = d.fp_hdata_explain_summary || d.fp_hdata_text || '';
|
||||
var html = '';
|
||||
html += '<div class="fp-hdata-cell">';
|
||||
if (summary) {
|
||||
html += '<span class="fp-hdata-summary" title="' + escapeAttr(summary) + '">' + escapeHtml(summary.length > 48 ? summary.slice(0, 48) + '…' : summary) + '</span>';
|
||||
}
|
||||
if (d.fp_hdata_explain_html) {
|
||||
html += '<span class="fp-hdata-btn" data-explain-id="' + escapeAttr(String(d.id)) + '">判定详情</span>';
|
||||
window.__fpExplainCache = window.__fpExplainCache || {};
|
||||
window.__fpExplainCache[d.id] = d.fp_hdata_explain_html;
|
||||
} else if (d.fp_hdata || d.fp_hdata_text) {
|
||||
html += '<span class="fp-hdata-btn fp-hdata-btn-raw" data-full="' + escapeAttr(d.fp_hdata || d.fp_hdata_text) + '">原始 hdata</span>';
|
||||
}
|
||||
html += '</div>';
|
||||
return html;
|
||||
}
|
||||
|
||||
var COLUMN_DEFS = [
|
||||
{ field: 'id', title: 'ID', width: 56, fixed: true, defaultVisible: true },
|
||||
{ field: 'domain', title: '域名', width: 120, defaultVisible: true, templet: function(d){ return cellEllipsis(d.domain, 18); } },
|
||||
{ field: 'visit_date', title: '访问日期', width: 130, defaultVisible: true, templet: function(d){
|
||||
return '<span class="cell-mono" title="' + escapeHtml(d.visit_date) + '">' + escapeHtml(d.visit_date) + '</span>';
|
||||
}},
|
||||
{ field: 'country', title: '国家', width: 100, defaultVisible: true, templet: function(d){ return cellEllipsis(d.country, 12); } },
|
||||
{ field: 'result', title: '是否正常', width: 88, defaultVisible: true, templet: function(d){ return badgeResult(d.result); } },
|
||||
{ field: 'reason', title: '理由', width: 140, defaultVisible: true, templet: function(d){ return badgeReason(d.reason); } },
|
||||
{ field: 'judge_timing_text', title: '判断用时', width: 240, defaultVisible: true, templet: function(d){ return cellEllipsis(d.judge_timing_text, 36); } },
|
||||
{ field: 'vtimes', title: '第几次访问', width: 96, defaultVisible: true },
|
||||
{ field: 'fp_url', title: '跳转至', width: 280, defaultVisible: true, templet: function(d){ return cellLinkEllipsis(d.fp_url, LINK_CELL_MAX); } },
|
||||
{ field: 'device', title: '访问设备', width: 200, defaultVisible: true, templet: function(d){ return cellEllipsis(d.device, 32); } },
|
||||
{ field: 'referer', title: '来源', width: 280, defaultVisible: true, templet: function(d){ return cellLinkEllipsis(d.referer, LINK_CELL_MAX); } },
|
||||
{ field: 'IP', title: 'IP(支持IPV6)', width: 130, defaultVisible: true, templet: function(d){
|
||||
return '<span class="cell-ip" title="' + escapeHtml(d.IP) + '">' + escapeHtml(d.IP) + '</span>';
|
||||
}},
|
||||
{ field: 'page', title: '访问页面', width: 280, defaultVisible: true, templet: function(d){ return cellLinkEllipsis(d.page, LINK_CELL_MAX); } },
|
||||
{ field: 'client', title: '客户端', width: 80, defaultVisible: true, templet: function(d){ return cellEllipsis(d.client, 10); } },
|
||||
{ field: 'language', title: '语言', width: 80, defaultVisible: true, templet: function(d){ return cellEllipsis(d.language, 10); } },
|
||||
{ field: 'browser', title: '浏览器', width: 88, defaultVisible: true, templet: function(d){ return cellEllipsis(d.browser, 10); } },
|
||||
{ field: 'campagin_id', title: '广告策略', width: 88, defaultVisible: true, templet: function(d){ return cellEllipsis(d.campagin_id, 10); } },
|
||||
{ field: 'user_agent', title: 'User-Agent', width: 320, defaultVisible: false, templet: function(d){ return cellEllipsis(d.user_agent, 48); } },
|
||||
{ field: 'http_referer', title: 'HTTP-Referer', width: 260, defaultVisible: false, templet: function(d){ return cellLinkEllipsis(d.http_referer, LINK_CELL_MAX); } },
|
||||
{ field: 'accept_language_raw', title: 'Accept-Language', width: 220, defaultVisible: false, templet: function(d){ return cellEllipsis(d.accept_language_raw, 32); } },
|
||||
{ field: 'fp_hdata_text', title: '指纹 hdata', width: 360, defaultVisible: false, templet: function(d){ return cellFpHdata(d); } },
|
||||
];
|
||||
|
||||
var COLUMN_DEF_MAP = {};
|
||||
COLUMN_DEFS.forEach(function(def) {
|
||||
COLUMN_DEF_MAP[def.field] = def;
|
||||
});
|
||||
|
||||
function getDefaultColConfig() {
|
||||
return COLUMN_DEFS.map(function(def) {
|
||||
return { field: def.field, visible: def.defaultVisible !== false };
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeColConfig(raw) {
|
||||
var defaults = getDefaultColConfig();
|
||||
if (!Array.isArray(raw) || !raw.length) {
|
||||
return defaults;
|
||||
}
|
||||
var seen = {};
|
||||
var merged = [];
|
||||
raw.forEach(function(item) {
|
||||
if (!item || !item.field || !COLUMN_DEF_MAP[item.field] || seen[item.field]) {
|
||||
return;
|
||||
}
|
||||
seen[item.field] = true;
|
||||
merged.push({
|
||||
field: item.field,
|
||||
visible: item.visible !== false
|
||||
});
|
||||
});
|
||||
defaults.forEach(function(item) {
|
||||
if (!seen[item.field]) {
|
||||
merged.push(item);
|
||||
}
|
||||
});
|
||||
return merged;
|
||||
}
|
||||
|
||||
function loadColConfig() {
|
||||
try {
|
||||
var raw = localStorage.getItem(COLUMN_STORAGE_KEY);
|
||||
if (!raw) {
|
||||
return getDefaultColConfig();
|
||||
}
|
||||
return normalizeColConfig(JSON.parse(raw));
|
||||
} catch (e) {
|
||||
return getDefaultColConfig();
|
||||
}
|
||||
}
|
||||
|
||||
function saveColConfig(config) {
|
||||
colConfig = normalizeColConfig(config);
|
||||
localStorage.setItem(COLUMN_STORAGE_KEY, JSON.stringify(colConfig));
|
||||
}
|
||||
|
||||
function buildColItem(def, visible) {
|
||||
var col = {
|
||||
field: def.field,
|
||||
title: def.title,
|
||||
width: def.width,
|
||||
hide: !visible
|
||||
};
|
||||
if (def.templet) {
|
||||
col.templet = def.templet;
|
||||
}
|
||||
return col;
|
||||
}
|
||||
|
||||
function buildCols(config) {
|
||||
config = normalizeColConfig(config || colConfig);
|
||||
var cols = [];
|
||||
var firstVisibleField = null;
|
||||
config.forEach(function(item) {
|
||||
if (item.visible && !firstVisibleField) {
|
||||
firstVisibleField = item.field;
|
||||
}
|
||||
});
|
||||
config.forEach(function(item) {
|
||||
var def = COLUMN_DEF_MAP[item.field];
|
||||
if (!def) {
|
||||
return;
|
||||
}
|
||||
var col = buildColItem(def, item.visible);
|
||||
if (def.fixed && item.field === firstVisibleField) {
|
||||
col.fixed = def.fixed;
|
||||
} else {
|
||||
delete col.fixed;
|
||||
}
|
||||
cols.push(col);
|
||||
});
|
||||
if (!cols.length) {
|
||||
cols.push(buildColItem(COLUMN_DEF_MAP.id, true));
|
||||
}
|
||||
return [cols];
|
||||
}
|
||||
|
||||
function reloadTableCols() {
|
||||
table.reload(TABLE_ID, { cols: buildCols(colConfig) });
|
||||
}
|
||||
|
||||
function renderColSettingsList() {
|
||||
var html = '<p class="col-settings-tip">勾选显示列,拖拽左侧手柄调整顺序。设置保存在本浏览器。</p>';
|
||||
html += '<ul class="col-settings-list" id="col-settings-list">';
|
||||
colConfig.forEach(function(item) {
|
||||
var def = COLUMN_DEF_MAP[item.field];
|
||||
if (!def) {
|
||||
return;
|
||||
}
|
||||
html += '<li class="col-settings-item" draggable="true" data-field="' + escapeAttr(item.field) + '">';
|
||||
html += '<span class="col-settings-handle" title="拖拽排序">☰</span>';
|
||||
html += '<input type="checkbox" lay-skin="primary" class="col-settings-check" data-field="' + escapeAttr(item.field) + '"' + (item.visible ? ' checked' : '') + '>';
|
||||
html += '<span class="col-settings-title">' + escapeHtml(def.title) + '</span>';
|
||||
html += '</li>';
|
||||
});
|
||||
html += '</ul>';
|
||||
html += '<div class="col-settings-actions">';
|
||||
html += '<button type="button" class="layui-btn layui-btn-sm" id="col-settings-apply">应用</button>';
|
||||
html += '<button type="button" class="layui-btn layui-btn-sm layui-btn-primary" id="col-settings-reset">恢复默认</button>';
|
||||
html += '</div>';
|
||||
return html;
|
||||
}
|
||||
|
||||
function refreshColSettingsPanel($panel) {
|
||||
var checks = {};
|
||||
$panel.find('.col-settings-item').each(function() {
|
||||
var field = this.getAttribute('data-field');
|
||||
checks[field] = $(this).find('.col-settings-check').prop('checked');
|
||||
});
|
||||
colConfig.forEach(function(item) {
|
||||
if (Object.prototype.hasOwnProperty.call(checks, item.field)) {
|
||||
item.visible = !!checks[item.field];
|
||||
}
|
||||
});
|
||||
$panel.find('.col-settings-body').html(renderColSettingsList());
|
||||
form.render('checkbox');
|
||||
}
|
||||
|
||||
function bindColSettingsEvents(layerIndex, $panel) {
|
||||
$panel.off('.colSettings');
|
||||
$panel.on('dragstart.colSettings', '.col-settings-item', function(e) {
|
||||
dragField = this.getAttribute('data-field');
|
||||
this.classList.add('dragging');
|
||||
if (e.originalEvent && e.originalEvent.dataTransfer) {
|
||||
e.originalEvent.dataTransfer.effectAllowed = 'move';
|
||||
}
|
||||
});
|
||||
$panel.on('dragend.colSettings', '.col-settings-item', function() {
|
||||
this.classList.remove('dragging');
|
||||
$panel.find('.col-settings-item').removeClass('drag-over');
|
||||
dragField = null;
|
||||
});
|
||||
$panel.on('dragover.colSettings', '.col-settings-item', function(e) {
|
||||
e.preventDefault();
|
||||
$panel.find('.col-settings-item').removeClass('drag-over');
|
||||
this.classList.add('drag-over');
|
||||
});
|
||||
$panel.on('drop.colSettings', '.col-settings-item', function(e) {
|
||||
e.preventDefault();
|
||||
var targetField = this.getAttribute('data-field');
|
||||
if (!dragField || !targetField || dragField === targetField) {
|
||||
return;
|
||||
}
|
||||
var fromIdx = -1;
|
||||
var toIdx = -1;
|
||||
colConfig.forEach(function(item, idx) {
|
||||
if (item.field === dragField) fromIdx = idx;
|
||||
if (item.field === targetField) toIdx = idx;
|
||||
});
|
||||
if (fromIdx < 0 || toIdx < 0) {
|
||||
return;
|
||||
}
|
||||
var moved = colConfig.splice(fromIdx, 1)[0];
|
||||
colConfig.splice(toIdx, 0, moved);
|
||||
refreshColSettingsPanel($panel);
|
||||
});
|
||||
|
||||
$panel.on('click.colSettings', '#col-settings-apply', function() {
|
||||
var next = [];
|
||||
$panel.find('.col-settings-item').each(function() {
|
||||
var field = this.getAttribute('data-field');
|
||||
var visible = $(this).find('.col-settings-check').prop('checked');
|
||||
next.push({ field: field, visible: !!visible });
|
||||
});
|
||||
if (!next.some(function(item) { return item.visible; })) {
|
||||
layer.msg('至少保留一列显示');
|
||||
return;
|
||||
}
|
||||
saveColConfig(next);
|
||||
reloadTableCols();
|
||||
layer.close(layerIndex);
|
||||
layer.msg('列设置已应用');
|
||||
});
|
||||
|
||||
$panel.on('click.colSettings', '#col-settings-reset', function() {
|
||||
colConfig = getDefaultColConfig();
|
||||
refreshColSettingsPanel($panel);
|
||||
});
|
||||
}
|
||||
|
||||
function openColSettings() {
|
||||
colConfig = loadColConfig();
|
||||
var shell = '<div class="col-settings-body">' + renderColSettingsList() + '</div>';
|
||||
var layerIndex = layer.open({
|
||||
type: 1,
|
||||
title: '表格列设置',
|
||||
area: ['360px', '560px'],
|
||||
shadeClose: true,
|
||||
content: '<div class="col-settings-panel" style="padding:14px 16px 16px;">' + shell + '</div>',
|
||||
success: function(layero) {
|
||||
var $panel = layero.find('.col-settings-panel');
|
||||
form.render('checkbox');
|
||||
bindColSettingsEvents(layerIndex, $panel);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
colConfig = loadColConfig();
|
||||
|
||||
table.render({
|
||||
elem: '#ID-table-demo-search',
|
||||
id: TABLE_ID,
|
||||
url: 'datatable/datalist.php',
|
||||
cols: buildCols(false),
|
||||
cols: buildCols(colConfig),
|
||||
page: true,
|
||||
limit: 50,
|
||||
height: 800,
|
||||
@@ -371,18 +737,57 @@ layui.use(function(){
|
||||
}
|
||||
},
|
||||
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) });
|
||||
$('#btn-col-settings').on('click', openColSettings);
|
||||
|
||||
$(document).on('click', '.fp-hdata-btn', function(e) {
|
||||
e.stopPropagation();
|
||||
var id = this.getAttribute('data-explain-id');
|
||||
if (id && window.__fpExplainCache && window.__fpExplainCache[id]) {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '二次风控判定解析 #' + id,
|
||||
area: ['720px', '85vh'],
|
||||
shadeClose: true,
|
||||
content: '<div style="padding:16px 18px;max-height:calc(85vh - 60px);overflow:auto;">' + window.__fpExplainCache[id] + '</div>'
|
||||
});
|
||||
return;
|
||||
}
|
||||
var full = this.getAttribute('data-full') || '';
|
||||
if (full) {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '指纹 hdata',
|
||||
area: ['680px', '70vh'],
|
||||
shadeClose: true,
|
||||
content: '<pre style="padding:14px;margin:0;max-height:calc(70vh - 50px);overflow:auto;font-size:12px;white-space:pre-wrap;word-break:break-all;">' + escapeHtml(full) + '</pre>'
|
||||
});
|
||||
}
|
||||
});
|
||||
$(document).on('dblclick', '.cell-copy-link', function() {
|
||||
var full = this.getAttribute('data-full') || '';
|
||||
if (!full) return;
|
||||
var notify = function() { layer.msg('已复制完整内容'); };
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard.writeText(full).then(notify).catch(function() {
|
||||
layer.msg('复制失败');
|
||||
});
|
||||
return;
|
||||
}
|
||||
var ta = document.createElement('textarea');
|
||||
ta.value = full;
|
||||
document.body.appendChild(ta);
|
||||
ta.select();
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
notify();
|
||||
} catch (e) {
|
||||
layer.msg('复制失败');
|
||||
}
|
||||
document.body.removeChild(ta);
|
||||
});
|
||||
|
||||
// 日期
|
||||
@@ -407,7 +812,6 @@ layui.use(function(){
|
||||
// curr: 1 // 重新从第 1 页开始
|
||||
// },
|
||||
// });
|
||||
var layer = layui.layer;
|
||||
var util = layui.util;
|
||||
util.on('lay-on', {
|
||||
confirm: function(){
|
||||
|
||||
Reference in New Issue
Block a user