浏览代码

💪🏼 Simplify Models using Casts Class

BrettonYe 2 年之前
父节点
当前提交
2ef6257db2

+ 1 - 1
.env.example

@@ -43,7 +43,7 @@ MAIL_ENCRYPTION=ssl
 [email protected]
 MAIL_FROM_NAME=ProxyPanel
 
-SESSION_SECURE_COOKIE=true
+SESSION_SECURE_COOKIE=
 #IP查询相关
 BAIDU_APP_AK=
 IPINFO_ACCESS_TOKEN=

+ 29 - 0
app/Casts/data_rate.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Casts;
+
+use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
+use Illuminate\Database\Eloquent\Model;
+
+class data_rate implements CastsAttributes
+{
+    /**
+     * Cast the given value.
+     *
+     * @param  array<string, mixed>  $attributes
+     */
+    public function get(Model $model, string $key, mixed $value, array $attributes): int|float
+    {
+        return $value / Mbps;
+    }
+
+    /**
+     * Prepare the given value for storage.
+     *
+     * @param  array<string, mixed>  $attributes
+     */
+    public function set(Model $model, string $key, mixed $value, array $attributes): int
+    {
+        return $value * Mbps;
+    }
+}

+ 29 - 0
app/Casts/datestamp.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Casts;
+
+use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
+use Illuminate\Database\Eloquent\Model;
+
+class datestamp implements CastsAttributes
+{
+    /**
+     * Cast the given value.
+     *
+     * @param  array<string, mixed>  $attributes
+     */
+    public function get(Model $model, string $key, mixed $value, array $attributes): string
+    {
+        return date('Y-m-d', $value);
+    }
+
+    /**
+     * Prepare the given value for storage.
+     *
+     * @param  array<string, mixed>  $attributes
+     */
+    public function set(Model $model, string $key, mixed $value, array $attributes): int
+    {
+        return strtotime($value);
+    }
+}

+ 29 - 0
app/Casts/money.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Casts;
+
+use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
+use Illuminate\Database\Eloquent\Model;
+
+class money implements CastsAttributes
+{
+    /**
+     * Cast the given value.
+     *
+     * @param  array<string, mixed>  $attributes
+     */
+    public function get(Model $model, string $key, mixed $value, array $attributes): int|float
+    {
+        return $value / 100;
+    }
+
+    /**
+     * Prepare the given value for storage.
+     *
+     * @param  array<string, mixed>  $attributes
+     */
+    public function set(Model $model, string $key, mixed $value, array $attributes): int
+    {
+        return $value * 100;
+    }
+}

+ 1 - 1
app/Console/Commands/PanelUpdate.php

@@ -23,7 +23,7 @@ class PanelUpdate extends Command
             Artisan::call('migrate --force');
 
             if (config('app.demo') && $this->confirm('检测到您在DEMO模式, 是否重置数据库?')) {
-                Artisan::call('migrate:fresh --seed');
+                Artisan::call('migrate:fresh --seed --force');
             }
 
             $bar->advance();

+ 2 - 3
app/Console/Commands/TaskDaily.php

