mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-09-05 15:25:31 +08:00
feat(nginx-log): NginxLogStat dashboard 视图与 JS(echarts 趋势图)
This commit is contained in:
3
extend/base/admin/view/system/nginx_log_stat/_common.js
Normal file
3
extend/base/admin/view/system/nginx_log_stat/_common.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// NginxLogStat dashboard _common.js
|
||||||
|
// 仪表盘页面不使用 ua.table.render(数据由 AJAX 预取后客户端渲染),故 init 对象为空。
|
||||||
|
// 本文件仅用于满足 STRICT_VIEW_JS=true(AdminControllerBase::fetchJS 要求 _common 模板存在)。
|
||||||
121
extend/base/admin/view/system/nginx_log_stat/index.html
Normal file
121
extend/base/admin/view/system/nginx_log_stat/index.html
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
<div class="layuimini-container">
|
||||||
|
<div class="layuimini-main" id="nginxStatDashboard"
|
||||||
|
data-period="{$period|default='day'}"
|
||||||
|
data-start="{$start|default=''}"
|
||||||
|
data-end="{$end|default=''}">
|
||||||
|
|
||||||
|
<!-- 时间范围选择器 -->
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-body" style="padding: 10px 15px;">
|
||||||
|
<div class="layui-btn-group" id="periodGroup">
|
||||||
|
<button type="button" class="layui-btn layui-btn-sm" data-period="day">今天</button>
|
||||||
|
<button type="button" class="layui-btn layui-btn-sm layui-btn-primary" data-period="week">近7天</button>
|
||||||
|
<button type="button" class="layui-btn layui-btn-sm layui-btn-primary" data-period="month">近30天</button>
|
||||||
|
<button type="button" class="layui-btn layui-btn-sm layui-btn-primary" data-period="year">本年</button>
|
||||||
|
</div>
|
||||||
|
<span class="nginx-stat-custom-range" style="margin-left: 15px; display: inline-flex; align-items: center; gap: 5px; vertical-align: middle;">
|
||||||
|
<input type="text" class="layui-input" id="dateStart" placeholder="开始日期" autocomplete="off" style="width:130px;" readonly>
|
||||||
|
<span style="color:#999;">~</span>
|
||||||
|
<input type="text" class="layui-input" id="dateEnd" placeholder="结束日期" autocomplete="off" style="width:130px;" readonly>
|
||||||
|
<button type="button" class="layui-btn layui-btn-sm layui-btn-normal" id="customSearchBtn">查询</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 指标卡片 -->
|
||||||
|
<div class="layui-row layui-col-space15" style="margin-top: 0;">
|
||||||
|
<div class="layui-col-md3">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">访问量 PV</div>
|
||||||
|
<div class="layui-card-body nginx-stat-metric">
|
||||||
|
<span class="nginx-stat-metric-value" id="metricPv">-</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-md3">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">
|
||||||
|
独立访客 UV
|
||||||
|
<span class="layui-badge layui-bg-orange" id="uvEstimateBadge" style="display:none;">近似</span>
|
||||||
|
</div>
|
||||||
|
<div class="layui-card-body nginx-stat-metric">
|
||||||
|
<span class="nginx-stat-metric-value" id="metricUv">-</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-md3">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">流量</div>
|
||||||
|
<div class="layui-card-body nginx-stat-metric">
|
||||||
|
<span class="nginx-stat-metric-value" id="metricBytes">-</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-md3">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">平均响应时间</div>
|
||||||
|
<div class="layui-card-body nginx-stat-metric">
|
||||||
|
<span class="nginx-stat-metric-value" id="metricAvgTime">-</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 图表区:状态码饼图 + 趋势折线图 -->
|
||||||
|
<div class="layui-row layui-col-space15">
|
||||||
|
<div class="layui-col-md4">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">状态码分布</div>
|
||||||
|
<div class="layui-card-body">
|
||||||
|
<div id="statusPieChart" style="width:100%;height:320px;"></div>
|
||||||
|
<div class="nginx-stat-empty-tip" id="statusPieEmpty" style="display:none;">暂无数据</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-md8">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">PV / UV 趋势</div>
|
||||||
|
<div class="layui-card-body">
|
||||||
|
<div id="trendChart" style="width:100%;height:320px;"></div>
|
||||||
|
<div class="nginx-stat-empty-tip" id="trendEmpty" style="display:none;">暂无数据</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表格区:Top URL / Top Referer / UA 分布 -->
|
||||||
|
<div class="layui-row layui-col-space15">
|
||||||
|
<div class="layui-col-md4">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">Top URL</div>
|
||||||
|
<div class="layui-card-body" style="padding:5px 10px;">
|
||||||
|
<table id="topUrlTable" lay-filter="topUrlTable"></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-md4">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">Top Referer</div>
|
||||||
|
<div class="layui-card-body" style="padding:5px 10px;">
|
||||||
|
<table id="topRefererTable" lay-filter="topRefererTable"></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-md4">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">UA 分布</div>
|
||||||
|
<div class="layui-card-body" style="padding:5px 10px;">
|
||||||
|
<table id="topUaTable" lay-filter="topUaTable"></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.nginx-stat-metric { padding: 15px; }
|
||||||
|
.nginx-stat-metric-value { font-size: 28px; font-weight: 600; color: #333; }
|
||||||
|
.nginx-stat-empty-tip { text-align: center; color: #999; padding: 40px 0; font-size: 14px; }
|
||||||
|
</style>
|
||||||
398
extend/base/admin/view/system/nginx_log_stat/index.js
Normal file
398
extend/base/admin/view/system/nginx_log_stat/index.js
Normal file
@@ -0,0 +1,398 @@
|
|||||||
|
/**
|
||||||
|
* NginxLogStat dashboard
|
||||||
|
*
|
||||||
|
* 依赖:echarts(_require.html 全局加载)、layui(table / laydate / util)、ua(admin-core.js)
|
||||||
|
*
|
||||||
|
* 后端 URL 不硬编码:用 ua.url('system.nginx_log_stat/index') 由 CONFIG.ADMIN 拼接。
|
||||||
|
* AJAX 触发方式:URL 带 _ajax=1(不依赖 Accept header,命令行测试友好)。
|
||||||
|
*/
|
||||||
|
layui.use(['table', 'laydate', 'util'], function () {
|
||||||
|
|
||||||
|
var table = layui.table;
|
||||||
|
var laydate = layui.laydate;
|
||||||
|
var util = layui.util;
|
||||||
|
|
||||||
|
// ── 配置(URL 不硬编码:由 ua.url 拼接 /{ADMIN}/system.nginx_log_stat/index)──
|
||||||
|
var STAT_INDEX_URL = ua.url('system.nginx_log_stat/index');
|
||||||
|
|
||||||
|
// ── DOM 引用 ──
|
||||||
|
var $dashboard = $('#nginxStatDashboard');
|
||||||
|
var $periodGroup = $('#periodGroup');
|
||||||
|
var $metricPv = $('#metricPv');
|
||||||
|
var $metricUv = $('#metricUv');
|
||||||
|
var $metricBytes = $('#metricBytes');
|
||||||
|
var $metricAvgTime = $('#metricAvgTime');
|
||||||
|
var $uvBadge = $('#uvEstimateBadge');
|
||||||
|
var $statusPie = $('#statusPieChart');
|
||||||
|
var $statusPieEmpty = $('#statusPieEmpty');
|
||||||
|
var $trend = $('#trendChart');
|
||||||
|
var $trendEmpty = $('#trendEmpty');
|
||||||
|
|
||||||
|
// ── echarts 实例(惰性初始化,容器存在时才创建)──
|
||||||
|
var statusPieChart = null;
|
||||||
|
var trendChart = null;
|
||||||
|
|
||||||
|
// ── 状态:当前选中的 period ──
|
||||||
|
var currentPeriod = $dashboard.data('period') || 'day';
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// 工具函数
|
||||||
|
// ================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化字节数为人类可读(B / KB / MB / GB)
|
||||||
|
*/
|
||||||
|
function formatBytes(bytes) {
|
||||||
|
bytes = Number(bytes) || 0;
|
||||||
|
if (bytes < 1024) return bytes + ' B';
|
||||||
|
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
|
||||||
|
if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
|
||||||
|
return (bytes / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化响应时间(秒 → ms / s)
|
||||||
|
*/
|
||||||
|
function formatTime(seconds) {
|
||||||
|
seconds = Number(seconds) || 0;
|
||||||
|
if (seconds < 1) return Math.round(seconds * 1000) + ' ms';
|
||||||
|
return seconds.toFixed(2) + ' s';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数字千分位
|
||||||
|
*/
|
||||||
|
function formatNumber(num) {
|
||||||
|
num = Number(num) || 0;
|
||||||
|
return util.number ? util.number(num) : num.toLocaleString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 截断长文本(表格 label 列)
|
||||||
|
*/
|
||||||
|
function truncate(text, maxLen) {
|
||||||
|
text = String(text || '');
|
||||||
|
maxLen = maxLen || 50;
|
||||||
|
if (text.length <= maxLen) return text;
|
||||||
|
return text.substring(0, maxLen) + '...';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// period 按钮切换
|
||||||
|
// ================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 period 按钮高亮(active 用 layui-btn 实色,其余 layui-btn-primary)
|
||||||
|
*/
|
||||||
|
function setActivePeriod(period) {
|
||||||
|
currentPeriod = period;
|
||||||
|
$periodGroup.find('button[data-period]').each(function () {
|
||||||
|
var $btn = $(this);
|
||||||
|
if ($btn.data('period') === period) {
|
||||||
|
$btn.removeClass('layui-btn-primary');
|
||||||
|
} else {
|
||||||
|
$btn.addClass('layui-btn-primary');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$periodGroup.on('click', 'button[data-period]', function () {
|
||||||
|
var period = $(this).data('period');
|
||||||
|
setActivePeriod(period);
|
||||||
|
loadData({ period: period });
|
||||||
|
});
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// 自定义日期区间
|
||||||
|
// ================================================================
|
||||||
|
|
||||||
|
laydate.render({
|
||||||
|
elem: '#dateStart',
|
||||||
|
type: 'date',
|
||||||
|
format: 'yyyy-MM-dd',
|
||||||
|
});
|
||||||
|
laydate.render({
|
||||||
|
elem: '#dateEnd',
|
||||||
|
type: 'date',
|
||||||
|
format: 'yyyy-MM-dd',
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#customSearchBtn').on('click', function () {
|
||||||
|
var startVal = $('#dateStart').val();
|
||||||
|
var endVal = $('#dateEnd').val();
|
||||||
|
if (!startVal || !endVal) {
|
||||||
|
ua.msg.error('请选择开始和结束日期');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 选了自定义区间后取消 period 按钮高亮
|
||||||
|
setActivePeriod('');
|
||||||
|
loadData({ period: 'custom', start: startVal, end: endVal });
|
||||||
|
});
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// AJAX 加载数据
|
||||||
|
// ================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求后端统计数据并重绘全部区块
|
||||||
|
*
|
||||||
|
* @param {object} extra 额外参数(period / start / end)
|
||||||
|
*/
|
||||||
|
function loadData(extra) {
|
||||||
|
extra = extra || {};
|
||||||
|
|
||||||
|
var params = $.extend({ _ajax: 1, period: currentPeriod }, extra);
|
||||||
|
|
||||||
|
ua.request.get({
|
||||||
|
url: STAT_INDEX_URL + '?_ajax=1',
|
||||||
|
data: params,
|
||||||
|
statusName: 'code',
|
||||||
|
statusCode: 0,
|
||||||
|
}, function (res) {
|
||||||
|
// ok:code=0
|
||||||
|
var data = (res && res.data) ? res.data : null;
|
||||||
|
if (!data) {
|
||||||
|
renderAll(buildEmptyData());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
renderAll(data);
|
||||||
|
}, function (res) {
|
||||||
|
// no:code!=0 或业务错误
|
||||||
|
var msg = (res && res.msg) ? res.msg : '加载统计数据失败';
|
||||||
|
ua.msg.error(msg);
|
||||||
|
renderAll(buildEmptyData());
|
||||||
|
}, function () {
|
||||||
|
// ex:网络异常等
|
||||||
|
renderAll(buildEmptyData());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildEmptyData() {
|
||||||
|
return {
|
||||||
|
summary: {
|
||||||
|
pv: 0, uv: 0, total_bytes: 0,
|
||||||
|
status_2xx: 0, status_3xx: 0, status_4xx: 0, status_5xx: 0, status_other: 0,
|
||||||
|
avg_request_time: 0,
|
||||||
|
},
|
||||||
|
trend: [],
|
||||||
|
top_urls: [],
|
||||||
|
top_referers: [],
|
||||||
|
top_uas: [],
|
||||||
|
uv_is_estimate: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// 渲染:汇总入口
|
||||||
|
// ================================================================
|
||||||
|
|
||||||
|
function renderAll(data) {
|
||||||
|
renderSummary(data.summary || {}, data.uv_is_estimate);
|
||||||
|
renderStatusPie(data.summary || {});
|
||||||
|
renderTrend(data.trend || []);
|
||||||
|
renderTopTables({
|
||||||
|
top_urls: data.top_urls || [],
|
||||||
|
top_referers: data.top_referers || [],
|
||||||
|
top_uas: data.top_uas || [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// 渲染:指标卡片
|
||||||
|
// ================================================================
|
||||||
|
|
||||||
|
function renderSummary(summary, uvIsEstimate) {
|
||||||
|
$metricPv.text(formatNumber(summary.pv));
|
||||||
|
$metricUv.text(formatNumber(summary.uv));
|
||||||
|
$metricBytes.text(formatBytes(summary.total_bytes));
|
||||||
|
$metricAvgTime.text(formatTime(summary.avg_request_time));
|
||||||
|
|
||||||
|
// UV 近似角标
|
||||||
|
if (uvIsEstimate) {
|
||||||
|
$uvBadge.show();
|
||||||
|
} else {
|
||||||
|
$uvBadge.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// 渲染:状态码饼图
|
||||||
|
// ================================================================
|
||||||
|
|
||||||
|
function renderStatusPie(summary) {
|
||||||
|
var segments = [
|
||||||
|
{ name: '2xx', value: Number(summary.status_2xx) || 0, color: '#5FB878' },
|
||||||
|
{ name: '3xx', value: Number(summary.status_3xx) || 0, color: '#1E9FFF' },
|
||||||
|
{ name: '4xx', value: Number(summary.status_4xx) || 0, color: '#FFB800' },
|
||||||
|
{ name: '5xx', value: Number(summary.status_5xx) || 0, color: '#FF5722' },
|
||||||
|
{ name: '其他', value: Number(summary.status_other) || 0, color: '#999' },
|
||||||
|
];
|
||||||
|
|
||||||
|
var total = 0;
|
||||||
|
for (var i = 0; i < segments.length; i++) {
|
||||||
|
total += segments[i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 空数据 → 隐藏 chart、显示占位
|
||||||
|
if (total === 0) {
|
||||||
|
$statusPie.hide();
|
||||||
|
$statusPieEmpty.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$statusPie.show();
|
||||||
|
$statusPieEmpty.hide();
|
||||||
|
|
||||||
|
if (!statusPieChart) {
|
||||||
|
statusPieChart = echarts.init($statusPie[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
statusPieChart.setOption({
|
||||||
|
tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' },
|
||||||
|
legend: { bottom: 0, left: 'center', data: segments.map(function (s) { return s.name; }) },
|
||||||
|
series: [{
|
||||||
|
name: '状态码',
|
||||||
|
type: 'pie',
|
||||||
|
radius: ['40%', '65%'],
|
||||||
|
center: ['50%', '45%'],
|
||||||
|
avoidLabelOverlap: true,
|
||||||
|
label: { show: true, formatter: '{b}\n{d}%' },
|
||||||
|
labelLine: { show: true },
|
||||||
|
data: segments.map(function (s) {
|
||||||
|
return { name: s.name, value: s.value, itemStyle: { color: s.color } };
|
||||||
|
}),
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// 渲染:趋势折线图(PV/UV 双 Y 轴)
|
||||||
|
// ================================================================
|
||||||
|
|
||||||
|
function renderTrend(trend) {
|
||||||
|
var hasData = trend && trend.length > 0;
|
||||||
|
var pvSum = 0;
|
||||||
|
if (hasData) {
|
||||||
|
for (var i = 0; i < trend.length; i++) {
|
||||||
|
pvSum += Number(trend[i].pv) || 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全部点 PV 都为 0 → 视为空数据
|
||||||
|
if (!hasData || pvSum === 0) {
|
||||||
|
$trend.hide();
|
||||||
|
$trendEmpty.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$trend.show();
|
||||||
|
$trendEmpty.hide();
|
||||||
|
|
||||||
|
if (!trendChart) {
|
||||||
|
trendChart = echarts.init($trend[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var labels = trend.map(function (d) { return d.label; });
|
||||||
|
var pvData = trend.map(function (d) { return Number(d.pv) || 0; });
|
||||||
|
var uvData = trend.map(function (d) { return Number(d.uv) || 0; });
|
||||||
|
|
||||||
|
trendChart.setOption({
|
||||||
|
tooltip: { trigger: 'axis' },
|
||||||
|
legend: { data: ['PV', 'UV'], bottom: 0 },
|
||||||
|
grid: { left: '3%', right: '4%', bottom: '12%', top: '8%', containLabel: true },
|
||||||
|
xAxis: { type: 'category', boundaryGap: false, data: labels },
|
||||||
|
yAxis: [
|
||||||
|
{ type: 'value', name: 'PV', position: 'left' },
|
||||||
|
{ type: 'value', name: 'UV', position: 'right' },
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'PV',
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 6,
|
||||||
|
itemStyle: { color: '#1E9FFF' },
|
||||||
|
areaStyle: { opacity: 0.1 },
|
||||||
|
data: pvData,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'UV',
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
yAxisIndex: 1,
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 6,
|
||||||
|
itemStyle: { color: '#5FB878' },
|
||||||
|
areaStyle: { opacity: 0.1 },
|
||||||
|
data: uvData,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// 渲染:Top 表格(客户端数据,无分页)
|
||||||
|
// ================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用 Top 表格渲染(客户端 data 模式)
|
||||||
|
*
|
||||||
|
* @param {string} elem 表格选择器
|
||||||
|
* @param {string} filter lay-filter
|
||||||
|
* @param {array} rows 数据行 [{label,pv,uv}]
|
||||||
|
* @param {number} maxLabelLen label 截断长度
|
||||||
|
*/
|
||||||
|
function renderTopTable(elem, filter, rows, maxLabelLen) {
|
||||||
|
// layui table 客户端渲染:传 data 数组(非 url)
|
||||||
|
table.render({
|
||||||
|
elem: elem,
|
||||||
|
filter: filter,
|
||||||
|
data: rows || [],
|
||||||
|
page: false,
|
||||||
|
limit: 1000,
|
||||||
|
even: true,
|
||||||
|
text: { none: '暂无数据' },
|
||||||
|
cols: [[
|
||||||
|
{ type: 'numbers', title: '#', width: 45 },
|
||||||
|
{
|
||||||
|
field: 'label', title: '名称', minWidth: 120,
|
||||||
|
templet: function (d) {
|
||||||
|
var text = truncate(d.label, maxLabelLen || 50);
|
||||||
|
// 鼠标悬停显示完整内容
|
||||||
|
if (d.label && String(d.label).length > (maxLabelLen || 50)) {
|
||||||
|
return '<span title="' + String(d.label).replace(/"/g, '"') + '">' + text + '</span>';
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ field: 'pv', title: 'PV', width: 80, sort: true },
|
||||||
|
{ field: 'uv', title: 'UV', width: 80, sort: true },
|
||||||
|
]],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTopTables(data) {
|
||||||
|
renderTopTable('#topUrlTable', 'topUrlTable', data.top_urls, 50);
|
||||||
|
renderTopTable('#topRefererTable', 'topRefererTable', data.top_referers, 40);
|
||||||
|
renderTopTable('#topUaTable', 'topUaTable', data.top_uas, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// 窗口 resize → echarts 自适应
|
||||||
|
// ================================================================
|
||||||
|
|
||||||
|
$(window).on('resize', function () {
|
||||||
|
if (statusPieChart) statusPieChart.resize();
|
||||||
|
if (trendChart) trendChart.resize();
|
||||||
|
});
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// 初始化
|
||||||
|
// ================================================================
|
||||||
|
|
||||||
|
// 初始高亮当前 period 按钮(由控制器 assign 的 period 决定)
|
||||||
|
setActivePeriod(currentPeriod);
|
||||||
|
|
||||||
|
// 首次加载数据
|
||||||
|
loadData({ period: currentPeriod });
|
||||||
|
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user