此处以统计后台用户(admin_users)的在线时长为例;前台用户的话,只是对应的表不一样 (对应 users)。
准备数据库
此处需要添加两个字段,分别是 上次在线时间 和 总计在线时长(秒为单位):
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddSpentToAdminUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('admin_users', function (Blueprint $table) {
$table->unsignedInteger('spent')->default('0')->comment('使用时长')->after('id');
$table->timestamp('onlined_at')->nullable()->comment('最后访问时间')->after('updated_at');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('admin_users', function (Blueprint $table) {
//
$table->dropColumn(['spent', 'onlined_at']);
});
}
}
创建中间件
<?php
namespace App\Http\Middleware;
use Carbon\Carbon;
use Closure;
use Dcat\Admin\Admin;
use Illuminate\Support\Facades\Cache;
class CountAdminUserOnlineTime
{
public function handle($request, Closure $next)
{
$user = Admin::user(); // 获取当前认证用户
if ($user) {
$seenKey = 'auser-last-seen-'; //缓存标识
$lastSeenAt = Cache::get($seenKey . $user->id); // 获取上次访问时间戳
$now = Carbon::now();
if ($lastSeenAt != null) {
$duration = $now->diffInSeconds($lastSeenAt); // 计算在线时长(秒数)
$user->increment('spent', $duration, ['updated_at' => $user->updated_at, 'onlined_at' => $now]); //updated_at 维持原值
}
Cache::put($seenKey . $user->id, $now, Carbon::now()->addMinutes(1)); // 保存当前访问时间戳(并设置缓存过期时间为一分钟)
}
return $next($request);
}
}
👆 此处没有用使用 DB facade 来避免更新用户表的 {更新时间} 字段,而用 increment 函数的第二个参数来维持 updated_at 值不变。
应用中间件
- 在 \app\Http\Kernel.php 中添加一个 $routeMiddleware
protected $routeMiddleware = [
//其它
'admin.spent' => \App\Http\Middleware\CountAdminUserOnlineTime::class,
//其它
];
- 如果你用的是 dcat-admin 后台框架,可以在 config/admin.php 的 route 配置里直接附加 middleware:
//如果你用的是 dcat-admin 后台框架,可以在 config/admin.php 的 route 配置里直接附加 middleware:
'middleware' => ['web', 'admin'], // 默认值:
'middleware' => ['web', 'admin', 'admin.spent'], //添加在线时长中间件
//其它情况: 在路由定义里添加:
Route::middleware([/* 其它中间件*/ , 'admin.spent'])->group(
function () {
//... 需要统计的路由
});
dcat-admin 在概览页面展示用户时长(可选)
//新建一个 AdminUser 模型继承默认的 Administrator
<?php
namespace App\Models;
use Dcat\Admin\Models\Administrator;
class AdminUser extends Administrator
{
}
//在线时间表格
use Carbon\Carbon;
use Dcat\Admin\Widgets\Callout;
use Dcat\Admin\Widgets\Tab;
use Dcat\Admin\Widgets\Table;
...
public static function tab()
{
$data = AdminUser::query()
->orderBy('onlined_at', 'DESC')
->get(['name', 'onlined_at', 'spent'])
->toArray();
foreach ($data as &$d) {
if (!$d['spent']) {
$d['spent'] = '-';
} else {
$d['spent'] = formatTime($d['spent']);
}
if (Carbon::parse($d['onlined_at'])->diffInMinutes() <= 5) {
$d['name'] = '<i class="fa fa-circle" style="font-size: 13px;color: #4e9876"></i> ' . $d['name'];
} else {
$d['name'] = '<i class="fa fa-circle" style="font-size: 13px;color: #7c858e
"></i> ' . $d['name'];
}
}
$titles = ['管理员', '最后在线', '总在线时长'];
return Tab::make()
->padding(0)
->add('业务信息',
Callout::make('后台用户(最近登录)')->success() . Table::make($titles, $data)
);
}
//公共函数库增加 formatTime
/**
* 将给定秒数转换为以“x天x时x分钟”形式
* e.g. 123456 => 1天10时17分钟
*/
function formatTime($seconds)
{
$days = floor($seconds / 86400);
$hours = floor(($seconds % 86400) / 3600);
$minutes = floor(($seconds % 3600) / 60);
$result = "";
if ($days > 0) {
$result .= "{$days}天";
}
if ($hours > 0) {
$result .= "{$hours}时";
}
if ($minutes > 0) {
$result .= "{$minutes}分钟";
}
return $result;
}
统计结果示例
原文发表于:https://learnku.com/articles/76349