Sfoglia il codice sorgente

Merge pull request #2344 from SSPanel-UIM/dev

Dev 20240127
M1Screw 1 anno fa
parent
commit
ae040a046f

+ 2 - 3
app/routes.php

@@ -80,6 +80,8 @@ return static function (Slim\App $app): void {
         $group->post('/switch_theme_mode', App\Controllers\UserController::class . ':switchThemeMode');
         // 订阅记录
         $group->get('/subscribe', App\Controllers\User\SubLogController::class . ':index');
+        // 流量记录
+        $group->get('/traffic', App\Controllers\User\TrafficLogController::class . ':index');
         // 账户余额
         $group->get('/money', App\Controllers\User\MoneyController::class . ':index');
         $group->post('/giftcard', App\Controllers\User\MoneyController::class . ':applyGiftCard');
@@ -216,9 +218,6 @@ return static function (Slim\App $app): void {
         // 返利日志
         $group->get('/payback', App\Controllers\Admin\PaybackController::class . ':index');
         $group->post('/payback/ajax', App\Controllers\Admin\PaybackController::class . ':ajax');
-        // 流量日志
-        $group->get('/traffic', App\Controllers\Admin\TrafficLogController::class . ':index');
-        $group->post('/traffic/ajax', App\Controllers\Admin\TrafficLogController::class . ':ajax');
         // 用户余额日志
         $group->get('/money', App\Controllers\Admin\MoneyLogController::class . ':index');
         $group->post('/money/ajax', App\Controllers\Admin\MoneyLogController::class . ':ajax');

+ 58 - 58
composer.lock

@@ -123,16 +123,16 @@
         },
         {
             "name": "aws/aws-sdk-php",
-            "version": "3.296.6",
+            "version": "3.297.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/aws/aws-sdk-php.git",
-                "reference": "11d0a94f8b2539d587e2f6db7c2fa8e39fe78a67"
+                "reference": "bbf516a4a88f829f92cc396628be705966880dbd"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/11d0a94f8b2539d587e2f6db7c2fa8e39fe78a67",
-                "reference": "11d0a94f8b2539d587e2f6db7c2fa8e39fe78a67",
+                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/bbf516a4a88f829f92cc396628be705966880dbd",
+                "reference": "bbf516a4a88f829f92cc396628be705966880dbd",
                 "shasum": ""
             },
             "require": {
@@ -212,9 +212,9 @@
             "support": {
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
-                "source": "https://github.com/aws/aws-sdk-php/tree/3.296.6"
+                "source": "https://github.com/aws/aws-sdk-php/tree/3.297.2"
             },
-            "time": "2024-01-19T19:14:55+00:00"
+            "time": "2024-01-26T19:09:20+00:00"
         },
         {
             "name": "bacon/bacon-qr-code",
@@ -1200,16 +1200,16 @@
         },
         {
             "name": "illuminate/collections",
-            "version": "v10.41.0",
+            "version": "v10.42.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/illuminate/collections.git",
-                "reference": "82025fd7ac761cc50d5dbd9f9532ebf066821858"
+                "reference": "221c1ee944cb20ed807a8a5e8668552d6ca736ff"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/illuminate/collections/zipball/82025fd7ac761cc50d5dbd9f9532ebf066821858",
-                "reference": "82025fd7ac761cc50d5dbd9f9532ebf066821858",
+                "url": "https://api.github.com/repos/illuminate/collections/zipball/221c1ee944cb20ed807a8a5e8668552d6ca736ff",
+                "reference": "221c1ee944cb20ed807a8a5e8668552d6ca736ff",
                 "shasum": ""
             },
             "require": {
@@ -1251,11 +1251,11 @@
                 "issues": "https://github.com/laravel/framework/issues",
                 "source": "https://github.com/laravel/framework"
             },
-            "time": "2024-01-01T15:17:18+00:00"
+            "time": "2024-01-22T13:55:20+00:00"
         },
         {
             "name": "illuminate/conditionable",
-            "version": "v10.41.0",
+            "version": "v10.42.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/illuminate/conditionable.git",
@@ -1301,7 +1301,7 @@
         },
         {
             "name": "illuminate/container",
-            "version": "v10.41.0",
+            "version": "v10.42.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/illuminate/container.git",
@@ -1352,7 +1352,7 @@
         },
         {
             "name": "illuminate/contracts",
-            "version": "v10.41.0",
+            "version": "v10.42.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/illuminate/contracts.git",
@@ -1400,7 +1400,7 @@
         },
         {
             "name": "illuminate/database",
-            "version": "v10.41.0",
+            "version": "v10.42.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/illuminate/database.git",
@@ -1473,7 +1473,7 @@
         },
         {
             "name": "illuminate/macroable",
-            "version": "v10.41.0",
+            "version": "v10.42.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/illuminate/macroable.git",
@@ -1519,7 +1519,7 @@
         },
         {
             "name": "illuminate/pagination",
-            "version": "v10.41.0",
+            "version": "v10.42.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/illuminate/pagination.git",
@@ -1569,16 +1569,16 @@
         },
         {
             "name": "illuminate/support",
-            "version": "v10.41.0",
+            "version": "v10.42.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/illuminate/support.git",
-                "reference": "1355b7d28ebb802e95bffcb27417862961382c52"
+                "reference": "11a87daf9c4bef3d654c853161b34e11a6ca0618"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/illuminate/support/zipball/1355b7d28ebb802e95bffcb27417862961382c52",
-                "reference": "1355b7d28ebb802e95bffcb27417862961382c52",
+                "url": "https://api.github.com/repos/illuminate/support/zipball/11a87daf9c4bef3d654c853161b34e11a6ca0618",
+                "reference": "11a87daf9c4bef3d654c853161b34e11a6ca0618",
                 "shasum": ""
             },
             "require": {
@@ -1636,7 +1636,7 @@
                 "issues": "https://github.com/laravel/framework/issues",
                 "source": "https://github.com/laravel/framework"
             },
