where('type', $data['type']) ->first(); if ($existing) { throw new \Exception("服务已存在 {$data['type']} 类型的配额"); } return ThirdPartyQuota::createQuota($data); } /** * 更新配额 * * @param int $quotaId * @param array $data * @return bool * @throws \Exception */ public static function update(int $quotaId, array $data): bool { $quota = ThirdPartyQuota::findOrFail($quotaId); // 如果更新配额类型,验证唯一性 if (isset($data['type']) && $data['type'] !== $quota->type) { if (!QUOTA_TYPE::tryFrom($data['type'])) { throw new \Exception("无效的配额类型: {$data['type']}"); } $existing = ThirdPartyQuota::where('service_id', $quota->service_id) ->where('type', $data['type']) ->where('id', '!=', $quotaId) ->first(); if ($existing) { throw new \Exception("服务已存在 {$data['type']} 类型的配额"); } } return $quota->update($data); } /** * 删除配额 * * @param int $quotaId * @return bool */ public static function delete(int $quotaId): bool { $quota = ThirdPartyQuota::findOrFail($quotaId); return $quota->delete(); } /** * 获取配额详情 * * @param int $quotaId * @return ThirdPartyQuota */ public static function getById(int $quotaId): ThirdPartyQuota { return ThirdPartyQuota::with('service')->findOrFail($quotaId); } /** * 获取配额列表 * * @param array $filters * @param array $options * @return Collection */ public static function getList(array $filters = [], array $options = []): Collection { $query = ThirdPartyQuota::with('service'); // 应用过滤条件 if (isset($filters['service_id'])) { $query->where('service_id', $filters['service_id']); } if (isset($filters['type'])) { $query->where('type', $filters['type']); } if (isset($filters['is_active'])) { $query->where('is_active', $filters['is_active']); } if (isset($filters['is_exceeded'])) { $query->where('is_exceeded', $filters['is_exceeded']); } if (isset($filters['near_threshold'])) { if ($filters['near_threshold']) { $query->nearThreshold(); } } // 应用排序 $sortBy = $options['sort_by'] ?? 'created_at'; $sortOrder = $options['sort_order'] ?? 'desc'; $query->orderBy($sortBy, $sortOrder); return $query->get(); } /** * 检查配额是否可用 * * @param int $serviceId * @param int $amount * @return bool */ public static function canUse(int $serviceId, int $amount = 1): bool { $quotas = ThirdPartyQuota::where('service_id', $serviceId) ->where('is_active', true) ->get(); foreach ($quotas as $quota) { if (!$quota->canUse($amount)) { return false; } } return true; } /** * 使用配额 * * @param int $serviceId * @param int $amount * @return bool */ public static function use(int $serviceId, int $amount = 1): bool { $quotas = ThirdPartyQuota::where('service_id', $serviceId) ->where('is_active', true) ->get(); foreach ($quotas as $quota) { $quota->incrementUsage($amount); } return true; } /** * 重置配额 * * @param int $quotaId * @return bool */ public static function reset(int $quotaId): bool { $quota = ThirdPartyQuota::findOrFail($quotaId); return $quota->resetQuota(); } /** * 批量重置配额 * * @param array $quotaIds * @return array */ public static function batchReset(array $quotaIds): array { $results = [ 'success' => [], 'failed' => [], ]; foreach ($quotaIds as $quotaId) { try { static::reset($quotaId); $results['success'][] = $quotaId; } catch (\Exception $e) { $results['failed'][] = [ 'id' => $quotaId, 'error' => $e->getMessage(), ]; } } return $results; } /** * 获取需要重置的配额 * * @return Collection */ public static function getQuotasNeedingReset(): Collection { return ThirdPartyQuota::where('is_active', true) ->get() ->filter(function ($quota) { return $quota->needsReset(); }); } /** * 自动重置配额 * * @return int 重置数量 */ public static function autoReset(): int { $quotas = static::getQuotasNeedingReset(); $resetCount = 0; foreach ($quotas as $quota) { try { $quota->resetQuota(); $resetCount++; } catch (\Exception $e) { \Log::warning("自动重置配额失败: {$quota->id}, 错误: {$e->getMessage()}"); } } return $resetCount; } /** * 获取超限的配额 * * @return Collection */ public static function getExceededQuotas(): Collection { return ThirdPartyQuota::with('service') ->where('is_active', true) ->where('is_exceeded', true) ->get(); } /** * 获取接近阈值的配额 * * @return Collection */ public static function getNearThresholdQuotas(): Collection { return ThirdPartyQuota::with('service') ->where('is_active', true) ->nearThreshold() ->get(); } /** * 获取配额统计信息 * * @param int|null $serviceId * @return array */ public static function getStats(?int $serviceId = null): array { $query = ThirdPartyQuota::query(); if ($serviceId) { $query->where('service_id', $serviceId); } $total = $query->count(); $active = $query->where('is_active', true)->count(); $exceeded = $query->where('is_exceeded', true)->count(); $nearThreshold = $query->nearThreshold()->count(); // 按类型统计 $typeStats = $query->selectRaw('type, COUNT(*) as count') ->groupBy('type') ->pluck('count', 'type') ->toArray(); // 使用率统计 $usageStats = $query->where('is_active', true) ->get() ->map(function ($quota) { return [ 'service_name' => $quota->service->name, 'type' => $quota->type, 'usage_percentage' => $quota->getUsagePercentage(), 'status' => $quota->getStatus(), ]; }) ->toArray(); return [ 'total' => $total, 'active' => $active, 'exceeded' => $exceeded, 'near_threshold' => $nearThreshold, 'by_type' => $typeStats, 'usage_stats' => $usageStats, 'health_rate' => $total > 0 ? round((($active - $exceeded) / $total) * 100, 2) : 0, ]; } /** * 创建默认配额 * * @param int $serviceId * @return array */ public static function createDefaultQuotas(int $serviceId): array { $service = ThirdPartyService::findOrFail($serviceId); $defaultLimits = config('thirdparty.quota.default_limits', []); $created = []; foreach ($defaultLimits as $type => $limit) { try { $quota = static::create([ 'service_id' => $serviceId, 'type' => $type, 'limit_value' => $limit, 'is_active' => true, ]); $created[] = $quota; } catch (\Exception $e) { // 如果配额已存在,跳过 if (!str_contains($e->getMessage(), '已存在')) { throw $e; } } } return $created; } /** * 导出配额配置 * * @param array $quotaIds * @return array */ public static function export(array $quotaIds = []): array { $query = ThirdPartyQuota::with('service'); if (!empty($quotaIds)) { $query->whereIn('id', $quotaIds); } $quotas = $query->get(); $exported = []; foreach ($quotas as $quota) { $exported[] = [ 'id' => $quota->id, 'service_name' => $quota->service->name, 'service_code' => $quota->service->code, 'type' => $quota->type, 'type_label' => $quota->getTypeLabel(), 'limit_value' => $quota->limit_value, 'used_value' => $quota->used_value, 'usage_percentage' => $quota->getUsagePercentage(), 'is_active' => $quota->is_active, 'alert_threshold' => $quota->alert_threshold, 'is_exceeded' => $quota->is_exceeded, 'status' => $quota->getStatusLabel(), 'created_at' => $quota->created_at->toDateTimeString(), ]; } return $exported; } }