Laravel中介軟體統計使用者線上時長

mouc發表於2023-03-30

Laravel — 瞭解使用者上次線上的時間以及總計線上時長

此處以統計後臺使用者(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(); // 獲取當前認證使用者
        //dd($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:

'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>&ensp;' . $d['name'];

            } else {
                $d['name'] = '<i class="fa fa-circle" style="font-size: 13px;color: #7c858e
"></i>&ensp;' . $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;

}

統計結果示例

Laravel中介軟體統計使用者線上時長

本作品採用《CC 協議》,轉載必須註明作者和本文連結
種菜養魚歸山林

相關文章