exists()) { throw new \Exception("服务代码已存在: {$data['code']}"); } // 设置默认值 $data = array_merge([ 'version' => 'v1', 'status' => SERVICE_STATUS::INACTIVE->value, 'priority' => 0, 'timeout' => config('thirdparty.defaults.timeout', 30), 'retry_times' => config('thirdparty.defaults.retry_times', 3), 'retry_delay' => config('thirdparty.defaults.retry_delay', 1000), 'health_check_interval' => config('thirdparty.defaults.health_check_interval', 300), 'health_status' => 'UNKNOWN', ], $data); return ThirdPartyService::create($data); } /** * 更新服务信息 * * @param ThirdPartyService $service * @param array $data * @return bool * @throws \Exception */ public static function updateService(ThirdPartyService $service, array $data): bool { // 如果更新服务类型,验证类型有效性 if (isset($data['type']) && !SERVICE_TYPE::tryFrom($data['type'])) { throw new \Exception("不支持的服务类型: {$data['type']}"); } // 如果更新认证类型,验证类型有效性 if (isset($data['auth_type']) && !AUTH_TYPE::tryFrom($data['auth_type'])) { throw new \Exception("不支持的认证类型: {$data['auth_type']}"); } // 如果更新代码,验证唯一性 if (isset($data['code']) && $data['code'] !== $service->code) { if (ThirdPartyService::where('code', $data['code'])->where('id', '!=', $service->id)->exists()) { throw new \Exception("服务代码已存在: {$data['code']}"); } } return $service->update($data); } /** * 删除服务 * * @param ThirdPartyService $service * @return bool * @throws \Exception */ public static function deleteService(ThirdPartyService $service): bool { // 检查服务是否有活跃的凭证 $activeCredentials = $service->credentials()->where('is_active', true)->count(); if ($activeCredentials > 0) { throw new \Exception("服务有 {$activeCredentials} 个活跃凭证,无法删除"); } // 检查服务状态 if ($service->status === SERVICE_STATUS::ACTIVE->value) { throw new \Exception("活跃状态的服务无法删除,请先停用服务"); } return $service->delete(); } /** * 更新服务状态 * * @param ThirdPartyService $service * @param string $status * @return bool * @throws \Exception */ public static function updateServiceStatus(ThirdPartyService $service, string $status): bool { $newStatus = SERVICE_STATUS::tryFrom($status); if (!$newStatus) { throw new \Exception("无效的服务状态: {$status}"); } $currentStatus = SERVICE_STATUS::from($service->status); // 检查状态转换是否允许 if (!$currentStatus->canTransitionTo($newStatus)) { throw new \Exception("不能从状态 {$currentStatus->getLabel()} 转换到 {$newStatus->getLabel()}"); } // 如果要激活服务,检查是否有可用的凭证 if ($newStatus === SERVICE_STATUS::ACTIVE) { $hasActiveCredential = $service->credentials() ->where('is_active', true) ->where(function ($query) { $query->whereNull('expires_at') ->orWhere('expires_at', '>', now()); }) ->exists(); if (!$hasActiveCredential) { throw new \Exception("服务没有可用的认证凭证,无法激活"); } } return $service->update(['status' => $status]); } /** * 获取服务列表 * * @param array $filters * @param array $options * @return Collection */ public static function getServiceList(array $filters = [], array $options = []): Collection { $query = ThirdPartyService::query(); // 应用过滤条件 if (isset($filters['type'])) { $query->where('type', $filters['type']); } if (isset($filters['status'])) { $query->where('status', $filters['status']); } if (isset($filters['provider'])) { $query->where('provider', $filters['provider']); } if (isset($filters['search'])) { $search = $filters['search']; $query->where(function ($q) use ($search) { $q->where('name', 'like', "%{$search}%") ->orWhere('code', 'like', "%{$search}%") ->orWhere('provider', 'like', "%{$search}%"); }); } // 应用排序 $sortBy = $options['sort_by'] ?? 'priority'; $sortOrder = $options['sort_order'] ?? 'asc'; $query->orderBy($sortBy, $sortOrder); // 如果优先级相同,按名称排序 if ($sortBy !== 'name') { $query->orderBy('name', 'asc'); } return $query->get(); } /** * 获取可用的服务列表 * * @param string|null $type * @return Collection */ public static function getAvailableServices(?string $type = null): Collection { $query = ThirdPartyService::query() ->where('status', SERVICE_STATUS::ACTIVE->value); if ($type) { $query->where('type', $type); } return $query->orderBy('priority')->orderBy('name')->get(); } /** * 根据代码获取服务 * * @param string $code * @return ThirdPartyService|null */ public static function getServiceByCode(string $code): ?ThirdPartyService { return ThirdPartyService::where('code', $code)->first(); } /** * 检查服务健康状态 * * @param ThirdPartyService $service * @return array */ public static function checkServiceHealth(ThirdPartyService $service): array { $result = [ 'service_id' => $service->id, 'service_code' => $service->code, 'status' => 'unknown', 'message' => '', 'details' => [], ]; try { // 检查服务状态 if (!$service->isAvailable()) { $result['status'] = 'unavailable'; $result['message'] = "服务状态为 {$service->getStatusLabel()},不可用"; return $result; } // 检查认证凭证 $credential = $service->getActiveCredential(); if (!$credential) { $result['status'] = 'error'; $result['message'] = '没有可用的认证凭证'; return $result; } if ($credential->isExpired()) { $result['status'] = 'error'; $result['message'] = '认证凭证已过期'; return $result; } // 检查配额 $quotaStatus = static::checkServiceQuota($service); if (!$quotaStatus['available']) { $result['status'] = 'quota_exceeded'; $result['message'] = '服务配额已用完'; $result['details']['quota'] = $quotaStatus; return $result; } $result['status'] = 'healthy'; $result['message'] = '服务健康'; $result['details'] = [ 'credential_expires_at' => $credential->expires_at?->toDateTimeString(), 'quota' => $quotaStatus, ]; } catch (\Exception $e) { $result['status'] = 'error'; $result['message'] = $e->getMessage(); } return $result; } /** * 检查服务配额状态 * * @param ThirdPartyService $service * @return array */ public static function checkServiceQuota(ThirdPartyService $service): array { $quotas = $service->quotas()->active()->get(); $result = [ 'available' => true, 'quotas' => [], ]; foreach ($quotas as $quota) { $quotaInfo = [ 'type' => $quota->type, 'limit' => $quota->limit_value, 'used' => $quota->used_value, 'remaining' => $quota->getRemainingQuota(), 'percentage' => $quota->getUsagePercentage(), 'exceeded' => $quota->isExceeded(), 'near_threshold' => $quota->isNearThreshold(), ]; $result['quotas'][] = $quotaInfo; if ($quota->isExceeded()) { $result['available'] = false; } } return $result; } /** * 生成唯一的服务代码 * * @param string $name * @param string $provider * @return string */ protected static function generateUniqueCode(string $name, string $provider): string { $code = strtolower($provider . '_' . str_replace([' ', '-', '.'], '_', $name)); $code = preg_replace('/[^a-z0-9_]/', '', $code); // 确保代码唯一 $counter = 1; $originalCode = $code; while (ThirdPartyService::where('code', $code)->exists()) { $code = $originalCode . '_' . $counter; $counter++; } return $code; } /** * 获取服务统计信息 * * @return array */ public static function getServiceStats(): array { $total = ThirdPartyService::count(); $active = ThirdPartyService::where('status', SERVICE_STATUS::ACTIVE->value)->count(); $inactive = ThirdPartyService::where('status', SERVICE_STATUS::INACTIVE->value)->count(); $error = ThirdPartyService::where('status', SERVICE_STATUS::ERROR->value)->count(); $typeStats = ThirdPartyService::selectRaw('type, COUNT(*) as count') ->groupBy('type') ->pluck('count', 'type') ->toArray(); return [ 'total' => $total, 'active' => $active, 'inactive' => $inactive, 'error' => $error, 'by_type' => $typeStats, 'health_rate' => $total > 0 ? round(($active / $total) * 100, 2) : 0, ]; } }