ItemOutputLimit.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. <?php
  2. namespace App\Module\GameItems\Models;
  3. use Illuminate\Database\Eloquent\Relations\BelongsTo;
  4. use Illuminate\Database\Eloquent\Relations\HasMany;
  5. use UCore\ModelCore;
  6. /**
  7. * 物品产出限制
  8. *
  9. * field start
  10. * @property int $id 记录ID,主键
  11. * @property int $item_id 物品ID,外键关联kku_item_items表
  12. * @property int $limit_type 限制类型(1:全局总量, 2:单个用户, 3:单日全局, 4:单日用户)
  13. * @property int $max_quantity 最大产出数量
  14. * @property int $current_quantity 当前已产出数量(全局限制时使用)
  15. * @property int $reset_type 重置类型(0:不重置, 1:每日, 2:每周, 3:每月)
  16. * @property string $last_reset_time 上次重置时间
  17. * @property object|array $related_items 关联物品ID列表,这些物品共享同一个限制额度
  18. * @property \Carbon\Carbon $created_at 创建时间
  19. * @property \Carbon\Carbon $updated_at 更新时间
  20. * field end
  21. */
  22. class ItemOutputLimit extends ModelCore
  23. {
  24. /**
  25. * 与模型关联的表名
  26. *
  27. * @var string
  28. */
  29. protected $table = 'item_output_limits';
  30. // attrlist start
  31. protected $fillable = [
  32. 'id',
  33. 'item_id',
  34. 'limit_type',
  35. 'max_quantity',
  36. 'current_quantity',
  37. 'reset_type',
  38. 'last_reset_time',
  39. 'related_items',
  40. ];
  41. // attrlist end
  42. /**
  43. * 应该被转换为日期的属性
  44. *
  45. * @var array
  46. */
  47. protected $dates = [
  48. 'reset_time',
  49. 'created_at',
  50. 'updated_at',
  51. ];
  52. /**
  53. * 应该被转换为原生类型的属性
  54. *
  55. * @var array
  56. */
  57. protected $casts = [
  58. 'max_quantity' => 'integer',
  59. 'period_type' => 'integer',
  60. 'period_value' => 'integer',
  61. 'is_active' => 'boolean',
  62. ];
  63. /**
  64. * 限制类型常量
  65. */
  66. const LIMIT_TYPE_GLOBAL = 1; // 全局限制
  67. const LIMIT_TYPE_USER = 2; // 用户限制
  68. const LIMIT_TYPE_DAILY = 3; // 每日限制
  69. const LIMIT_TYPE_WEEKLY = 4; // 每周限制
  70. const LIMIT_TYPE_MONTHLY = 5; // 每月限制
  71. /**
  72. * 获取关联的物品
  73. *
  74. * @return BelongsTo
  75. */
  76. public function item(): BelongsTo
  77. {
  78. return $this->belongsTo(Item::class, 'item_id');
  79. }
  80. /**
  81. * 获取用户产出限制计数
  82. *
  83. * @return HasMany
  84. */
  85. public function userCounters(): HasMany
  86. {
  87. return $this->hasMany(ItemUserOutputCounter::class, 'limit_id');
  88. }
  89. /**
  90. * 检查是否达到全局限制
  91. *
  92. * @return bool
  93. */
  94. public function isGlobalLimitReached(): bool
  95. {
  96. if ($this->limit_type != self::LIMIT_TYPE_GLOBAL) {
  97. return false;
  98. }
  99. $totalCount = ItemUserOutputCounter::where('limit_id', $this->id)
  100. ->sum('current_count');
  101. return $totalCount >= $this->max_quantity;
  102. }
  103. /**
  104. * 检查用户是否达到限制
  105. *
  106. * @param int $userId 用户ID
  107. * @return bool
  108. */
  109. public function isUserLimitReached(int $userId): bool
  110. {
  111. if ($this->limit_type == self::LIMIT_TYPE_GLOBAL) {
  112. return $this->isGlobalLimitReached();
  113. }
  114. $counter = ItemUserOutputCounter::where('limit_id', $this->id)
  115. ->where('user_id', $userId)
  116. ->first();
  117. if (!$counter) {
  118. return false;
  119. }
  120. return $counter->current_count >= $this->max_quantity;
  121. }
  122. /**
  123. * 增加计数
  124. *
  125. * @param int $userId 用户ID
  126. * @param int $count 增加的数量
  127. * @return bool
  128. */
  129. public function incrementCount(int $userId, int $count = 1): bool
  130. {
  131. $counter = ItemUserOutputCounter::firstOrCreate(
  132. [
  133. 'limit_id' => $this->id,
  134. 'user_id' => $userId,
  135. ],
  136. [
  137. 'current_count' => 0,
  138. 'last_reset_time' => now(),
  139. ]
  140. );
  141. // 检查是否需要重置计数
  142. if ($this->shouldResetCounter($counter)) {
  143. $counter->current_count = 0;
  144. $counter->last_reset_time = now();
  145. }
  146. $counter->current_count += $count;
  147. return $counter->save();
  148. }
  149. /**
  150. * 检查是否应该重置计数器
  151. *
  152. * @param ItemUserOutputCounter $counter 计数器
  153. * @return bool
  154. */
  155. protected function shouldResetCounter(ItemUserOutputCounter $counter): bool
  156. {
  157. if (empty($counter->last_reset_time)) {
  158. return true;
  159. }
  160. switch ($this->limit_type) {
  161. case self::LIMIT_TYPE_DAILY:
  162. return $counter->last_reset_time->diffInDays(now()) >= 1;
  163. case self::LIMIT_TYPE_WEEKLY:
  164. return $counter->last_reset_time->diffInWeeks(now()) >= 1;
  165. case self::LIMIT_TYPE_MONTHLY:
  166. return $counter->last_reset_time->diffInMonths(now()) >= 1;
  167. default:
  168. return false;
  169. }
  170. }
  171. }