-            "time": "2024-01-15T18:53:10+00:00"
+            "time": "2024-01-22T18:45:06+00:00"
         },
         {
             "name": "irazasyed/telegram-bot-sdk",
@@ -2150,16 +2150,16 @@
         },
         {
             "name": "moneyphp/money",
-            "version": "v4.3.0",
+            "version": "v4.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/moneyphp/money.git",
-                "reference": "50ddfd15b2be01d4bed3bcb0c975a6af5f78a183"
+                "reference": "5e60aebf09f709dd4ea16bf85e66d65301c0d172"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/moneyphp/money/zipball/50ddfd15b2be01d4bed3bcb0c975a6af5f78a183",
-                "reference": "50ddfd15b2be01d4bed3bcb0c975a6af5f78a183",
+                "url": "https://api.github.com/repos/moneyphp/money/zipball/5e60aebf09f709dd4ea16bf85e66d65301c0d172",
+                "reference": "5e60aebf09f709dd4ea16bf85e66d65301c0d172",
                 "shasum": ""
             },
             "require": {
@@ -2183,7 +2183,7 @@
                 "phpbench/phpbench": "^1.2.5",
                 "phpunit/phpunit": "^9.5.4",
                 "psalm/plugin-phpunit": "^0.18.4",
-                "psr/cache": "^1.0.1",
+                "psr/cache": "^1.0.1 || ^2.0 || ^3.0",
                 "vimeo/psalm": "~5.15.0"
             },
             "suggest": {
@@ -2232,9 +2232,9 @@
             ],
             "support": {
                 "issues": "https://github.com/moneyphp/money/issues",
-                "source": "https://github.com/moneyphp/money/tree/v4.3.0"
+                "source": "https://github.com/moneyphp/money/tree/v4.4.0"
             },
-            "time": "2023-11-22T09:46:30+00:00"
+            "time": "2024-01-24T08:29:16+00:00"
         },
         {
             "name": "mtdowling/jmespath.php",
@@ -2304,16 +2304,16 @@
         },
         {
             "name": "nesbot/carbon",
-            "version": "2.72.1",
+            "version": "2.72.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/briannesbitt/Carbon.git",
-                "reference": "2b3b3db0a2d0556a177392ff1a3bf5608fa09f78"
+                "reference": "3e7edc41b58d65509baeb0d4a14c8fa41d627130"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/2b3b3db0a2d0556a177392ff1a3bf5608fa09f78",
-                "reference": "2b3b3db0a2d0556a177392ff1a3bf5608fa09f78",
+                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/3e7edc41b58d65509baeb0d4a14c8fa41d627130",
+                "reference": "3e7edc41b58d65509baeb0d4a14c8fa41d627130",
                 "shasum": ""
             },
             "require": {
@@ -2407,7 +2407,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-12-08T23:47:49+00:00"
+            "time": "2024-01-19T00:21:53+00:00"
         },
         {
             "name": "nikic/fast-route",
@@ -2621,21 +2621,21 @@
         },
         {
             "name": "openai-php/client",
-            "version": "v0.8.1",
+            "version": "v0.8.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/openai-php/client.git",
-                "reference": "ce84f541fe8a2869de7f48030d5757be1fd604c9"
+                "reference": "081ea0b0096d5788ae1d4f8e2e4c82d7f68dccb7"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/openai-php/client/zipball/ce84f541fe8a2869de7f48030d5757be1fd604c9",
-                "reference": "ce84f541fe8a2869de7f48030d5757be1fd604c9",
+                "url": "https://api.github.com/repos/openai-php/client/zipball/081ea0b0096d5788ae1d4f8e2e4c82d7f68dccb7",
+                "reference": "081ea0b0096d5788ae1d4f8e2e4c82d7f68dccb7",
                 "shasum": ""
             },
             "require": {
                 "php": "^8.1.0",
-                "php-http/discovery": "^1.19.1",
+                "php-http/discovery": "^1.19.2",
                 "php-http/multipart-stream-builder": "^1.3.0",
                 "psr/http-client": "^1.0.3",
                 "psr/http-client-implementation": "^1.0.1",
@@ -2648,12 +2648,12 @@
                 "laravel/pint": "^1.13.7",
                 "mockery/mockery": "^1.6.7",
                 "nunomaduro/collision": "^7.10.0",
-                "pestphp/pest": "^2.28.1",
-                "pestphp/pest-plugin-arch": "^2.5",
-                "pestphp/pest-plugin-type-coverage": "^2.5.0",
-                "phpstan/phpstan": "^1.10.50",
+                "pestphp/pest": "^2.30.0",
+                "pestphp/pest-plugin-arch": "^2.6",
+                "pestphp/pest-plugin-type-coverage": "^2.7.0",
+                "phpstan/phpstan": "^1.10.55",
                 "rector/rector": "^0.16.0",
-                "symfony/var-dumper": "^6.4"
+                "symfony/var-dumper": "^6.4.2"
             },
             "type": "library",
             "autoload": {
@@ -2693,7 +2693,7 @@
             ],
             "support": {
                 "issues": "https://github.com/openai-php/client/issues",
-                "source": "https://github.com/openai-php/client/tree/v0.8.1"
+                "source": "https://github.com/openai-php/client/tree/v0.8.2"
             },
             "funding": [
                 {
@@ -2709,7 +2709,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2023-12-22T15:18:26+00:00"
+            "time": "2024-01-26T08:20:30+00:00"
         },
         {
             "name": "ozdemir/datatables",
@@ -4326,16 +4326,16 @@
         },
         {
             "name": "sentry/sentry",
-            "version": "4.3.1",
+            "version": "4.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/getsentry/sentry-php.git",
-                "reference": "cd89f230bda0833cb9992ebe9a1b7d24d6ee245b"
+                "reference": "95a428a59ebddf786a27f09d19ec395a32f62082"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/cd89f230bda0833cb9992ebe9a1b7d24d6ee245b",
-                "reference": "cd89f230bda0833cb9992ebe9a1b7d24d6ee245b",
+                "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/95a428a59ebddf786a27f09d19ec395a32f62082",
+                "reference": "95a428a59ebddf786a27f09d19ec395a32f62082",
                 "shasum": ""
             },
             "require": {
@@ -4399,7 +4399,7 @@
             ],
             "support": {
                 "issues": "https://github.com/getsentry/sentry-php/issues",
-                "source": "https://github.com/getsentry/sentry-php/tree/4.3.1"
+                "source": "https://github.com/getsentry/sentry-php/tree/4.4.0"
             },
             "funding": [
                 {
@@ -4411,7 +4411,7 @@
                     "type": "custom"
                 }
             ],
-            "time": "2023-12-22T18:46:49+00:00"
+            "time": "2024-01-23T09:49:55+00:00"
         },
         {
             "name": "slim/http",
@@ -4607,16 +4607,16 @@
         },
         {
             "name": "smarty/smarty",
-            "version": "v4.3.4",
+            "version": "v4.3.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/smarty-php/smarty.git",
-                "reference": "3931d8f54b8f7a4ffab538582d34d4397ba8daa5"
+                "reference": "e0cbbdf6ea21768d0194e59d2f8c2e20d5f0868c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/smarty-php/smarty/zipball/3931d8f54b8f7a4ffab538582d34d4397ba8daa5",
-                "reference": "3931d8f54b8f7a4ffab538582d34d4397ba8daa5",
+                "url": "https://api.github.com/repos/smarty-php/smarty/zipball/e0cbbdf6ea21768d0194e59d2f8c2e20d5f0868c",
+                "reference": "e0cbbdf6ea21768d0194e59d2f8c2e20d5f0868c",
                 "shasum": ""
             },
             "require": {
@@ -4667,9 +4667,9 @@
             "support": {
                 "forum": "https://github.com/smarty-php/smarty/discussions",
                 "issues": "https://github.com/smarty-php/smarty/issues",
-                "source": "https://github.com/smarty-php/smarty/tree/v4.3.4"
+                "source": "https://github.com/smarty-php/smarty/tree/v4.3.5"
             },
-            "time": "2023-09-14T10:59:08+00:00"
+            "time": "2024-01-23T10:47:54+00:00"
         },
         {
             "name": "srmklive/paypal",

+ 0 - 5
config/.config.example.php

@@ -54,11 +54,6 @@ $_ENV['mail_filter']        = 0;            //0: 关闭; 1: 白名单模式; 2;
 $_ENV['mail_filter_list']   = [];
 
 //已注册用户设置---------------------------------------------------------------------------------------
-#基础
-$_ENV['enable_checkin']             = true;         //是否啓用簽到功能
-$_ENV['checkinMin']                 = 1;            //用户签到最少流量 单位MB
-$_ENV['checkinMax']                 = 50;           //用户签到最多流量
-
 #高级
 $_ENV['class_expire_reset_traffic'] = 0;            //等级到期时重置为的流量值,单位GB,小于0时不重置
 $_ENV['enable_kill']                = true;         //是否允许用户注销账户

+ 30 - 0
config/settings.json

@@ -1429,6 +1429,36 @@
         "default": "0",
         "mark": "通知用户新IP登录"
     },
