User.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. <?php
  2. namespace App\Models;
  3. use App\Casts\data_rate;
  4. use App\Casts\money;
  5. use App\Observers\UserObserver;
  6. use App\Utils\Avatar;
  7. use App\Utils\Helpers;
  8. use Hash;
  9. use Hashids\Hashids;
  10. use Illuminate\Database\Eloquent\Attributes\ObservedBy;
  11. use Illuminate\Database\Eloquent\Builder;
  12. use Illuminate\Database\Eloquent\Factories\HasFactory;
  13. use Illuminate\Database\Eloquent\Relations\BelongsTo;
  14. use Illuminate\Database\Eloquent\Relations\HasMany;
  15. use Illuminate\Database\Eloquent\Relations\HasManyThrough;
  16. use Illuminate\Database\Eloquent\Relations\HasOne;
  17. use Illuminate\Foundation\Auth\User as Authenticatable;
  18. use Illuminate\Notifications\Notifiable;
  19. use Kyslik\ColumnSortable\Sortable;
  20. use Laravel\Sanctum\HasApiTokens;
  21. use Spatie\Permission\Traits\HasRoles;
  22. /**
  23. * 用户信息.
  24. */
  25. #[ObservedBy([UserObserver::class])]
  26. class User extends Authenticatable
  27. {
  28. use HasApiTokens, HasFactory, HasRoles, Notifiable, Sortable;
  29. public array $sortable = ['id', 'credit', 'port', 't', 'expired_at'];
  30. protected $table = 'user';
  31. 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'];
  32. protected $guarded = [];
  33. public function routeNotificationForMail($notification): string
  34. {
  35. return $this->username;
  36. }
  37. public function onlineIpLogs(): HasMany
  38. {
  39. return $this->hasMany(NodeOnlineIp::class);
  40. }
  41. public function payments(): HasMany
  42. {
  43. return $this->hasMany(Payment::class);
  44. }
  45. public function commissionSettlements(): HasMany
  46. {
  47. return $this->hasMany(ReferralApply::class);
  48. }
  49. public function commissionLogs(): HasMany
  50. {
  51. return $this->hasMany(ReferralLog::class, 'inviter_id');
  52. }
  53. public function ruleLogs(): HasMany
  54. {
  55. return $this->hasMany(RuleLog::class);
  56. }
  57. public function tickets(): HasMany
  58. {
  59. return $this->hasMany(Ticket::class);
  60. }
  61. public function ticketReplies(): HasMany
  62. {
  63. return $this->hasMany(TicketReply::class);
  64. }
  65. public function banedLogs(): HasMany
  66. {
  67. return $this->hasMany(UserBanedLog::class);
  68. }
  69. public function creditLogs(): HasMany
  70. {
  71. return $this->hasMany(UserCreditLog::class);
  72. }
  73. public function dailyDataFlows(): HasMany
  74. {
  75. return $this->hasMany(UserDailyDataFlow::class);
  76. }
  77. public function dataFlowLogs(): HasMany
  78. {
  79. return $this->hasMany(UserDataFlowLog::class);
  80. }
  81. public function dataModifyLogs(): HasMany
  82. {
  83. return $this->hasMany(UserDataModifyLog::class);
  84. }
  85. public function hourlyDataFlows(): HasMany
  86. {
  87. return $this->HasMany(UserHourlyDataFlow::class);
  88. }
  89. public function loginLogs(): HasMany
  90. {
  91. return $this->HasMany(UserLoginLog::class);
  92. }
  93. public function latestLoginLog(): HasOne
  94. {
  95. return $this->hasOne(UserLoginLog::class)->latestOfMany();
  96. }
  97. public function subscribe(): HasOne
  98. {
  99. return $this->hasOne(UserSubscribe::class);
  100. }
  101. public function subscribeLogs(): HasManyThrough
  102. {
  103. return $this->hasManyThrough(UserSubscribeLog::class, UserSubscribe::class);
  104. }
  105. public function verify(): HasMany
  106. {
  107. return $this->hasMany(Verify::class);
  108. }
  109. public function inviter(): BelongsTo
  110. {
  111. return $this->belongsTo(__CLASS__);
  112. }
  113. public function invites(): HasMany
  114. {
  115. return $this->hasMany(Invite::class, 'inviter_id');
  116. }
  117. public function invitees(): HasMany
  118. {
  119. return $this->hasMany(__CLASS__, 'inviter_id');
  120. }
  121. public function userGroup(): BelongsTo
  122. {
  123. return $this->belongsTo(UserGroup::class);
  124. }
  125. public function orders(): HasMany
  126. {
  127. return $this->hasMany(Order::class);
  128. }
  129. public function paidOrders(): hasMany
  130. {
  131. return $this->hasMany(Order::class)->where('status', 2)->whereNotNull('goods_id')->where('is_expire', 0)->where('amount', '>', 0);
  132. }
  133. public function scopeActiveUser(Builder $query): Builder
  134. {
  135. return $query->where('status', '<>', -1)->whereEnable(1);
  136. }
  137. public function scopeBannedUser(Builder $query): Builder
  138. {
  139. return $query->where('status', '<>', -1)->whereEnable(0);
  140. }
  141. public function getExpirationDateAttribute(): ?string
  142. {
  143. return $this->attributes['expired_at'];
  144. }
  145. public function getResetDateAttribute(): ?string
  146. {
  147. return $this->attributes['reset_time'];
  148. }
  149. public function getTelegramUserIdAttribute(): ?string
  150. {
  151. $telegram = $this->userAuths()->whereType('telegram')->first();
  152. return $telegram->identifier ?? null;
  153. }
  154. public function userAuths(): HasMany
  155. {
  156. return $this->hasMany(UserOauth::class);
  157. }
  158. public function getCreditTagAttribute(): string
  159. {
  160. return Helpers::getPriceTag($this->credit);
  161. }
  162. public function getTransferEnableFormattedAttribute(): string
  163. {
  164. return formatBytes($this->attributes['transfer_enable']);
  165. }
  166. public function getExpirationStatusAttribute(): int
  167. {
  168. $today = date('Y-m-d');
  169. $nextMonth = date('Y-m-d', strtotime('next month'));
  170. if ($this->expiration_date < $today) {
  171. $status = 0; // 已过期
  172. } elseif ($this->expiration_date === $today) {
  173. $status = 1; // 今日过期
  174. } elseif ($this->expiration_date <= $nextMonth) {
  175. $status = 2; // 一个月内过期
  176. }
  177. return $status ?? 3;
  178. }
  179. public function getSubUrlAttribute(): string
  180. {
  181. return route('sub', $this->subscribe->code);
  182. }
  183. public function getInviteCodeAttribute(): string
  184. {
  185. $uid = $this->id;
  186. $affSalt = sysConfig('affiliate_link_salt');
  187. return empty($affSalt) ? $uid : (new Hashids($affSalt, 8))->encode($uid);
  188. }
  189. public function getInviteUrlAttribute(): string
  190. {
  191. return sysConfig('website_url').route('register', ['aff' => $this->invite_code], false);
  192. }
  193. public function getUsedTrafficAttribute(): int
  194. {
  195. return $this->d + $this->u;
  196. }
  197. public function getUnusedTrafficAttribute(): int
  198. {
  199. return max($this->transfer_enable - $this->d - $this->u, 0);
  200. }
  201. public function getAvatarAttribute(): string
  202. {
  203. return session()->remember('avatar_url_'.$this->id, function () {
  204. if ($this->qq) {
  205. return Avatar::getQQAvatar($this->qq);
  206. }
  207. if (str(str($this->username)->lower())->endsWith('@qq.com')) {
  208. return Avatar::getQQAvatar($this->username);
  209. }
  210. return Avatar::getRandomAvatar($this->username);
  211. });
  212. }
  213. public function getLevelNameAttribute(): string
  214. {
  215. return Level::where('level', $this->level)->value('name');
  216. }
  217. public function setPasswordAttribute(string $password): string
  218. {
  219. return $this->attributes['password'] = Hash::make($password);
  220. }
  221. public function nodes(?int $userLevel = null, ?int $userGroupId = null): Builder
  222. {
  223. if ($userGroupId === null && $this->user_group_id) { // 使用默认的用户分组
  224. $query = $this->userGroup->nodes()->getQuery();
  225. } elseif ($userGroupId) { // 使用给的用户分组
  226. $query = UserGroup::findOrFail($userGroupId)->nodes()->getQuery();
  227. } else { // 无用户分组
  228. $query = Node::query();
  229. }
  230. return $query->whereStatus(1)->where('level', '<=', $userLevel ?? $this->level ?? 0);
  231. }
  232. public function updateCredit(float $credit): bool
  233. {
  234. $this->credit += $credit;
  235. return $this->credit >= 0 && $this->save();
  236. }
  237. public function incrementData(int $data): bool
  238. { // 添加用户流量
  239. $this->transfer_enable += $data;
  240. return $this->save();
  241. }
  242. public function routeNotificationForTelegram()
  243. {
  244. return $this->telegram_user_id;
  245. }
  246. }