User.php 8.1 KB

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