+    {
+        "id": null,
+        "item": "enable_checkin",
+        "value": "0",
+        "class": "feature",
+        "is_public": 1,
+        "type": "bool",
+        "default": "0",
+        "mark": "签到开关"
+    },
+    {
+        "id": null,
+        "item": "checkin_min",
+        "value": "1",
+        "class": "feature",
+        "is_public": 1,
+        "type": "int",
+        "default": "1",
+        "mark": "签到最少流量"
+    },
+    {
+        "id": null,
+        "item": "checkin_max",
+        "value": "50",
+        "class": "feature",
+        "is_public": 1,
+        "type": "int",
+        "default": "50",
+        "mark": "签到最多流量"
+    },
     {
         "id": null,
         "item": "enable_forced_replacement",

+ 9 - 10
db/migrations/2023020100-init.php

@@ -92,6 +92,15 @@ return new class() implements MigrationInterface {
                 KEY `id` (`id`),
                 KEY `status` (`status`)
             ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+            
+            CREATE TABLE `hourly_usage` (
+                `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '记录ID',
+                `user_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '用户ID',
+                `date` date NOT NULL DEFAULT 0 COMMENT '记录日期',
+                `usage` longtext NOT NULL DEFAULT '{}' COMMENT '流量用量' CHECK (json_valid(`usage`)),
+                PRIMARY KEY (`id`),
+                KEY `user_id` (`user_id`)
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
 
             CREATE TABLE `invoice` (
                 `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '账单ID',
@@ -332,16 +341,6 @@ return new class() implements MigrationInterface {
                 KEY `expire_time` (`expire_time`)
             ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
 
-            CREATE TABLE `user_hourly_usage` (
-                `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '记录ID',
-                `user_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '用户ID',
-                `traffic` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '当前总流量',
-                `hourly_usage` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '过去一小时流量',
-                `datetime` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '记录时间',
-                PRIMARY KEY (`id`),
-                KEY `user_id` (`user_id`)
-            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-
             CREATE TABLE `user_invite_code` (
                 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '记录ID',
                 `code` varchar(255) NOT NULL DEFAULT '' COMMENT '邀请码',

+ 43 - 0
db/migrations/2024012700-add_hourly_usage.php

@@ -0,0 +1,43 @@
+<?php
+
+declare(strict_types=1);
+
+use App\Interfaces\MigrationInterface;
+use App\Services\DB;
+
+return new class() implements MigrationInterface {
+    public function up(): int
+    {
+        DB::getPdo()->exec("
+            CREATE TABLE IF NOT EXISTS `hourly_usage` (
+                `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '记录ID',
+                `user_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '用户ID',
+                `date` date NOT NULL DEFAULT 0 COMMENT '记录日期',
+                `usage` longtext NOT NULL DEFAULT '{}' COMMENT '流量用量' CHECK (json_valid(`usage`)),
+                PRIMARY KEY (`id`),
+                KEY `user_id` (`user_id`)
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+            DROP TABLE IF EXISTS `user_hourly_usage`;
+        ");
+
+        return 2024012700;
+    }
+
+    public function down(): int
+    {
+        DB::getPdo()->exec("
+            CREATE TABLE IF NOT EXISTS `user_hourly_usage` (
+                `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '记录ID',
+                `user_id` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '用户ID',
+                `traffic` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '当前总流量',
+                `hourly_usage` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '过去一小时流量',
+                `datetime` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '记录时间',
+                PRIMARY KEY (`id`),
+                KEY `user_id` (`user_id`)
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+            DROP TABLE IF EXISTS `hourly_usage`;
+        ");
+
+        return 2024012300;
+    }
+};

+ 0 - 4
resources/views/tabler/admin/header.tpl

@@ -205,10 +205,6 @@
                                     <i class="ti ti-router"></i>&nbsp;
                                     在线IP
                                 </a>
-                                <a class="dropdown-item" href="/admin/traffic">
-                                    <i class="ti ti-arrows-up-down"></i>&nbsp;
-                                    流量使用
-                                </a>
                             </div>
                         </li>
                         <li class="nav-item dropdown">

+ 0 - 99
resources/views/tabler/admin/log/traffic.tpl

@@ -1,99 +0,0 @@
-{include file='admin/header.tpl'}
-
-<div class="page-wrapper">
-    <div class="container-xl">
-        <div class="page-header d-print-none text-white">
-            <div class="row align-items-center">
-                <div class="col">
-                    <h2 class="page-title">
-                        <span class="home-title">流量记录</span>
-                    </h2>
-                    <div class="page-pretitle my-3">
-                        <span class="home-subtitle">查看用户每小时使用流量记录</span>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-    <div class="page-body">
-        <div class="container-xl">
-            <div class="row row-deck row-cards">
-                <div class="col-12">
-                    <div class="card">
-                        <div class="table-responsive">
-                            <table id="data-table" class="table card-table table-vcenter text-nowrap datatable">
-                                <thead>
-                                <tr>
-                                    {foreach $details['field'] as $key => $value}
-                                        <th>{$value}</th>
-                                    {/foreach}
-                                </tr>
-                                </thead>
-                            </table>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-
-    <script>
-        let table = new DataTable('#data-table', {
-            "serverSide": true,
-            "searching": true,
-            "ordering": true,
-            ajax: {
-                url: '/admin/traffic/ajax',
-                type: 'POST',
-                dataSrc: 'trafficlogs.data'
-            },
-            "autoWidth": false,
-            'iDisplayLength': 10,
-            'scrollX': true,
-            'order': [
-                [0, 'desc']
-            ],
-            columns: [
-                {foreach $details['field'] as $key => $value}
-                {
-                    data: '{$key}'
-                },
-                {/foreach}
-            ],
-            "dom": "<'row px-3 py-3'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>>" +
-                "<'row'<'col-sm-12'tr>>" +
-                "<'row card-footer d-flex d-flexalign-items-center'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
-            language: {
-                "sProcessing": "处理中...",
-                "sLengthMenu": "显示 _MENU_ 条",
-                "sZeroRecords": "没有匹配结果",
-                "sInfo": "第 _START_ 至 _END_ 项结果,共 _TOTAL_项",
-                "sInfoEmpty": "第 0 至 0 项结果,共 0 项",
-                "sInfoFiltered": "(在 _MAX_ 项中查找)",
-                "sInfoPostFix": "",
-                "sSearch": "<i class=\"ti ti-search\"></i> ",
-                "sUrl": "",
-                "sEmptyTable": "表中数据为空",
-                "sLoadingRecords": "载入中...",
-                "sInfoThousands": ",",
-                "oPaginate": {
-                    "sFirst": "首页",
-                    "sPrevious": "<i class=\"titi-arrow-left\"></i>",
-                    "sNext": "<i class=\"ti ti-arrow-right\"><i>",
-                    "sLast": "末页"
-                },
-                "oAria": {
-                    "sSortAscending": ": 以升序排列此列",
-                    "sSortDescending": ": 以降序排列此列"
-                }
-            },
-        });
-
-        function loadTable() {
-            table;
-        }
-
-        loadTable();
-    </script>
-
-    {include file='admin/footer.tpl'}

+ 35 - 0
resources/views/tabler/admin/setting/feature.tpl

@@ -36,6 +36,9 @@
                                 <li class="nav-item">
                                     <a href="#log" class="nav-link" data-bs-toggle="tab">用户日志</a>
                                 </li>
+                                <li class="nav-item">
+                                    <a href="#checkin" class="nav-link" data-bs-toggle="tab">签到</a>
+                                </li>
                             </ul>
                         </div>
                         <div class="card-body">
@@ -173,6 +176,38 @@
                                         </div>
                                     </div>
                                 </div>
+                                <div class="tab-pane" id="checkin">
+                                    <div class="card-body">
+                                        <div class="form-group mb-3 row">
+                                            <label class="form-label col-3 col-form-label">启用签到</label>
+                                            <div class="col">
+                                                <select id="enable_checkin" class="col form-select"
+                                                        value="{$settings['enable_checkin']}">
+                                                    <option value="0" {if ! $settings['enable_checkin']}selected{/if}>
+                                                        关闭
+                                                    </option>
+                                                    <option value="1" {if $settings['enable_checkin']}selected{/if}>开启
+                                                    </option>
+                                                </select>
+                                            </div>
+                                        </div>
+                                        <div class="form-group mb-3 row">
+                                            <label class="form-label col-3 col-form-label">签到最少流量(MB)</label>
+                                            <div class="col">
+                                                <input id="checkin_min" type="text" class="form-control"
+                                                       value="{$settings['checkin_min']}">
+                                            </div>
+                                        </div>
+                                        <div class="form-group mb-3 row">
+                                            <label class="form-label col-3 col-form-label">签到最多流量(MB)</label>
+                                            <div class="col">
+                                                <input id="checkin_max" type="text"
+                                                       class="form-control"
+                                                       value="{$settings['checkin_max']}">
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
                             </div>
                         </div>
                     </div>

+ 8 - 2
resources/views/tabler/user/header.tpl

@@ -105,8 +105,14 @@
                                         </a>
                                         {if $public_setting['subscribe_log']}
                                             <a class="dropdown-item" href="/user/subscribe">
-                                                <i class="ti ti-rss"></i></i>&nbsp;
-                                                订阅
+                                                <i class="ti ti-rss"></i>&nbsp;
+                                                订阅日志
+                                            </a>
+                                        {/if}
+                                        {if $public_setting['traffic_log']}
+                                            <a class="dropdown-item" href="/user/traffic">
+                                                <i class="ti ti-traffic-lights"></i>&nbsp;
+                                                流量日志
                                             </a>
                                         {/if}
                                         <a class="dropdown-item" href="/user/invite">

+ 5 - 5
resources/views/tabler/user/index.tpl

@@ -531,7 +531,7 @@
                         </div>
                     </div>
                 </div>
-                {if $config['enable_checkin']}
+                {if $public_setting['enable_checkin']}
                     <div class="col-lg-6 col-sm-12">
                         <div class="card">
                             <div class="card-stamp">
@@ -543,14 +543,14 @@
                                 <h3 class="card-title">每日签到</h3>
                                 <p>
                                     签到可领取
-                                    {if $config['checkinMin'] !== $config['checkinMax']}
+                                    {if $public_setting['checkin_min'] !== $public_setting['checkin_max']}
                                         &nbsp;
-                                        <code>{$config['checkinMin']} MB</code>
+                                        <code>{$public_setting['checkin_min']} MB</code>
-                                        <code>{$config['checkinMax']} MB</code>
+                                        <code>{$public_setting['checkin_max']} MB</code>
                                         范围内的流量
                                     {else}
-                                        <code>{$config['checkinMin']} MB</code>
+                                        <code>{$public_setting['checkin_min']} MB</code>
                                     {/if}
                                 </p>
                                 <p>

+ 132 - 0
resources/views/tabler/user/traffic_log.tpl

@@ -0,0 +1,132 @@
+{include file='user/header.tpl'}
+
+<div class="page-wrapper">
+    <div class="container-xl">
+        <div class="page-header d-print-none text-white">
+            <div class="row align-items-center">
+                <div class="col">
+                    <h2 class="page-title">
+                        <span class="home-title">流量记录</span>
+                    </h2>
+                    <div class="page-pretitle my-3">
+                        <span class="home-subtitle">本日内的流量使用记录</span>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <div class="page-body">
+        <div class="container-xl">
+            <div class="row row-deck row-cards">
+                <div class="col-sm-12 col-lg-12">
+                    <div class="card">
+                        <div class="card-body">
+                            <div id="traffic-log"></div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <script>
+        document.addEventListener("DOMContentLoaded", function () {
+            let chart = window.ApexCharts && new ApexCharts(document.getElementById('traffic-log'), {
+                chart: {
+                    type: "line",
+                    fontFamily: "inherit",
+                    height: '250%',
+                    parentHeightOffset: 0,
+                    toolbar: {
+                        show: false
+                    },
+                    animations: {
+                        enabled: false
+                    }
+                },
+                stroke: {
+                    curve: "smooth"
+                },
+                fill: {
+                    opacity: 1
+                },
+                series: [
+                    {
+                        name: "使用流量(MB)",
+                        data: {$logs}
+                    }
+                ],
+                tooltip: {
+                    theme: "dark"
+                },
+                grid: {
+                    padding: {
+                        top: -20,
+                        right: 0,
+                        left: 0,
+                        bottom: 0
+                    },
+                    strokeDashArray: 4
+                },
+                xaxis: {
+                    title: {
+                        text: "小时"
+                    },
+                    labels: {
+                        padding: 0
+                    },
+                    tooltip: {
+                        enabled: false
+                    },
+                    axisBorder: {
+                        show: false
+                    },
+                    categories: [
+                        "00",
+                        "01",
+                        "02",
+                        "03",
+                        "04",
+                        "05",
+                        "06",
+                        "07",
+                        "08",
+                        "09",
+                        "10",
+                        "11",
+                        "12",
+                        "13",
+                        "14",
+                        "15",
+                        "16",
+                        "17",
+                        "18",
+                        "19",
+                        "20",
+                        "21",
+                        "22",
+                        "23"
+                    ]
+                },
+                yaxis: {
+                    title: {
+                        text: "使用流量(MB)",
+                        rotate: -90
+                    },
+                    labels: {
+                        padding: 14
+                    }
+                },
+                colors: [tabler.getColor("azure")],
+                legend: {
+                    show: false
+                }
+            });
+            chart.render();
+        });
+    </script>
+
+    <script src="//{$config['jsdelivr_url']}/npm/@tabler/core@latest/dist/libs/apexcharts/dist/apexcharts.min.js"></script>
+
+{include file='user/footer.tpl'}

+ 0 - 5
src/Command/Cron.php

@@ -49,11 +49,6 @@ EOL;
             $jobs->detectNodeOffline();
         }
 
-        // Run traffic log job
-        if ($minute === 0 && Config::obtain('traffic_log')) {
-            $jobs->addTrafficLog();
-        }
-
         // Run daily job
         if ($hour === Config::obtain('daily_job_hour') &&
             $minute === Config::obtain('daily_job_minute') &&

+ 3 - 0
src/Controllers/Admin/Setting/FeatureController.php

@@ -21,6 +21,9 @@ final class FeatureController extends BaseController
         'notify_new_subscribe',
         'login_log',
         'notify_new_login',
+        'enable_checkin',
+        'checkin_min',
+        'checkin_max',
     ];
 
     /**

+ 0 - 87
src/Controllers/Admin/TrafficLogController.php

@@ -1,87 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace App\Controllers\Admin;
-
-use App\Controllers\BaseController;
-use App\Models\UserHourlyUsage;
-use App\Utils\Tools;
-use Exception;
-use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Response;
-use Slim\Http\ServerRequest;
-
-final class TrafficLogController extends BaseController
-{
-    private static array $details =
-        [
-            'field' => [
-                'id' => '记录ID',
-                'user_id' => '用户ID',
-                'traffic' => '累计流量/GB',
-                'hourly_usage' => '过去一小时使用流量/GB',
-                'datetime' => '时间',
-            ],
-        ];
-
-    /**
-     * 后台流量记录页面
-     *
-     * @throws Exception
-     */
-    public function index(ServerRequest $request, Response $response, array $args): ResponseInterface
-    {
-        return $response->write(
-            $this->view()
-                ->assign('details', self::$details)
-                ->fetch('admin/log/traffic.tpl')
-        );
-    }
-
-    /**
-     * 后台流量记录页面 AJAX
-     */
-    public function ajax(ServerRequest $request, Response $response, array $args): ResponseInterface
-    {
-        $length = $request->getParam('length');
-        $page = $request->getParam('start') / $length + 1;
-        $draw = $request->getParam('draw');
-
-        $traffic_log = UserHourlyUsage::query();
-
-        $search = $request->getParam('search')['value'];
-
-        if ($search !== '') {
-            $traffic_log->where('user_id', '=', $search);
-        }
-
-        $order = $request->getParam('order')[0]['dir'];
-
-        if ($request->getParam('order')[0]['column'] !== '0') {
-            $order_by = $request->getParam('columns')[$request->getParam('order')[0]['column']]['data'];
-
-            $traffic_log->orderBy($order_by, $order)->orderBy('id', 'desc');
-        } else {
-            $traffic_log->orderBy('id', $order);
-        }
-
-        $filtered = $traffic_log->count();
-        $total = (new UserHourlyUsage())->count();
-
-        $trafficlogs = $traffic_log->paginate($length, '*', '', $page);
-
-        foreach ($trafficlogs as $trafficlog) {
-            $trafficlog->traffic = Tools::flowToGB($trafficlog->traffic);
-            $trafficlog->hourly_usage = Tools::flowToGB($trafficlog->hourly_usage);
-            $trafficlog->datetime = Tools::toDateTime((int) $trafficlog->datetime);
-        }
-
-        return $response->withJson([
-            'draw' => $draw,
-            'recordsTotal' => $total,
-            'recordsFiltered' => $filtered,
-            'trafficlogs' => $trafficlogs,
-        ]);
-    }
-}

