PetActiveSkill.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. <?php
  2. namespace App\Module\Pet\Models;
  3. use UCore\ModelCore;
  4. use Illuminate\Database\Eloquent\Relations\BelongsTo;
  5. /**
  6. * 宠物激活技能模型
  7. *
  8. * 用于记录宠物当前激活的技能状态,支持定时任务自动处理
  9. *
  10. * @property int $id 主键ID
  11. * @property int $pet_id 宠物ID
  12. * @property int $skill_id 技能ID
  13. * @property string $skill_name 技能名称
  14. * @property \Carbon\Carbon $start_time 开始时间
  15. * @property \Carbon\Carbon $end_time 结束时间
  16. * @property string $status 状态:active-生效中,expired-已过期,cancelled-已取消
  17. * @property array $config 技能配置信息
  18. * @property \Carbon\Carbon|null $last_check_time 最后检查时间
  19. * @property \Carbon\Carbon $created_at 创建时间
  20. * @property \Carbon\Carbon $updated_at 更新时间
  21. */
  22. class PetActiveSkill extends ModelCore
  23. {
  24. /**
  25. * 数据表名
  26. *
  27. * @var string
  28. */
  29. protected $table = 'pet_active_skills';
  30. /**
  31. * 可批量赋值的属性
  32. *
  33. * @var array<int, string>
  34. */
  35. protected $fillable = [
  36. 'pet_id',
  37. 'skill_id',
  38. 'skill_name',
  39. 'start_time',
  40. 'end_time',
  41. 'status',
  42. 'config',
  43. 'last_check_time',
  44. ];
  45. /**
  46. * 属性类型转换
  47. *
  48. * @var array<string, string>
  49. */
  50. protected $casts = [
  51. 'start_time' => 'datetime',
  52. 'end_time' => 'datetime',
  53. 'config' => 'array',
  54. 'last_check_time' => 'datetime',
  55. 'created_at' => 'datetime',
  56. 'updated_at' => 'datetime',
  57. ];
  58. /**
  59. * 技能状态常量
  60. */
  61. const STATUS_ACTIVE = 'active'; // 生效中
  62. const STATUS_EXPIRED = 'expired'; // 已过期
  63. const STATUS_CANCELLED = 'cancelled'; // 已取消
  64. /**
  65. * 关联宠物
  66. *
  67. * @return BelongsTo
  68. */
  69. public function pet(): BelongsTo
  70. {
  71. return $this->belongsTo(PetUser::class, 'pet_id');
  72. }
  73. /**
  74. * 关联技能配置
  75. *
  76. * @return BelongsTo
  77. */
  78. public function skill(): BelongsTo
  79. {
  80. return $this->belongsTo(PetSkill::class, 'skill_id');
  81. }
  82. /**
  83. * 检查技能是否仍然有效
  84. *
  85. * @return bool
  86. */
  87. public function isActive(): bool
  88. {
  89. return $this->status === self::STATUS_ACTIVE && $this->end_time > now();
  90. }
  91. /**
  92. * 检查技能是否已过期
  93. *
  94. * @return bool
  95. */
  96. public function isExpired(): bool
  97. {
  98. return $this->end_time <= now();
  99. }
  100. /**
  101. * 获取剩余时间(秒)
  102. *
  103. * @return int
  104. */
  105. public function getRemainingSeconds(): int
  106. {
  107. if ($this->isExpired()) {
  108. return 0;
  109. }
  110. return now()->diffInSeconds($this->end_time);
  111. }
  112. /**
  113. * 标记技能为已过期
  114. *
  115. * @return bool
  116. */
  117. public function markAsExpired(): bool
  118. {
  119. $this->status = self::STATUS_EXPIRED;
  120. return $this->save();
  121. }
  122. /**
  123. * 取消技能
  124. *
  125. * @return bool
  126. */
  127. public function cancel(): bool
  128. {
  129. $this->status = self::STATUS_CANCELLED;
  130. return $this->save();
  131. }
  132. /**
  133. * 更新最后检查时间
  134. *
  135. * @return bool
  136. */
  137. public function updateLastCheckTime(): bool
  138. {
  139. $this->last_check_time = now();
  140. return $this->save();
  141. }
  142. /**
  143. * 获取最后检查时间
  144. *
  145. * @return \Carbon\Carbon|null
  146. */
  147. public function getLastCheckTime(): ?\Carbon\Carbon
  148. {
  149. return $this->last_check_time;
  150. }
  151. /**
  152. * 检查是否需要执行检查
  153. *
  154. * @return bool
  155. */
  156. public function shouldCheck(): bool
  157. {
  158. if (!$this->isActive()) {
  159. return false;
  160. }
  161. $lastCheckTime = $this->getLastCheckTime();
  162. if (!$lastCheckTime) {
  163. return true;
  164. }
  165. $config = $this->config;
  166. // 确保config是数组类型
  167. if (!is_array($config)) {
  168. if (is_string($config)) {
  169. $config = json_decode($config, true);
  170. if (json_last_error() !== JSON_ERROR_NONE) {
  171. $config = [];
  172. }
  173. } else {
  174. $config = [];
  175. }
  176. }
  177. $checkInterval = $config['check_interval'] ?? 60; // 默认60秒
  178. $diffSeconds = $lastCheckTime->diffInSeconds(now());
  179. return $diffSeconds >= $checkInterval;
  180. }
  181. /**
  182. * 获取技能配置中的特定值
  183. *
  184. * @param string $key 配置键名
  185. * @param mixed $default 默认值
  186. * @return mixed
  187. */
  188. public function getConfigValue(string $key, $default = null)
  189. {
  190. $config = $this->config;
  191. // 确保config是数组类型
  192. if (!is_array($config)) {
  193. if (is_string($config)) {
  194. $config = json_decode($config, true);
  195. if (json_last_error() !== JSON_ERROR_NONE) {
  196. return $default;
  197. }
  198. } else {
  199. return $default;
  200. }
  201. }
  202. return $config[$key] ?? $default;
  203. }
  204. /**
  205. * 设置技能配置中的特定值
  206. *
  207. * @param string $key 配置键名
  208. * @param mixed $value 配置值
  209. * @return bool
  210. */
  211. public function setConfigValue(string $key, $value): bool
  212. {
  213. $config = $this->config;
  214. // 确保config是数组类型
  215. if (!is_array($config)) {
  216. if (is_string($config)) {
  217. $config = json_decode($config, true);
  218. if (json_last_error() !== JSON_ERROR_NONE) {
  219. $config = [];
  220. }
  221. } else {
  222. $config = [];
  223. }
  224. }
  225. $config[$key] = $value;
  226. $this->config = $config;
  227. return $this->save();
  228. }
  229. /**
  230. * 查询生效中的技能
  231. *
  232. * @param \Illuminate\Database\Eloquent\Builder $query
  233. * @return \Illuminate\Database\Eloquent\Builder
  234. */
  235. public function scopeActive($query)
  236. {
  237. return $query->where('status', self::STATUS_ACTIVE)
  238. ->where('end_time', '>', now());
  239. }
  240. /**
  241. * 查询已过期的技能
  242. *
  243. * @param \Illuminate\Database\Eloquent\Builder $query
  244. * @return \Illuminate\Database\Eloquent\Builder
  245. */
  246. public function scopeExpired($query)
  247. {
  248. return $query->where('end_time', '<=', now());
  249. }
  250. /**
  251. * 查询特定技能类型
  252. *
  253. * @param \Illuminate\Database\Eloquent\Builder $query
  254. * @param string $skillName 技能名称
  255. * @return \Illuminate\Database\Eloquent\Builder
  256. */
  257. public function scopeBySkillName($query, string $skillName)
  258. {
  259. return $query->where('skill_name', $skillName);
  260. }
  261. /**
  262. * 查询特定宠物的技能
  263. *
  264. * @param \Illuminate\Database\Eloquent\Builder $query
  265. * @param int $petId 宠物ID
  266. * @return \Illuminate\Database\Eloquent\Builder
  267. */
  268. public function scopeByPet($query, int $petId)
  269. {
  270. return $query->where('pet_id', $petId);
  271. }
  272. /**
  273. * 按最后检查时间排序
  274. *
  275. * @param \Illuminate\Database\Eloquent\Builder $query
  276. * @param string $direction 排序方向:asc或desc
  277. * @return \Illuminate\Database\Eloquent\Builder
  278. */
  279. public function scopeOrderByLastCheckTime($query, string $direction = 'desc')
  280. {
  281. return $query->orderBy('last_check_time', $direction);
  282. }
  283. /**
  284. * 查询需要检查的技能(基于最后检查时间和检查间隔)
  285. *
  286. * @param \Illuminate\Database\Eloquent\Builder $query
  287. * @return \Illuminate\Database\Eloquent\Builder
  288. */
  289. public function scopeNeedCheck($query)
  290. {
  291. return $query->where('status', self::STATUS_ACTIVE)
  292. ->where('end_time', '>', now())
  293. ->where(function ($subQuery) {
  294. $subQuery->whereNull('last_check_time')
  295. ->orWhereRaw('TIMESTAMPDIFF(SECOND, last_check_time, NOW()) >= JSON_UNQUOTE(JSON_EXTRACT(config, "$.check_interval"))');
  296. });
  297. }
  298. /**
  299. * 查询最后检查时间在指定时间之前的技能
  300. *
  301. * @param \Illuminate\Database\Eloquent\Builder $query
  302. * @param \Carbon\Carbon $time 时间点
  303. * @return \Illuminate\Database\Eloquent\Builder
  304. */
  305. public function scopeLastCheckBefore($query, \Carbon\Carbon $time)
  306. {
  307. return $query->where(function ($subQuery) use ($time) {
  308. $subQuery->whereNull('last_check_time')
  309. ->orWhere('last_check_time', '<', $time);
  310. });
  311. }
  312. /**
  313. * 查询最后检查时间在指定时间之后的技能
  314. *
  315. * @param \Illuminate\Database\Eloquent\Builder $query
  316. * @param \Carbon\Carbon $time 时间点
  317. * @return \Illuminate\Database\Eloquent\Builder
  318. */
  319. public function scopeLastCheckAfter($query, \Carbon\Carbon $time)
  320. {
  321. return $query->where('last_check_time', '>', $time);
  322. }
  323. /**
  324. * 查询最后检查时间在指定时间范围内的技能
  325. *
  326. * @param \Illuminate\Database\Eloquent\Builder $query
  327. * @param \Carbon\Carbon $start 开始时间
  328. * @param \Carbon\Carbon $end 结束时间
  329. * @return \Illuminate\Database\Eloquent\Builder
  330. */
  331. public function scopeLastCheckBetween($query, \Carbon\Carbon $start, \Carbon\Carbon $end)
  332. {
  333. return $query->whereBetween('last_check_time', [$start, $end]);
  334. }
  335. }