*/ protected $fillable = [ 'pet_id', 'skill_id', 'skill_name', 'start_time', 'end_time', 'status', 'config', 'last_check_time', ]; /** * 属性类型转换 * * @var array */ protected $casts = [ 'start_time' => 'datetime', 'end_time' => 'datetime', 'config' => 'array', 'last_check_time' => 'datetime', 'created_at' => 'datetime', 'updated_at' => 'datetime', ]; /** * 技能状态常量 */ const STATUS_ACTIVE = 'active'; // 生效中 const STATUS_EXPIRED = 'expired'; // 已过期 const STATUS_CANCELLED = 'cancelled'; // 已取消 /** * 关联宠物 * * @return BelongsTo */ public function pet(): BelongsTo { return $this->belongsTo(PetUser::class, 'pet_id'); } /** * 关联技能配置 * * @return BelongsTo */ public function skill(): BelongsTo { return $this->belongsTo(PetSkill::class, 'skill_id'); } /** * 检查技能是否仍然有效 * * @return bool */ public function isActive(): bool { return $this->status === self::STATUS_ACTIVE && $this->end_time > now(); } /** * 检查技能是否已过期 * * @return bool */ public function isExpired(): bool { return $this->end_time <= now(); } /** * 获取剩余时间(秒) * * @return int */ public function getRemainingSeconds(): int { if ($this->isExpired()) { return 0; } return now()->diffInSeconds($this->end_time); } /** * 标记技能为已过期 * * @return bool */ public function markAsExpired(): bool { $this->status = self::STATUS_EXPIRED; return $this->save(); } /** * 取消技能 * * @return bool */ public function cancel(): bool { $this->status = self::STATUS_CANCELLED; return $this->save(); } /** * 更新最后检查时间 * * @return bool */ public function updateLastCheckTime(): bool { $this->last_check_time = now(); return $this->save(); } /** * 获取最后检查时间 * * @return \Carbon\Carbon|null */ public function getLastCheckTime(): ?\Carbon\Carbon { return $this->last_check_time; } /** * 检查是否需要执行检查 * * @return bool */ public function shouldCheck(): bool { if (!$this->isActive()) { return false; } $lastCheckTime = $this->getLastCheckTime(); if (!$lastCheckTime) { return true; } $config = $this->config; // 确保config是数组类型 if (!is_array($config)) { if (is_string($config)) { $config = json_decode($config, true); if (json_last_error() !== JSON_ERROR_NONE) { $config = []; } } else { $config = []; } } $checkInterval = $config['check_interval'] ?? 60; // 默认60秒 $diffSeconds = $lastCheckTime->diffInSeconds(now()); return $diffSeconds >= $checkInterval; } /** * 获取技能配置中的特定值 * * @param string $key 配置键名 * @param mixed $default 默认值 * @return mixed */ public function getConfigValue(string $key, $default = null) { $config = $this->config; // 确保config是数组类型 if (!is_array($config)) { if (is_string($config)) { $config = json_decode($config, true); if (json_last_error() !== JSON_ERROR_NONE) { return $default; } } else { return $default; } } return $config[$key] ?? $default; } /** * 设置技能配置中的特定值 * * @param string $key 配置键名 * @param mixed $value 配置值 * @return bool */ public function setConfigValue(string $key, $value): bool { $config = $this->config; // 确保config是数组类型 if (!is_array($config)) { if (is_string($config)) { $config = json_decode($config, true); if (json_last_error() !== JSON_ERROR_NONE) { $config = []; } } else { $config = []; } } $config[$key] = $value; $this->config = $config; return $this->save(); } /** * 查询生效中的技能 * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopeActive($query) { return $query->where('status', self::STATUS_ACTIVE) ->where('end_time', '>', now()); } /** * 查询已过期的技能 * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopeExpired($query) { return $query->where('end_time', '<=', now()); } /** * 查询特定技能类型 * * @param \Illuminate\Database\Eloquent\Builder $query * @param string $skillName 技能名称 * @return \Illuminate\Database\Eloquent\Builder */ public function scopeBySkillName($query, string $skillName) { return $query->where('skill_name', $skillName); } /** * 查询特定宠物的技能 * * @param \Illuminate\Database\Eloquent\Builder $query * @param int $petId 宠物ID * @return \Illuminate\Database\Eloquent\Builder */ public function scopeByPet($query, int $petId) { return $query->where('pet_id', $petId); } /** * 按最后检查时间排序 * * @param \Illuminate\Database\Eloquent\Builder $query * @param string $direction 排序方向:asc或desc * @return \Illuminate\Database\Eloquent\Builder */ public function scopeOrderByLastCheckTime($query, string $direction = 'desc') { return $query->orderBy('last_check_time', $direction); } /** * 查询需要检查的技能(基于最后检查时间和检查间隔) * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopeNeedCheck($query) { return $query->where('status', self::STATUS_ACTIVE) ->where('end_time', '>', now()) ->where(function ($subQuery) { $subQuery->whereNull('last_check_time') ->orWhereRaw('TIMESTAMPDIFF(SECOND, last_check_time, NOW()) >= JSON_UNQUOTE(JSON_EXTRACT(config, "$.check_interval"))'); }); } /** * 查询最后检查时间在指定时间之前的技能 * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Carbon\Carbon $time 时间点 * @return \Illuminate\Database\Eloquent\Builder */ public function scopeLastCheckBefore($query, \Carbon\Carbon $time) { return $query->where(function ($subQuery) use ($time) { $subQuery->whereNull('last_check_time') ->orWhere('last_check_time', '<', $time); }); } /** * 查询最后检查时间在指定时间之后的技能 * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Carbon\Carbon $time 时间点 * @return \Illuminate\Database\Eloquent\Builder */ public function scopeLastCheckAfter($query, \Carbon\Carbon $time) { return $query->where('last_check_time', '>', $time); } /** * 查询最后检查时间在指定时间范围内的技能 * * @param \Illuminate\Database\Eloquent\Builder $query * @param \Carbon\Carbon $start 开始时间 * @param \Carbon\Carbon $end 结束时间 * @return \Illuminate\Database\Eloquent\Builder */ public function scopeLastCheckBetween($query, \Carbon\Carbon $start, \Carbon\Carbon $end) { return $query->whereBetween('last_check_time', [$start, $end]); } }