+ 4 - 0
src/Controllers/User/DetectLogController.php

@@ -21,6 +21,10 @@ final class DetectLogController extends BaseController
      */
     public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
+        if (! Config::obtain('display_detect_log')) {
+            return $response->withRedirect('/user');
+        }
+
         $logs = (new DetectLog())->orderBy('id', 'desc')->where('user_id', $this->user->id)->get();
 
         foreach ($logs as $log) {

+ 4 - 0
src/Controllers/User/SubLogController.php

@@ -22,6 +22,10 @@ final class SubLogController extends BaseController
      */
     public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
+        if (! Config::obtain('subscribe_log')) {
+            return $response->withRedirect('/user');
+        }
+
         $logs = (new SubscribeLog())->orderBy('id', 'desc')->where('user_id', $this->user->id)->get();
 
         foreach ($logs as $log) {

+ 41 - 0
src/Controllers/User/TrafficLogController.php

@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Controllers\User;
+
+use App\Controllers\BaseController;
+use App\Models\Config;
+use App\Services\Analytics;
+use App\Utils\Tools;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
+use Slim\Http\Response;
+use Slim\Http\ServerRequest;
+use function json_encode;
+
+final class TrafficLogController extends BaseController
+{
+    /**
+     * 订阅记录
+     *
+     * @throws Exception
+     */
+    public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    {
+        if (! Config::obtain('traffic_log')) {
+            return $response->withRedirect('/user');
+        }
+
+        $logs = [];
+        $hourly_usage = Analytics::getUserTodayHourlyUsage($this->user->id);
+
+        foreach ($hourly_usage as $hour => $usage) {
+            $logs[] = Tools::flowToMB((int) $usage);
+        }
+
+        return $response->write($this->view()
+            ->assign('logs', json_encode($logs))
+            ->fetch('user/traffic_log.tpl'));
+    }
+}

+ 7 - 6
src/Controllers/UserController.php

@@ -13,6 +13,7 @@ use App\Models\OnlineLog;
 use App\Models\Payback;
 use App\Services\Auth;
 use App\Services\Captcha;
+use App\Services\Reward;
 use App\Services\Subscribe;
 use App\Utils\ResponseHelper;
 use App\Utils\Tools;
@@ -139,7 +140,7 @@ final class UserController extends BaseController
 
     public function checkin(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
-        if (! $_ENV['enable_checkin']) {
+        if (! Config::obtain('enable_checkin') || ! $this->user->isAbleToCheckin()) {
             return ResponseHelper::error($response, '暂时还不能签到');
         }
 
@@ -151,17 +152,17 @@ final class UserController extends BaseController
             }
         }
 
-        $checkin = $this->user->checkin();
+        $traffic = Reward::issueCheckinReward($this->user->id);
 
-        if (! $checkin['ok']) {
-            return ResponseHelper::error($response, (string) $checkin['msg']);
+        if (! $traffic) {
+            return ResponseHelper::error($response, '签到失败');
         }
 
         return $response->withJson([
             'ret' => 1,
-            'msg' => $checkin['msg'],
+            'msg' => '获得了 ' . $traffic . 'MB 流量',
             'data' => [
-                'last-checkin-time' => $this->user->lastCheckInTime(),
+                'last-checkin-time' => Tools::toDateTime(time()),
             ],
         ]);
     }

+ 8 - 1
src/Controllers/WebAPI/UserController.php

@@ -5,7 +5,9 @@ declare(strict_types=1);
 namespace App\Controllers\WebAPI;
 
 use App\Controllers\BaseController;
+use App\Models\Config;
 use App\Models\DetectLog;
+use App\Models\HourlyUsage;
 use App\Models\Node;
 use App\Services\DB;
 use App\Services\DynamicRate;
@@ -204,6 +206,7 @@ final class UserController extends BaseController
         }
 
         $sum = 0;
+        $is_traffic_log = Config::obtain('traffic_log');
 
         foreach ($data as $log) {
             $u = $log?->u;
@@ -211,7 +214,11 @@ final class UserController extends BaseController
             $user_id = $log?->user_id;
 
             if ($user_id) {
-                $stat->execute([(int) ($u * $rate), (int) ($d * $rate), (int) ($u + $d), (int) ($u + $d), $user_id]);
+                $stat->execute([(int) ($u * $rate), (int) ($d * $rate), (int) ($u + $d), (int) ($u + $d), (int) $user_id]);
+            }
+
+            if ($is_traffic_log) {
+                (new HourlyUsage())->add((int) $user_id, (int) ($u + $d));
             }
 
             $sum += $u + $d;

+ 46 - 0
src/Models/HourlyUsage.php

@@ -0,0 +1,46 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Models;
+
+use Illuminate\Database\Query\Builder;
+use function array_fill;
+use function date;
+use function json_decode;
+use function json_encode;
+
+/**
+ * @property int $id           记录ID
+ * @property int $user_id      用户ID
+ * @property string $date      记录日期
+ * @property string $usage     流量用量
+ *
+ * @mixin Builder
+ */
+final class HourlyUsage extends Model
+{
+    protected $connection = 'default';
+    protected $table = 'hourly_usage';
+
+    public function add(int $user_id, int $usage): void
+    {
+        $hour = (int) date('H');
+        $date = date('Y-m-d');
+        $exist_usage = $this->where('user_id', $user_id)->where('date', $date)->first();
+
+        if ($exist_usage === null) {
+            $new_usage_array = array_fill(0, 24, 0);
+            $new_usage_array[$hour] = $usage;
+            $this->user_id = $user_id;
+            $this->date = $date;
+            $this->usage = json_encode($new_usage_array);
+            $this->save();
+        } else {
+            $exist_usage_array = json_decode($exist_usage->usage, true);
+            $exist_usage_array[$hour] += $usage;
+            $exist_usage->usage = json_encode($exist_usage_array);
+            $exist_usage->save();
+        }
+    }
+}

+ 1 - 31
src/Models/User.php

@@ -7,7 +7,6 @@ namespace App\Models;
 use App\Services\IM;
 use App\Utils\Hash;
 use App\Utils\Tools;
-use Exception;
 use GuzzleHttp\Exception\GuzzleException;
 use Illuminate\Database\Eloquent\Collection;
 use Illuminate\Database\Query\Builder;
@@ -16,7 +15,6 @@ use Telegram\Bot\Exceptions\TelegramSDKException;
 use function date;
 use function is_null;
 use function md5;
-use function random_int;
 use function round;
 use function time;
 use const PHP_EOL;
@@ -292,7 +290,7 @@ final class User extends Model
      */
     public function isAbleToCheckin(): bool
     {
-        return date('Ymd') !== date('Ymd', $this->last_check_in_time);
+        return date('Ymd') !== date('Ymd', $this->last_check_in_time) && ! $this->is_shadow_banned;
     }
 
     /**
@@ -348,34 +346,6 @@ final class User extends Model
         return $this->delete();
     }
 
-    /**
-     * 签到
-     */
-    public function checkin(): array
-    {
-        $return = [
-            'ok' => true,
-        ];
-
-        if (! $this->isAbleToCheckin() || $this->is_shadow_banned) {
-            $return['ok'] = false;
-            $return['msg'] = '签到失败,请稍后再试';
-        } else {
-            try {
-                $traffic = random_int((int) $_ENV['checkinMin'], (int) $_ENV['checkinMax']);
-            } catch (Exception $e) {
-                $traffic = 0;
-            }
-
-            $this->transfer_enable += Tools::toMB($traffic);
-            $this->last_check_in_time = time();
-            $this->save();
-            $return['msg'] = '获得了 ' . $traffic . 'MB 流量.';
-        }
-
-        return $return;
-    }
-
     public function unbindIM(): bool
     {
         $this->im_type = 0;

+ 0 - 22
src/Models/UserHourlyUsage.php

@@ -1,22 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace App\Models;
-
-use Illuminate\Database\Query\Builder;
-
-/**
- * @property int $id           记录ID
- * @property int $user_id      用户ID
- * @property int $traffic      当前总流量
- * @property int $hourly_usage 过去一小时流量
- * @property int $datetime     记录时间
- *
- * @mixin Builder
- */
-final class UserHourlyUsage extends Model
-{
-    protected $connection = 'default';
-    protected $table = 'user_hourly_usage';
-}

+ 18 - 0
src/Services/Analytics.php

@@ -4,12 +4,16 @@ declare(strict_types=1);
 
 namespace App\Services;
 
+use App\Models\HourlyUsage;
 use App\Models\Node;
 use App\Models\Paylist;
 use App\Models\User;
 use App\Utils\Tools;
+use function array_fill;
+use function date;
 use function floatval;
 use function is_null;
+use function json_decode;
 use function round;
 use function strtotime;
 use function time;
@@ -142,4 +146,18 @@ final class Analytics
     {
         return (new User())->where('is_inactive', 0)->count();
     }
+
+    public static function getUserHourlyUsage(int $user_id, string $date): array
+    {
+        $hourly_usage = (new HourlyUsage())->where('user_id', $user_id)->where('date', $date)->first();
+
+        return $hourly_usage ? json_decode($hourly_usage->usage, true) : array_fill(0, 24, 0);
+    }
+
+    public static function getUserTodayHourlyUsage(int $user_id): array
+    {
+        $date = date('Y-m-d');
+
+        return self::getUserHourlyUsage($user_id, $date);
+    }
 }

+ 16 - 5
src/Services/Bot/Telegram/Callback.php

@@ -11,6 +11,7 @@ use App\Models\OnlineLog;
 use App\Models\Payback;
 use App\Models\SubscribeLog;
 use App\Models\User;
+use App\Services\Reward;
 use App\Services\Subscribe;
 use App\Utils\Tools;
 use GuzzleHttp\Exception\GuzzleException;
@@ -892,8 +893,8 @@ final class Callback
         $text = [
             '<strong>你每邀请 <code>1</code> 位用户注册:</strong>',
             '',
-            '- 你会获得 <code>' . Config::obtain('invite_reg_money_reward') . 'G</code> 流量奖励。',
-            '- 对方将获得 <code>' . Config::obtain('invite_reg_traffic_reward') . '元</code> 初始账户余额。',
+            '- 你会获得 <code>' . Config::obtain('invite_reg_traffic_reward') . 'G</code> 流量奖励。',
+            '- 对方将获得 <code>' . Config::obtain('invite_reg_money_reward') . '元</code> 初始账户余额。',
             '- 对方支付账单时你会获得对方账单金额的 <code>' . Config::obtain('invite_reward_rate') * 100 . '%</code> 的返利。',
             '',
             '已获得返利:' . $paybacks_sum . ' 元。',
@@ -981,10 +982,20 @@ final class Callback
      */
     public function userCheckin(): void
     {
-        $checkin = $this->user->checkin();
+        if ($this->user->isAbleToCheckin()) {
+            $traffic = Reward::issueCheckinReward($this->user->id);
+
+            if (! $traffic) {
+                $msg = '签到失败';
+            } else {
+                $msg = '获得了 ' . $traffic . 'MB 流量.';
+            }
+        } else {
+            $msg = '你今天已经签到过了';
+        }
 
         $this->answerCallbackQuery([
-            'text' => $checkin['msg'],
+            'text' => $msg,
             'show_alert' => true,
         ]);
         // 回送信息
@@ -1006,7 +1017,7 @@ final class Callback
         }
 
         $this->replyWithMessage([
-            'text' => $temp['text'] . PHP_EOL . PHP_EOL . $checkin['msg'],
+            'text' => $temp['text'] . PHP_EOL . PHP_EOL . $msg,
             'reply_to_message_id' => $this->message_id,
             'parse_mode' => 'Markdown',
             'reply_markup' => json_encode(

+ 13 - 2
src/Services/Bot/Telegram/Commands/CheckinCommand.php

@@ -6,6 +6,7 @@ namespace App\Services\Bot\Telegram\Commands;
 
 use App\Models\Config;
 use App\Services\Bot\Telegram\Message;
+use App\Services\Reward;
 use Telegram\Bot\Actions;
 use Telegram\Bot\Commands\Command;
 
@@ -64,11 +65,21 @@ final class CheckinCommand extends Command
                 ]
             );
         } else {
-            $checkin = $user->checkin();
+            if ($user->isAbleToCheckin()) {
+                $traffic = Reward::issueCheckinReward($this->user->id);
+
+                if (! $traffic) {
+                    $msg = '签到失败';
+                } else {
+                    $msg = '获得了 ' . $traffic . 'MB 流量.';
+                }
+            } else {
+                $msg = '你今天已经签到过了';
+            }
             // 回送信息
             $response = $this->replyWithMessage(
                 [
-                    'text' => $checkin['msg'],
+                    'text' => $msg,
                     'parse_mode' => 'Markdown',
                     'reply_to_message_id' => $message->getMessageId(),
                 ]

+ 10 - 29
src/Services/Cron.php

@@ -8,6 +8,7 @@ use App\Models\Ann;
 use App\Models\Config;
 use App\Models\DetectLog;
 use App\Models\EmailQueue;
+use App\Models\HourlyUsage;
 use App\Models\Invoice;
 use App\Models\Node;
 use App\Models\OnlineLog;
@@ -15,7 +16,6 @@ use App\Models\Order;
 use App\Models\Paylist;
 use App\Models\SubscribeLog;
 use App\Models\User;
-use App\Models\UserHourlyUsage;
 use App\Services\IM\Telegram;
 use App\Utils\Tools;
 use DateTime;
@@ -34,31 +34,6 @@ use const PHP_EOL;
 
 final class Cron
 {
-    public static function addTrafficLog(): void
-    {
-        $users = User::all();
-
-        foreach ($users as $user) {
-            $transfer_total = $user->transfer_total;
-            $transfer_total_last = (new UserHourlyUsage())->where('user_id', $user->id)->orderBy('id', 'desc')->first();
-
-            if ($transfer_total_last === null) {
-                $transfer_total_last = 0;
-            } else {
-                $transfer_total_last = $transfer_total_last->traffic;
-            }
-
-            $trafficlog = new UserHourlyUsage();
-            $trafficlog->user_id = $user->id;
-            $trafficlog->traffic = $transfer_total;
-            $trafficlog->hourly_usage = $transfer_total - $transfer_total_last;
-            $trafficlog->datetime = time();
-            $trafficlog->save();
-        }
-
-        echo Tools::toDateTime(time()) . ' 流量记录处理完成' . PHP_EOL;
-    }
-
     public static function cleanDb(): void
     {
         (new SubscribeLog())->where(
@@ -66,7 +41,11 @@ final class Cron
             '<',
             time() - 86400 * Config::obtain('subscribe_log_retention_days')
         )->delete();
-        (new UserHourlyUsage())->where('datetime', '<', time() - 86400 * Config::obtain('traffic_log_retention_days'))->delete();
+        (new HourlyUsage())->where(
+            'date',
+            '<',
+            date('Y-m-d', time() - 86400 * Config::obtain('traffic_log_retention_days'))
+        )->delete();
         (new DetectLog())->where('datetime', '<', time() - 86400 * 3)->delete();
         (new EmailQueue())->where('time', '<', time() - 86400)->delete();
         (new OnlineLog())->where('last_time', '<', time() - 86400)->delete();
@@ -430,7 +409,8 @@ final class Cron
 
     public static function resetFreeUserTraffic(): void
     {
-        $freeUsers = (new User())->where('class', 0)->where('auto_reset_day', date('d'))->get();
+        $freeUsers = (new User())->where('class', 0)
+            ->where('auto_reset_day', date('d'))->get();
 
         foreach ($freeUsers as $user) {
             try {
@@ -455,7 +435,8 @@ final class Cron
     public static function sendDailyFinanceMail(): void
     {
         $today = strtotime('00:00:00');
-        $paylists = (new Paylist())->where('status', 1)->whereBetween('datetime', [strtotime('-1 day', $today), $today])->get();
+        $paylists = (new Paylist())->where('status', 1)
+            ->whereBetween('datetime', [strtotime('-1 day', $today), $today])->get();
         $text_html = '<table border=1><tr><td>金额</td><td>用户ID</td><td>用户名</td><td>充值时间</td>';
 
         foreach ($paylists as $paylist) {

+ 3 - 9
src/Services/Gateway/AopF2F.php

@@ -98,17 +98,11 @@ final class AopF2F extends Base
 
         if ($aliResponse->isPaid()) {
             $this->postPayment($pid);
-
-            return $response->withJson([
-                'ret' => 1,
-                'msg' => '支付成功',
-            ]);
+            // https://opendocs.alipay.com/open/194/103296#%E5%BC%82%E6%AD%A5%E9%80%9A%E7%9F%A5%E7%89%B9%E6%80%A7
+            return $response->write('success');
         }
 
-        return $response->withJson([
-            'ret' => 0,
-            'msg' => '支付失败',
-        ]);
+        return $response->write('failed');
     }
 
     /**

+ 3 - 1
src/Services/Gateway/Base.php

@@ -80,7 +80,7 @@ abstract class Base
 
         $user = (new User())->find($paylist?->userid);
         // 返利
-        if ($user !== null && $user->ref_by > 0 && Config::obtain('invitation_mode') === 'reward') {
+        if ($user !== null && $user->ref_by > 0 && Config::obtain('invite_mode') === 'reward') {
             Reward::issuePaybackReward($user->id, $user->ref_by, $paylist->total, $paylist->invoice_id);
         }
     }
@@ -104,9 +104,11 @@ abstract class Base
     {
         $payment_gateways = (new Config())->where('item', 'payment_gateway')->first();
         $active_gateways = json_decode($payment_gateways->value);
+
         if (in_array($key, $active_gateways)) {
             return true;
         }
+
         return false;
     }
 }

+ 33 - 0
src/Services/Reward.php

@@ -9,6 +9,9 @@ use App\Models\Payback;
 use App\Models\User;
 use App\Models\UserMoneyLog;
 use App\Utils\Tools;
+use Exception;
+use function random_int;
+use function time;
 
 final class Reward
 {
@@ -114,4 +117,34 @@ final class Reward
             }
         }
     }
+
+    public static function issueCheckinReward($user_id): int|false
+    {
+        $user = (new User())->where('id', $user_id)->first();
+
+        if ($user === null) {
+            return false;
+        }
+
+        $checkin_min = Config::obtain('checkin_min');
+        $checkin_max = Config::obtain('checkin_max');
+
+        if ($checkin_min === $checkin_max) {
+            $traffic = $checkin_min;
+        } else {
+            try {
+                $traffic = random_int($checkin_min, $checkin_max);
+            } catch (Exception $e) {
+                $traffic = 0;
+            }
+        }
+
+        if ($traffic !== 0) {
+            $user->transfer_enable += Tools::toMB($traffic);
+            $user->last_check_in_time = time();
+            $user->save();
+        }
+
+        return $traffic;
+    }
 }

+ 0 - 4
src/Services/View.php

@@ -63,10 +63,6 @@ final class View
             'appName' => $_ENV['appName'],
             'baseUrl' => $_ENV['baseUrl'],
 
-            'enable_checkin' => $_ENV['enable_checkin'],
-            'checkinMin' => $_ENV['checkinMin'],
-            'checkinMax' => $_ENV['checkinMax'],
-
             'jump_delay' => $_ENV['jump_delay'],
 
             'enable_kill' => $_ENV['enable_kill'],

+ 4 - 4
src/Utils/Tools.php

@@ -189,9 +189,9 @@ final class Tools
      *
      * @return float
      */
-    public static function flowToGB($traffic): float
+    public static function flowToMB($traffic): float
     {
-        return round($traffic / 1073741824, 2);
+        return round($traffic / 1048576, 2);
     }
 
     /**
@@ -199,9 +199,9 @@ final class Tools
      *
      * @return float
      */
-    public static function flowToMB($traffic): float
+    public static function flowToGB($traffic): float
     {
-        return round($traffic / 1048576, 2);
+        return round($traffic / 1073741824, 2);
     }
 
     public static function genSubToken(): string