layui.define(['form', 'table', 'http', 'auth', 'laydate'], function (exports) { var $ = layui.jquery, form = layui.form, table = layui.table, layer = layui.layer, http = layui.http, laydate = layui.laydate, auth = layui.auth; var _savedPerms = (layui.data('backend').permission) || []; auth.init(_savedPerms); auth.setController('spider'); // 日期选择 laydate.render({ elem: '#dateInput' }); // 汇总 + 趋势(纯 CSS 迷你条形图,不依赖 echarts) function loadStats() { http.get('stats').then(function (res) { if (res.code !== 0) { return; } var summary = (res.data && res.data.summary) || []; var trend = (res.data && res.data.trend) || { dates: [], series: [] }; var $body = $('#summaryBody').empty(); // DNS 熔断提示 if (res.data && res.data.dns_down) { $('#dnsWarn').show().html('DNS 查询连续失败,真伪校验已临时降级(5 分钟后自动恢复)。请检查服务器 DNS 配置或 /etc/resolv.conf。'); } else { $('#dnsWarn').hide(); } if (summary.length === 0) { $body.append('暂无蜘蛛来访记录'); return; } var seriesMap = {}; (trend.series || []).forEach(function (s) { seriesMap[s.name] = s.data; }); // 蜘蛛下拉(去重,避免重复追加) var $sel = $('#spiderSelect'); if ($sel.find('option').length <= 1) { summary.forEach(function (row) { $sel.append(''); }); form.render('select'); } summary.forEach(function (row) { var line = seriesMap[row.label] || []; var max = Math.max.apply(null, line.concat([1])); var bars = line.map(function (v, i) { var h = v > 0 ? Math.max(2, Math.round(v / max * 28)) : 1; return ''; }).join(''); // 不支持 rDNS 校验的蜘蛛,真伪列显示占位说明 var realCell, fakeCell; if (row.verifiable === false) { realCell = '—'; fakeCell = '—'; } else { realCell = '' + (row.real || 0) + ''; fakeCell = (row.fake > 0) ? '' + row.fake + '' : '0'; } $body.append('' + '' + row.label + ' (' + row.spider + ')' + '' + row.today + '' + '' + row.week + '' + '' + row.month + '' + '' + row.total + '' + '' + realCell + '' + '' + fakeCell + '' + '
' + bars + '
' + ''); }); }); } loadStats(); // 明细表 table.render({ elem: '#dataTable', url: 'index', toolbar: '#tableBar', defaultToolbar: ['filter', 'exports', 'print'], parseData: function (res) { return { code: res.code === 0 ? 0 : 1, msg: res.message || '', count: res.count || (res.data ? res.data.length : 0), data: res.data || [] }; }, cols: [[ { field: 'id', width: 90, title: 'ID', sort: true }, { field: 'spider_text', width: 110, title: '蜘蛛' }, { field: 'verified_text', width: 100, title: '真伪', templet: function (d) { if (d.verified === 1) { return '真蜘蛛'; } if (d.verified === 2) { return '假蜘蛛'; } return '待验证'; }}, { field: 'rdns', width: 220, title: 'rDNS', templet: function (d) { return d.rdns ? '' + d.rdns + '' : '—'; }}, { field: 'url', title: '抓取URL', minWidth: 220 }, { field: 'ip', width: 140, title: '来源IP' }, { field: 'app', width: 90, title: '应用' }, { field: 'http_code', width: 80, title: '状态码' }, { field: 'time_text', width: 170, title: '抓取时间' } ]], limits: [15, 30, 50, 100], limit: 15, page: true, skin: 'line', done: function () { var view = $('#dataTable').next('.layui-table-view'); auth.filterDom(view); } }); // 搜索 form.on('submit(data-search-btn)', function (data) { table.reload('dataTable', { page: { curr: 1 }, where: data.field }); return false; }); $('#btn-reset').on('click', function () { $('input[name="ip"],input[name="url"],input[name="date"]').val(''); $('#spiderSelect').val(''); $('#verifiedSelect').val(''); form.render('select'); table.reload('dataTable', { page: { curr: 1 }, where: { spider: '', verified: '', ip: '', url: '', date: '' } }); }); // 工具条:重新校验 / 清理旧日志 table.on('toolbar(dataTable)', function (elem) { if (elem.event === 'dataRecheck') { layer.confirm('将对历史上「待验证」的蜘蛛记录重新做 rDNS 双向校验(每 IP 一次 DNS 查询,最多 200 个 IP),可能耗时数秒。是否继续?', { title: '重新校验真伪', btn: ['开始校验', '取消'] }, function (index) { layer.close(index); var loadIndex = layer.load(2, { shade: [0.3, '#000'] }); http.post('recheck', { limit: 200 }).then(function (res) { layer.close(loadIndex); if (res.code === 0) { layer.msg(res.message || '校验完成', { icon: 1, time: 5000 }); table.reload('dataTable', {}, true); loadStats(); } else { layer.msg(res.msg || res.message || '校验失败', { icon: 2 }); } }); }); return; } if (elem.event === 'dataClear') { layer.prompt({ title: '保留最近多少天的明细?(聚合报表不受影响)', value: '30' }, function (value, index) { layer.close(index); var days = parseInt(value, 10) || 30; http.post('clear', { days: days }).then(function (res) { if (res.code === 0) { layer.msg(res.message || '清理完成'); table.reload('dataTable', {}, true); } else { layer.msg(res.msg || res.message || '清理失败'); } }); }); } }); exports('spider', {}); });