@@ -70,11 +70,10 @@ class TaskDaily extends Command
 
     private function closeTickets(): void
     { // 关闭用户超时未处理的工单
-        Ticket::whereStatus(1)
+        Ticket::whereStatus(1)->with('reply')
             ->whereHas('reply', function ($q) {
                 $q->where('admin_id', '<>', null);
             })
-            ->has('reply')
             ->where('updated_at', '<=', date('Y-m-d', strtotime('-'.config('tasks.close.tickets').' hours')))
             ->chunk(config('tasks.chunk'), function ($tickets) {
                 foreach ($tickets as $ticket) {
@@ -92,7 +91,7 @@ class TaskDaily extends Command
         User::where('status', '<>', -1)
             ->where('expired_at', '>', date('Y-m-d'))
             ->where('reset_time', '<=', date('Y-m-d'))
-            ->with('orders')->whereHas('orders')
+            ->with('orders')->has('orders')
             ->chunk(config('tasks.chunk'), function ($users) {
                 foreach ($users as $user) {
                     $order = $user->orders()->activePlan()->first(); // 取出用户正在使用的套餐

+ 3 - 2
app/Models/Article.php

@@ -2,6 +2,7 @@
 
 namespace App\Models;
 
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\SoftDeletes;
 
@@ -19,12 +20,12 @@ class Article extends Model
     protected $guarded = [];
 
     // 筛选类型
-    public function scopeType($query, $type)
+    public function scopeType(Builder $query, int $type): Builder
     {
         return $query->whereType($type);
     }
 
-    public function scopeLang($query, $language = null)
+    public function scopeLang(Builder $query, ?string $language = null): Builder
     {
         return $query->whereLanguage($language ?? app()->getLocale());
     }

+ 4 - 12
app/Models/Coupon.php

@@ -2,6 +2,8 @@
 
 namespace App\Models;
 
+use App\Casts\datestamp;
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\SoftDeletes;
 
@@ -14,26 +16,16 @@ class Coupon extends Model
 
     protected $table = 'coupon';
 
-    protected $casts = ['limit' => 'array', 'start_time' => 'date:Y-m-d', 'end_time' => 'date:Y-m-d', 'deleted_at' => 'datetime'];
+    protected $casts = ['limit' => 'array', 'start_time' => datestamp::class, 'end_time' => datestamp::class, 'deleted_at' => 'datetime'];
 
     protected $guarded = [];
 
     // 筛选类型
-    public function scopeType($query, $type)
+    public function scopeType(Builder $query, int $type): Builder
     {
         return $query->whereType($type);
     }
 
-    public function setStartTimeAttribute($value)
-    {
-        return $this->attributes['start_time'] = strtotime($value);
-    }
-
-    public function setEndTimeAttribute($value)
-    {
-        return $this->attributes['end_time'] = strtotime($value);
-    }
-
     public function used(): bool
     {
         $this->attributes['status'] = 1;

+ 16 - 0
app/Models/CouponLog.php

@@ -3,6 +3,7 @@
 namespace App\Models;
 
 use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
 /**
  * 优惠券使用日志.
@@ -12,4 +13,19 @@ class CouponLog extends Model
     public const UPDATED_AT = null;
 
     protected $table = 'coupon_log';
+
+    public function coupon(): BelongsTo
+    {
+        return $this->belongsTo(User::class);
+    }
+
+    public function goods(): BelongsTo
+    {
+        return $this->belongsTo(Goods::class);
+    }
+
+    public function order(): BelongsTo
+    {
+        return $this->belongsTo(Order::class);
+    }
 }

+ 5 - 32
app/Models/Goods.php

@@ -2,7 +2,10 @@
 
 namespace App\Models;
 
+use App\Casts\data_rate;
+use App\Casts\money;
 use App\Utils\Helpers;
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\HasMany;
 use Illuminate\Database\Eloquent\SoftDeletes;
@@ -16,7 +19,7 @@ class Goods extends Model
 
     protected $table = 'goods';
 
-    protected $casts = ['deleted_at' => 'datetime'];
+    protected $casts = ['price' => money::class, 'renew' => money::class, 'speed_limit' => data_rate::class, 'deleted_at' => 'datetime'];
 
     protected $guarded = [];
 
@@ -25,36 +28,16 @@ class Goods extends Model
         return $this->hasMany(Order::class);
     }
 
-    public function scopeType($query, $type)
+    public function scopeType(Builder $query, int $type): Builder
     {
         return $query->whereType($type)->whereStatus(1)->orderByDesc('sort');
     }
 
-    public function getPriceAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    public function setPriceAttribute($value): void
-    {
-        $this->attributes['price'] = $value * 100;
-    }
-
     public function getPriceTagAttribute(): string
     {
         return Helpers::getPriceTag($this->price);
     }
 
-    public function getRenewAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    public function setRenewAttribute($value): void
-    {
-        $this->attributes['renew'] = $value * 100;
-    }
-
     public function getRenewTagAttribute(): string
     {
         return Helpers::getPriceTag($this->renew);
@@ -64,14 +47,4 @@ class Goods extends Model
     {
         return formatBytes($this->attributes['traffic'] * MB);
     }
-
-    public function setSpeedLimitAttribute($value)
-    {
-        return $this->attributes['speed_limit'] = $value * Mbps;
-    }
-
-    public function getSpeedLimitAttribute($value)
-    {
-        return $value / Mbps;
-    }
 }

+ 2 - 1
app/Models/Invite.php

@@ -3,6 +3,7 @@
 namespace App\Models;
 
 use Auth;
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use Illuminate\Database\Eloquent\SoftDeletes;
@@ -20,7 +21,7 @@ class Invite extends Model
 
     protected $guarded = [];
 
-    public function scopeUid($query)
+    public function scopeUid(Builder $query): Builder
     {
         return $query->whereInviterId(Auth::id());
     }

+ 3 - 2
app/Models/Marketing.php

@@ -15,10 +15,11 @@ class Marketing extends Model
 
     public function getStatusLabelAttribute(): string
     {
-        return [
+        return match ($this->attributes['status']) {
             -1 => '失败',
             0 => '待推送',
             1 => '成功',
-        ][$this->attributes['status']] ?? '';
+            default => '',
+        };
     }
 }

+ 7 - 14
app/Models/Node.php

@@ -2,7 +2,9 @@
 
 namespace App\Models;
 
+use App\Casts\data_rate;
 use App\Utils\IP;
+use Illuminate\Database\Eloquent\Collection;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use Illuminate\Database\Eloquent\Relations\BelongsToMany;
@@ -19,7 +21,7 @@ class Node extends Model
 
     protected $guarded = [];
 
-    protected $casts = ['profile' => 'array'];
+    protected $casts = ['speed_limit' => data_rate::class, 'profile' => 'array'];
 
     public function labels(): BelongsToMany
     {
@@ -96,7 +98,7 @@ class Node extends Model
         return $this->hasOne(Level::class, 'level', 'level');
     }
 
-    public function users()
+    public function users(): Collection
     {
         return User::activeUser()
             ->where('level', '>=', $this->attributes['level'])
@@ -140,25 +142,16 @@ class Node extends Model
         return array_map('trim', explode(',', $ip));
     }
 
-    public function getSpeedLimitAttribute($value)
-    {
-        return $value / Mbps;
-    }
-
-    public function setSpeedLimitAttribute($value)
-    {
-        return $this->attributes['speed_limit'] = $value * Mbps;
-    }
-
     public function getTypeLabelAttribute(): string
     {
-        return [
+        return match ($this->attributes['type']) {
             0 => 'Shadowsocks',
             1 => 'ShadowsocksR',
             2 => 'V2Ray',
             3 => 'Trojan',
             4 => 'VNet',
-        ][$this->attributes['type']] ?? 'UnKnown';
+            default => 'UnKnown',
+        };
     }
 
     public function getHostAttribute(): string

+ 2 - 1
app/Models/NodeHeartbeat.php

@@ -2,6 +2,7 @@
 
 namespace App\Models;
 
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -15,7 +16,7 @@ class NodeHeartbeat extends Model
 
     protected $guarded = [];
 
-    public function scopeRecently($query)
+    public function scopeRecently(Builder $query): Builder
     {
         return $query->where('log_time', '>=', strtotime(config('tasks.recently_heartbeat')))->latest('log_time');
     }

+ 24 - 36
app/Models/Order.php

@@ -2,8 +2,10 @@
 
 namespace App\Models;
 
+use App\Casts\money;
 use App\Utils\Helpers;
 use Auth;
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use Illuminate\Database\Eloquent\Relations\HasOne;
@@ -16,13 +18,13 @@ class Order extends Model
 {
     use Sortable;
 
-    public $sortable = ['id', 'sn', 'expired_at', 'created_at'];
+    public array $sortable = ['id', 'sn', 'expired_at', 'created_at'];
 
     protected $table = 'order';
 
     protected $guarded = [];
 
-    protected $casts = ['expired_at' => 'datetime'];
+    protected $casts = ['origin_amount' => money::class, 'amount' => money::class, 'expired_at' => 'datetime'];
 
     public function user(): BelongsTo
     {
@@ -44,50 +46,55 @@ class Order extends Model
         return $this->hasOne(Payment::class);
     }
 
-    public function scopeUid($query, $uid = null)
+    public function scopeUid(Builder $query, int $uid = 0): Builder
     {
         return $query->whereUserId($uid ?: Auth::id());
     }
 
-    public function scopeRecentUnPay($query, int $minutes = 0)
+    public function scopeRecentUnPay(Builder $query, int $minutes = 0): Builder
     {
         if (! $minutes) {
-            $minutes = config('tasks.close.orders');
+            $minutes = (int) config('tasks.close.orders');
         }
 
-        return $query->whereStatus(0)->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-'.$minutes.' minutes')));
+        return $query->whereStatus(0)->where('created_at', '<=', date('Y-m-d H:i:s', strtotime("-$minutes minutes")));
     }
 
-    public function scopeUserPrepay($query, $uid = null)
+    public function scopeUserPrepay(Builder $query, int $uid = 0): Builder
     {
         return $query->uid($uid)->whereStatus(3)->oldest();
     }
 
-    public function scopeActive($query)
+    public function scopeActive(Builder $query): Builder
     {
         return $query->whereIsExpire(0)->whereStatus(2);
     }
 
-    public function scopeActivePlan($query)
+    public function scopeActivePlan(Builder $query): Builder
     {
-        return $query->active()->with('goods')->whereHas('goods', static function ($query) {
+        return $query->active()->isPlan();
+    }
+
+    public function scopeIsPlan(Builder $query): Builder
+    {
+        return $query->with('goods')->whereHas('goods', function ($query) {
             $query->whereType(2);
         });
     }
 
-    public function scopeActivePackage($query)
+    public function scopeActivePackage(Builder $query): Builder
     {
         return $query->active()->with('goods')->whereHas('goods', static function ($query) {
             $query->whereType(1);
         });
     }
 
-    public function scopeUserActivePlan($query, $uid = null)
+    public function scopeUserActivePlan(Builder $query, int $uid = 0): Builder
     {
         return $query->uid($uid)->activePlan();
     }
 
-    public function scopeUserActivePackage($query, $uid = null)
+    public function scopeUserActivePackage(Builder $query, int $uid = 0): Builder
     {
         return $query->uid($uid)->activePackage();
     }
@@ -122,7 +129,7 @@ class Order extends Model
         return $this->statusTags($this->attributes['status'], $this->attributes['is_expire']);
     }
 
-    public function statusTags($status, $expire, $isHtml = true): string
+    public function statusTags(int $status, bool $expire, bool $isHtml = true): string
     {
         switch ($status) {
             case -1:
@@ -162,31 +169,11 @@ class Order extends Model
         return $label;
     }
 
-    public function getOriginAmountAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    public function setOriginAmountAttribute($value)
-    {
-        return $this->attributes['origin_amount'] = $value * 100;
-    }
-
     public function getOriginAmountTagAttribute(): string
     {
         return Helpers::getPriceTag($this->origin_amount);
     }
 
-    public function getAmountAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    public function setAmountAttribute($value)
-    {
-        return $this->attributes['amount'] = $value * 100;
-    }
-
     public function getAmountTagAttribute(): string
     {
         return Helpers::getPriceTag($this->amount);
@@ -195,7 +182,7 @@ class Order extends Model
     // 支付渠道
     public function getPayTypeLabelAttribute(): string
     {
-        return [
+        return match ($this->attributes['pay_type']) {
             0 => trans('common.payment.credit'),
             1 => trans('common.payment.alipay'),
             2 => trans('common.payment.qq'),
@@ -204,7 +191,8 @@ class Order extends Model
             5 => 'PayPal',
             6 => 'Stripe',
             7 => trans('common.payment.manual'),
-        ][$this->attributes['pay_type']] ?? '';
+            default => '',
+        };
     }
 
     // 支付图标

+ 5 - 11
app/Models/Payment.php

@@ -2,8 +2,10 @@
 
 namespace App\Models;
 
+use App\Casts\money;
 use App\Utils\Helpers;
 use Auth;
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
@@ -16,7 +18,9 @@ class Payment extends Model
 
     protected $guarded = [];
 
-    public function scopeUid($query)
+    protected $casts = ['amount' => money::class];
+
+    public function scopeUid(Builder $query): Builder
     {
         return $query->whereUserId(Auth::id());
     }
@@ -46,16 +50,6 @@ class Payment extends Model
         return $this->update(['status' => 1]);
     }
 
-    public function getAmountAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    public function setAmountAttribute($value)
-    {
-        return $this->attributes['amount'] = $value * 100;
-    }
-
     public function getAmountTagAttribute(): string
     {
         return Helpers::getPriceTag($this->amount);

+ 3 - 2
app/Models/PaymentCallback.php

@@ -15,11 +15,12 @@ class PaymentCallback extends Model
 
     public function getStatusLabelAttribute(): string
     {
-        return [
+        return match ($this->attributes['status']) {
             'WAIT_BUYER_PAY' => '等待买家付款',
             'WAIT_SELLER_SEND_GOODS' => '等待卖家发货',
             'TRADE_SUCCESS' => '交易成功',
             'PAID' => '支付完成',
-        ][$this->attributes['status']] ?? '';
+            default => '',
+        };
     }
 }

+ 5 - 33
app/Models/ReferralApply.php

@@ -2,8 +2,10 @@
 
 namespace App\Models;
 
+use App\Casts\money;
 use App\Utils\Helpers;
 use Auth;
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
@@ -14,11 +16,11 @@ class ReferralApply extends Model
 {
     protected $table = 'referral_apply';
 
-    protected $casts = ['link_logs' => 'array'];
+    protected $casts = ['before' => money::class, 'after' => money::class, 'amount' => money::class, 'link_logs' => 'array'];
 
     protected $guarded = [];
 
-    public function scopeUid($query)
+    public function scopeUid(Builder $query): Builder
     {
         return $query->whereUserId(Auth::id());
     }
@@ -28,41 +30,11 @@ class ReferralApply extends Model
         return $this->belongsTo(User::class);
     }
 
-    public function referral_logs()
+    public function referral_logs(): ReferralLog|\Illuminate\Database\Query\Builder
     {
         return ReferralLog::whereIn('id', $this->link_logs);
     }
 
-    public function getBeforeAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    public function setBeforeAttribute($value): void
-    {
-        $this->attributes['before'] = $value * 100;
-    }
-
-    public function getAfterAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    public function setAfterAttribute($value): void
-    {
-        $this->attributes['after'] = $value * 100;
-    }
-
-    public function getAmountAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    public function setAmountAttribute($value): void
-    {
-        $this->attributes['amount'] = $value * 100;
-    }
-
     public function getAmountTagAttribute(): string
     {
         return Helpers::getPriceTag($this->amount);

+ 5 - 21
app/Models/ReferralLog.php

@@ -2,8 +2,10 @@
 
 namespace App\Models;
 
+use App\Casts\money;
 use App\Utils\Helpers;
 use Auth;
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
@@ -14,9 +16,11 @@ class ReferralLog extends Model
 {
     protected $table = 'referral_log';
 
+    protected $casts = ['amount' => money::class, 'commission' => money::class];
+
     protected $guarded = [];
 
-    public function scopeUid($query)
+    public function scopeUid(Builder $query): Builder
     {
         return $query->whereInviterId(Auth::id());
     }
@@ -36,26 +40,6 @@ class ReferralLog extends Model
         return $this->belongsTo(Order::class);
     }
 
-    public function getAmountAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    public function getCommissionAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    public function setAmountAttribute($value): void
-    {
-        $this->attributes['amount'] = $value * 100;
-    }
-
-    public function setCommissionAttribute($value): void
-    {
-        $this->attributes['commission'] = $value * 100;
-    }
-
     public function getAmountTagAttribute(): string
     {
         return Helpers::getPriceTag($this->amount);

+ 11 - 9
app/Models/Rule.php

@@ -16,28 +16,30 @@ class Rule extends Model
 
     protected $guarded = [];
 
+    public function rule_groups(): BelongsToMany
+    {
+        return $this->belongsToMany(RuleGroup::class);
+    }
+
     public function getTypeLabelAttribute(): string
     {
-        return [
+        return match ($this->attributes['type']) {
             1 => trans('admin.rule.type.reg'),
             2 => trans('admin.rule.type.domain'),
             3 => trans('admin.rule.type.ip'),
             4 => trans('admin.rule.type.protocol'),
-        ][$this->attributes['type']] ?? trans('common.status.unknown');
+            default => trans('common.status.unknown'),
+        };
     }
 
     public function getTypeApiLabelAttribute(): string
     {
-        return [
+        return match ($this->attributes['type']) {
             1 => 'reg',
             2 => 'domain',
             3 => 'ip',
             4 => 'protocol',
-        ][$this->attributes['type']] ?? 'unknown';
-    }
-
-    public function rule_groups(): BelongsToMany
-    {
-        return $this->belongsToMany(RuleGroup::class);
+            default => 'unknown',
+        };
     }
 }

+ 7 - 10
app/Models/RuleGroup.php

@@ -14,19 +14,16 @@ class RuleGroup extends Model
 
     protected $guarded = [];
 
-    public function getTypeLabelAttribute(): string
+    public function rules(): BelongsToMany
     {
-        if ($this->attributes['type']) {
-            $type_label = '<span class="badge badge-danger">'.trans('admin.rule.group.type.off').'</span>';
-        } else {
-            $type_label = '<span class="badge badge-primary">'.trans('admin.rule.group.type.on').'</span>';
-        }
-
-        return $type_label;
+        return $this->belongsToMany(Rule::class);
     }
 
-    public function rules(): BelongsToMany
+    public function getTypeLabelAttribute(): string
     {
-        return $this->belongsToMany(Rule::class);
+        return match ($this->attributes['type']) {
+            0 => '<span class="badge badge-primary">'.trans('admin.rule.group.type.on').'</span>',
+            1 => '<span class="badge badge-danger">'.trans('admin.rule.group.type.off').'</span>',
+        };
     }
 }

+ 5 - 4
app/Models/SsConfig.php

@@ -2,6 +2,7 @@
 
 namespace App\Models;
 
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -15,14 +16,14 @@ class SsConfig extends Model
 
     protected $guarded = [];
 
-    public function scopeDefault($query): void
+    public function scopeDefault(Builder $query): Builder
     {  // 筛选默认
-        $query->whereIsDefault(1);
+        return $query->whereIsDefault(1);
     }
 
-    public function scopeType($query, int $type): void
+    public function scopeType(Builder $query, int $type): Builder
     { // 筛选类型
-        $query->whereType($type);
+        return $query->whereType($type);
     }
 
     public function setDefault(): bool

+ 2 - 1
app/Models/Ticket.php

@@ -3,6 +3,7 @@
 namespace App\Models;
 
 use Auth;
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use Illuminate\Database\Eloquent\Relations\HasMany;
@@ -16,7 +17,7 @@ class Ticket extends Model
 
     protected $guarded = [];
 
-    public function scopeUid($query)
+    public function scopeUid(Builder $query): Builder
     {
         return $query->whereUserId(Auth::id());
     }

+ 14 - 31
app/Models/User.php

@@ -2,9 +2,12 @@
 
 namespace App\Models;
 
+use App\Casts\data_rate;
+use App\Casts\money;
 use App\Utils\Helpers;
 use App\Utils\QQInfo;
 use Hash;
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use Illuminate\Database\Eloquent\Relations\HasMany;
@@ -23,11 +26,11 @@ class User extends Authenticatable
 {
     use HasApiTokens, HasFactory, Notifiable, HasRoles, Sortable;
 
-    public $sortable = ['id', 'credit', 'port', 't', 'expired_at'];
+    public array $sortable = ['id', 'credit', 'port', 't', 'expired_at'];
 
     protected $table = 'user';
 
-    protected $casts = ['expired_at' => 'date:Y-m-d', 'reset_time' => 'date:Y-m-d', 'ban_time' => 'date:Y-m-d'];
+    protected $casts = ['credit' => money::class, 'speed_limit' => data_rate::class, 'expired_at' => 'date:Y-m-d', 'reset_time' => 'date:Y-m-d', 'ban_time' => 'date:Y-m-d'];
 
     protected $guarded = [];
 
@@ -178,16 +181,6 @@ class User extends Authenticatable
         return Level::whereLevel($this->attributes['level'])->first()->name;
     }
 
-    public function getCreditAttribute()
-    {
-        return $this->attributes['credit'] / 100;
-    }
-
-    public function setCreditAttribute($value)
-    {
-        return $this->attributes['credit'] = $value * 100;
-    }
-
     public function getCreditTagAttribute(): string
     {
         return Helpers::getPriceTag($this->credit);
@@ -198,21 +191,11 @@ class User extends Authenticatable
         return formatBytes($this->attributes['transfer_enable']);
     }
 
-    public function getSpeedLimitAttribute()
-    {
-        return $this->attributes['speed_limit'] / Mbps;
-    }
-
-    public function setPasswordAttribute($password): string
+    public function setPasswordAttribute(string $password): string
     {
         return $this->attributes['password'] = Hash::make($password);
     }
 
-    public function setSpeedLimitAttribute($value)
-    {
-        return $this->attributes['speed_limit'] = $value * Mbps;
-    }
-
     public function getAvatarAttribute(): string
     {
         if ($this->qq) {
@@ -229,27 +212,27 @@ class User extends Authenticatable
         return $url;
     }
 
-    public function scopeActiveUser($query)
+    public function scopeActiveUser(Builder $query): Builder
     {
         return $query->where('status', '<>', -1)->whereEnable(1);
     }
 
-    public function scopeBannedUser($query)
+    public function scopeBannedUser(Builder $query): Builder
     {
         return $query->where('status', '<>', -1)->whereEnable(0);
     }
 
-    public function nodes($userLevel = -1, $userGroupId = -1)
+    public function nodes(?int $userLevel = null, int $userGroupId = 0): Node|Builder
     {
-        if ($userGroupId === -1 && $this->attributes['user_group_id']) {
+        if ($userGroupId === 0 && $this->attributes['user_group_id']) { // 使用默认的用户分组
             $query = $this->userGroup->nodes();
-        } elseif ($userGroupId !== -1 && $userGroupId) {
+        } elseif ($userGroupId) { // 使用给的用户分组
             $query = UserGroup::findOrFail($userGroupId)->nodes();
-        } else {
+        } else { // 无用户分组
             $query = Node::query();
         }
 
-        return $query->whereStatus(1)->where('level', '<=', $userLevel !== -1 && $userLevel !== null ? $userLevel : $this->attributes['level'] ?? 0);
+        return $query->whereStatus(1)->where('level', '<=', $userLevel ?? $this->attributes['level'] ?? 0);
     }
 
     public function userGroup(): BelongsTo
@@ -277,7 +260,7 @@ class User extends Authenticatable
     }
 
     public function isNotCompleteOrderByUserId(int $userId): bool
-    { // 添加用户余额
+    {
         return Order::uid($userId)->whereIn('status', [0, 1])->exists();
     }
 

+ 3 - 30
app/Models/UserCreditLog.php

@@ -2,6 +2,7 @@
 
 namespace App\Models;
 
+use App\Casts\money;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
@@ -14,6 +15,8 @@ class UserCreditLog extends Model
 
     protected $table = 'user_credit_log';
 
+    protected $casts = ['before' => money::class, 'after' => money::class, 'amount' => money::class];
+
     protected $guarded = [];
 
     public function user(): BelongsTo
@@ -25,34 +28,4 @@ class UserCreditLog extends Model
     {
         return $this->belongsTo(Order::class);
     }
-
-    public function getBeforeAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    public function setBeforeAttribute($value)
-    {
-        return $this->attributes['before'] = $value * 100;
-    }
-
-    public function getAfterAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    public function setAfterAttribute($value)
-    {
-        return $this->attributes['after'] = $value * 100;
-    }
-
-    public function getAmountAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    public function setAmountAttribute($value)
-    {
-        return $this->attributes['amount'] = $value * 100;
-    }
 }

+ 3 - 3
app/Models/UserDailyDataFlow.php

@@ -2,6 +2,7 @@
 
 namespace App\Models;
 
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
@@ -26,9 +27,8 @@ class UserDailyDataFlow extends Model
         return $this->belongsTo(Node::class);
     }
 
-    // 用户每天使用总流量
-    public function scopeUserDaily($query, $uid)
-    {
+    public function scopeUserDaily(Builder $query, int $uid): Builder
+    { // 用户每天使用总流量
         return $query->whereUserId($uid)->whereNodeId(null);
     }
 }

+ 3 - 2
app/Models/UserHourlyDataFlow.php

@@ -2,6 +2,7 @@
 
 namespace App\Models;
 
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
@@ -27,12 +28,12 @@ class UserHourlyDataFlow extends Model
     }
 
     // 用户每时使用总流量
-    public function scopeUserHourly($query, $uid)
+    public function scopeUserHourly(Builder $query, int $uid): Builder
     {
         return $query->whereUserId($uid)->whereNodeId(null);
     }
 
-    public function scopeUserRecentUsed($query, $uid)
+    public function scopeUserRecentUsed(Builder $query, int $uid): Builder
     {
         return $query->userHourly($uid)->where('created_at', '>=', date('Y-m-d H:i:s', time() - 3900));
     }

+ 3 - 2
app/Models/UserSubscribe.php

@@ -3,6 +3,7 @@
 namespace App\Models;
 
 use Auth;
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use Illuminate\Database\Eloquent\Relations\HasMany;
@@ -15,13 +16,13 @@ class UserSubscribe extends Model
 {
     use Sortable;
 
-    public $sortable = ['id', 'times'];
+    public array $sortable = ['id', 'times'];
 
     protected $table = 'user_subscribe';
 
     protected $guarded = [];
 
-    public function scopeUid($query)
+    public function scopeUid(Builder $query): Builder
     {
         return $query->whereUserId(Auth::id());
     }

+ 2 - 1
app/Models/Verify.php

@@ -2,6 +2,7 @@
 
 namespace App\Models;
 
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
@@ -15,7 +16,7 @@ class Verify extends Model
     protected $guarded = [];
 
     // 筛选类型
-    public function scopeType($query, $type)
+    public function scopeType(Builder $query, int $type): Builder
     {
         return $query->whereType($type);
     }

+ 2 - 1
app/Models/VerifyCode.php

@@ -2,6 +2,7 @@
 
 namespace App\Models;
 
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -13,7 +14,7 @@ class VerifyCode extends Model
 
     protected $guarded = [];
 
-    public function scopeRecentUnused($query)
+    public function scopeRecentUnused(Builder $query): Builder
     {
         return $query->whereStatus(0)->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-'.config('tasks.close.verify').' minutes')));
     }

+ 1 - 1
app/Providers/AppServiceProvider.php

@@ -44,7 +44,7 @@ class AppServiceProvider extends ServiceProvider
         Paginator::useBootstrap();
 
         // 检测是否强制跳转https
-        if (env('SESSION_SECURE_COOKIE', false)) { // todo
+        if (config('session.secure')) {
             URL::forceScheme('https');
         }
 

+ 19 - 15
app/Services/OrderService.php

@@ -79,14 +79,22 @@ class OrderService
 
     private function setPrepaidPlan(): bool
     { // 设置预支付套餐, 刷新账号有效时间用于流量重置判断
-        Order::whereId($this->order->id)->first()->prepay(); // 直接编辑$this->order->prepay() [手动修改]会加不上
+        $this->order->prepay();
 
-        return self::$user->update(['expired_at' => date('Y-m-d', strtotime(self::$user->expired_at.' +'.self::$goods->days.' days'))]);
+        return self::$user->update(['expired_at' => $this->getFinallyExpiredTime()]);
+    }
+
+    public function getFinallyExpiredTime(): string
+    { // 推算最新的到期时间
+        $orders = self::$user->orders()->whereIn('status', [2, 3])->whereIsExpire(0)->isPlan()->get();
+        $current = $orders->where('status', '==', 2)->first();
+
+        return ($current->expired_at ?? now())->addDays($orders->except($current->id ?? 0)->sum('goods.days'))->format('Y-m-d');
     }
 
     public function activatePlan(): bool
     { // 激活套餐
-        Order::whereId($this->order->id)->first()->update(['expired_at' => date('Y-m-d H:i:s', strtotime(self::$goods->days.' days'))]);
+        $this->order->update(['expired_at' => date('Y-m-d H:i:s', strtotime(self::$goods->days.' days'))]);
         $oldData = self::$user->transfer_enable;
         $updateData = [
             'invite_num' => self::$user->invite_num + (self::$goods->invite_num ?: 0),
@@ -109,27 +117,23 @@ class OrderService
 
     public function resetTimeAndData(string|null $expired_at = null): array
     { // 计算下次重置与账号过期时间
-        $data = ['u' => 0, 'd' => 0];
-        // 账号有效期
-        if (! $expired_at) {
-            $expired_at = date('Y-m-d', strtotime(self::$goods->days.' days'));
-            foreach (Order::userPrepay($this->order->user_id)->with('goods')->get() as $paidOrder) {//拿出可能存在的其余套餐, 推算最新的到期时间
-                //取出对应套餐信息
-                $expired_at = date('Y-m-d', strtotime("$expired_at +".$paidOrder->goods->days.' days'));
-            }
-            $data['expired_at'] = $expired_at;
+        if (! $expired_at) { // 账号有效期
+            $expired_at = $this->getFinallyExpiredTime();
         }
 
         //账号流量重置日期
-        $nextResetTime = date('Y-m-d', strtotime(self::$goods->period.' days'));
+        $nextResetTime = now()->addDays(self::$goods->period)->format('Y-m-d');
         if ($nextResetTime >= $expired_at) {
             $nextResetTime = null;
         }
 
-        return array_merge($data, [
+        return [
+            'u' => 0,
+            'd' => 0,
             'transfer_enable' => self::$goods->traffic * MB,
+            'expired_at' => $expired_at,
             'reset_time' => $nextResetTime,
-        ]);
+        ];
     }
 
     private function setCommissionExpense(User $user)

+ 2 - 3
resources/views/admin/config/system.blade.php

@@ -125,7 +125,7 @@
                             <x-system.switch code="is_custom_subscribe" :check="$is_custom_subscribe"/>
                             <x-system.input code="web_api_url" :value="$web_api_url" type="url"/>
                             <x-system.input code="v2ray_license" :value="$v2ray_license"/>
-                            <x-system.input code="trojan_license" value="$trojan_license"/>
+                            <x-system.input code="trojan_license" :value="$trojan_license"/>
                             <x-system.input code="v2ray_tls_provider" :value="$v2ray_tls_provider"/>
                         </x-system.tab-pane>
                         <x-system.tab-pane id="extend">
@@ -473,8 +473,7 @@
 
       function disablePayment(op) {
         for (let i = 1; i < op.length; i++) {
-            @json($payments).
-          includes(op[i].value)
+            @json($payments).includes(op[i].value)
               ? op[i].disabled = false
               : op[i].disabled = true;
         }