风险系数判断修复

This commit is contained in:
root
2026-06-14 18:30:06 +08:00
parent 235bf939b8
commit eb2724e3de
143 changed files with 68315 additions and 73 deletions
+446 -42
View File
@@ -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, '&quot;');
}
function escapeAttr(s) {
return String(s)
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/</g, '&lt;');
}
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(){