上文讲了 loadTable ,表格统计。表格统计的数据虽然在微观上较为准确,但不能从宏观上看到访客的趋势和比重,于是我制作了 loadChart 图表统计。
chart.js 部分代码,用于发送请求和接受数据
(function(){
"use strict";
var init = function(){
initPage();
bindEvent();
$("#vistor").click();
},
initPage = function(){
$("#vistorChart").css("height", "500px");
},
bindEvent = function(){
$("#btnGroup button").click(function(){
$("#btnGroup button").removeClass("active");
$(this).addClass("active");
});
$("#vistor").click(function(){
loadChart('vistor');
});
$("#link").click(function(){
loadChart('link');
});
$("#system").click(function(){
loadChart('system');
});
$("#browser").click(function(){
loadChart('browser');
});
},
loadChart = function(type){
$('#vistorChart').removeAttr('_echarts_instance_').empty();
var myChart = echarts.init($("#vistorChart")[0]);
myChart.showLoading();
$.ajax({
url: '__APP__/Vistor/loadChart',
data: {
type: type
},
type: 'POST',
cache: false,
dataType: 'JSON',
beforeSend: function(){},
complete: function(){}
}).done(function(data){
myChart.hideLoading();
myChart.setOption(data);
}).fail(function(){
swal({
type: 'error',
title: '加载失败',
allowOutsideClick: false,
allowEnterKey: false,
confirmButtonText: '确认',
animation: false,
customClass: 'animated wobble'
});
});
};
$(function(){
init();
});
})();
loadChart 部分,用于处理请求,组装数据,并返回:
public function loadChart($type = 'vistor') {
$Vistor = D('vistor');
$Dic = D('dictionary');
$vistorShow = array('all' => '总访问量', 'vistor' => '访客', 'Googlebot' => '谷歌蜘蛛', 'bingbot' => '必应蜘蛛', 'Baiduspider' => '百度蜘蛛', 'AhrefsBot' => 'Ahrefs蜘蛛', 'MJ12bot' => 'MJ12蜘蛛', 'others' => '其他流量');
$linkShow = array('all' => '访问总量', 'vistor' => '访客', 'spider' => '爬虫');
$systemShow = array('Windows 10', 'Windows 8', 'Windows 7', 'Windows XP', 'Windows Vista', 'Windows NT', 'Linux', 'MacOS', 'Android', 'iPhone', 'spider', 'sitemap', 'others');
$browserShow = array('Chrome', 'Firefox', 'Safari', 'IE', 'Opera', 'Edge', 'Maxthon', 'spider', 'sitemap', 'others');
switch ($type){
case 'vistor':
$countGroupDate = array();//临时存放数据,计算其余类型
$vistorCountGroupDate = array_column($Vistor->getCountGroupDate('all'), 'num');//总量线
$data['title'] = array('left' => '2%', 'text' => '访客类型统计图', 'subtext' => C('WUGN.WEB_SITE'));
$data['tooltip'] = array('trigger' => 'axis');
$data['legend'] = array('data' => array_values($vistorShow));
$data['toolbox'] = array('right' => '2%', 'feature' => array('dataZoom' => array('yAxisIndex' => 'none'), 'restore' => array(), 'dataView' => array(), 'saveAsImage' => array()));
$data['dataZoom'] = array(array('startValue' => '2018-09-20'), array('type' => 'inside'));
$data['xAxis'] = array('type' => 'category', 'boundaryGap' => false, 'data' => array_column($Vistor->getCountGroupDate('all'), 'ddate'));
$data['yAxis'] = array('type' => 'value');
$data['series'] = array();
foreach($vistorShow as $k=>$v) {
if($k != 'others'){
$temp = array_column($Vistor->getCountGroupDate($k), 'num');//本条线
array_push($data['series'], array('name' => $v, 'type' => 'line', 'data' => $temp));
foreach($temp as $i=>$j){
$countGroupDate[$i] += $j;
}
}
}
foreach($countGroupDate as $k=>&$v){
$v = $vistorCountGroupDate[$k] * 2 - $v;
}
array_push($data['series'], array('name' => '其他流量', 'type' => 'line', 'data' => $countGroupDate));
break;
case 'link':
$data['title'] = array('left' => '5%', 'text' => '受访页面统计图', 'subtext' => C('WUGN.WEB_SITE'));
$data['tooltip'] = array('trigger' => 'axis', 'axisPointer' => array('type' => 'cross'));
$data['legend'] = array('data' => array_values($linkShow));
$data['toolbox'] = array('right' => '5%', 'feature' => array('dataView' => array('readOnly' => true), 'magicType' => array('type' => array('line', 'bar')), 'restore' => array(), 'saveAsImage' => array()));
$data['xAxis'] = array('type' => 'category', 'axisPointer' => array('type' => 'shadow'), 'data' => array_column($Dic->getDictionary('vistor_link'), 'code_note'));
$data['yAxis'] = array('type' => 'value');
$data['series'] = array();
foreach($linkShow as $k=>$v){
$temp = array_column($Vistor->getCountGroupLink($k), 'num');
array_push($data['series'], array('name' => $v, 'type' => ($k=='all'?'line':'bar'), 'data' => $temp));
}
break;
case 'system':
$data['title'] = array('left' => '5%', 'text' => '操作系统统计图', 'subtext' => C('WUGN.WEB_SITE'));
$data['tooltip'] = array('trigger' => 'item', 'formatter' => '{a}<br />{b}:{c}({d}%)');
$data['legend'] = array('orient' => 'vertical', 'right' => '5%', 'data' => $systemShow);
$data['toolbox'] = array('right' => '5%', 'bottom' => '0', 'feature' => array('dataView' => array('readOnly' => true), 'restore' => array(), 'saveAsImage' => array()));
$data['series'] = array('name' => '操作系统', 'type' => 'pie', 'itemStyle' => array('emphasis' => array('shadowBlur' => '10', 'shadowOffsetX' => '0', 'shadowColor' => 'rgba(0, 0, 0, 0.5)')), 'data' => array());
foreach($Vistor->getSystemCount($systemShow) as $k=>$v){
array_push($data['series']['data'], array('value' => $v, 'name' => $k));
}
break;
case 'browser':
$countGroupBrowser = 0;//临时存放数据,计算其余类型
$data['title'] = array('left' => '5%', 'text' => '用户客户端统计图', 'subtext' => C('WUGN.WEB_SITE'));
$data['tooltip'] = array('trigger' => 'item', 'formatter' => '{a}<br />{b}:{c}({d}%)');
$data['legend'] = array('orient' => 'vertical', 'right' => '5%', 'data' => $browserShow);
$data['toolbox'] = array('right' => '5%', 'bottom' => '0', 'feature' => array('dataView' => array('readOnly' => true), 'restore' => array(), 'saveAsImage' => array()));
$data['series'] = array('name' => '客户端', 'type' => 'pie', 'itemStyle' => array('emphasis' => array('shadowBlur' => '10', 'shadowOffsetX' => '0', 'shadowColor' => 'rgba(0, 0, 0, 0.5)')), 'data' => array());
foreach($Vistor->getBrowserCount($browserShow) as $k=>$v){
array_push($data['series']['data'], array('value' => $v, 'name' => $k));
}
break;
}
$this->ajaxReturn($data);
}
$vistorShow $linkShow $systemShow $browserShow 分别定义要展示的数据内容。
代码逻辑比较简单,不懂的地方请咨询站长。
此外, 模型层如下:
public function getCountGroupDate($type){
$sql = "SELECT DATE(dday) AS ddate, COUNT(*) - 1 AS num
FROM(
SELECT datelist AS dday FROM wu_calendar WHERE DATE(datelist) BETWEEN '2018-08-12' AND CURDATE()
UNION ALL
SELECT tm FROM wu_vistor WHERE (";
switch ($type){
case 'all':
$sql .= "1=1";
break;
case 'vistor':
$sql .= "ag NOT LIKE '%spider%' AND ag NOT LIKE '%bot%' AND ag NOT LIKE '%sitemap%' AND ag NOT LIKE '%parser%'";
break;
case 'sitemap':
$sql .= "ag LIKE '%sitemap%' OR ag LIKE '%parser%'";
break;
default:
$sql .= "(ag LIKE '%spider%' OR ag LIKE '%bot%') AND ag LIKE '%{$type}%'";
}
$sql .= ") AND (DATE(tm) BETWEEN '2018-08-12' AND CURDATE())
)T GROUP BY ddate ORDER BY ddate";
return $this->query($sql);
}
public function getCountGroupLink($type){
$Dic = D('dictionary');
$linkCode = array_column($Dic->getDictionary('vistor_link'), 'code_value');
switch ($type){
case 'all':
$where['ag'] = array('neq','null');
break;
case 'vistor':
$where['ag'] = array('notlike',array('%spider%','%bot%'),'AND');
break;
case 'spider':
$where['ag'] = array('like',array('%spider%','%bot%'),'OR');
break;
}
$data = array();
foreach($linkCode as $v){
$where['lk'] = array('like', explode(',', $v), 'or');
array_push($data, $this->field('count(id) as num')->where($where)->find());
}
return $data;
}
public function getCountLike($type){
$where['ag'] = array('like', "%{$type}%");
$data = $this->field('count(id) as num')->where($where)->find();
return $data['num'];
}
public function getSystemCount($systemShow){
$where['ag'] = array('notlike', '%bot%');
$agent = $this->field('ag')->where($where)->select();
$data = get_os_count($agent, $systemShow);
return $data;
}
public function getBrowserCount($browserShow){
$where['ag'] = array('notlike', '%bot%');
$agent = $this->field('ag')->where($where)->select();
$data = get_br_count($agent, $browserShow);
return $data;
}
模型层中写的 SQL 不常见,(如:getCountGroupDate的查询方法)情参考本站其他文章。
get_os_count($agent, $systemShow) 函数和 get_br_count($agent, $browserShow) 用于统计数量,传入agent(array) 和要展示的内容,返回数量。这里只列出 get_br_count($agent, $browserShow) 以供参考:
function get_br_count($agent, $browserShow) {
foreach($agent as $v){
$v = $v['ag'];
if (preg_match('/sitemap/i', $v) || preg_match('/Parser/i', $v)) {
$data['sitemap'] += 1;
} else if (preg_match('/spider/i', $v) || preg_match('/bot/i', $v)) {
$data['spider'] += 1;
} else if (stripos($v, 'Firefox/')) {
$data['Firefox'] += 1;
} else if (stripos($v, 'Maxthon')) {
$data['Maxthon'] += 1;
} else if (stripos($v, 'MSIE')) {
$data['IE'] += 1;
} else if (stripos($v, 'OPR')) {
$data['Opera'] += 1;
} else if (stripos($v, 'Edge')) {
$data['Edge'] += 1;
} else if (stripos($v, 'Chrome')) {
$data['Chrome'] += 1;
} else if (stripos($v, 'Safari')) {
$data['Safari'] += 1;
} else if (stripos($v, 'rv:') && stripos($v, 'Gecko')) {
$data['IE'] += 1;
} else {
$others += 1;
}
}
arsort($data);//根据值降序排序
foreach($data as $k=>&$v){
if(!in_array($k, $browserShow)){
$others += $v;
unset($data[$k]);
}
}
$data['others'] = $others;
return $data;
}