From 7fc55ab9c323fbd3b8aed345f8b3e7e24ecbaab2 Mon Sep 17 00:00:00 2001 From: 54CHA Date: Thu, 17 Jul 2025 21:22:20 +0300 Subject: [PATCH] catalog prices fix --- src/lib/graphql/resolvers.ts | 96 ++++++++++++++++++++++++++++++++++- src/lib/partsapi-service.ts | 2 +- src/lib/partsindex-service.ts | 2 +- 3 files changed, 97 insertions(+), 3 deletions(-) diff --git a/src/lib/graphql/resolvers.ts b/src/lib/graphql/resolvers.ts index bc470e4..6b47054 100644 --- a/src/lib/graphql/resolvers.ts +++ b/src/lib/graphql/resolvers.ts @@ -3064,8 +3064,102 @@ export const resolvers = { } console.log('✅ Получены товары каталога:', entities.list.length) + console.log('🔍 Начинаем серверную фильтрацию по ценам...') - return entities + // Глобальный кэш для результатов проверки цен (персистентный между запросами) + if (!global.priceCache) { + global.priceCache = new Map() + } + const priceCache = global.priceCache as Map + const CACHE_TTL = 5 * 60 * 1000 // 5 минут + + const getCachedPriceResult = (code: string, brand: string): boolean | null => { + const key = `${code}_${brand}` + const cached = priceCache.get(key) + if (cached && (Date.now() - cached.timestamp) < CACHE_TTL) { + return cached.hasPrice + } + return null + } + + const cachePriceResult = (code: string, brand: string, hasPrice: boolean): void => { + const key = `${code}_${brand}` + priceCache.set(key, { hasPrice, timestamp: Date.now() }) + } + + // Фильтруем товары на сервере - проверяем наличие цен в AutoEuro + const filteredEntities: any[] = [] + const batchSize = 20 // Увеличенный размер батча для скорости + + for (let i = 0; i < entities.list.length; i += batchSize) { + const batch = entities.list.slice(i, i + batchSize) + + // Проверяем цены для каждого товара в батче параллельно + const priceCheckPromises = batch.map(async (entity) => { + try { + // Сначала проверяем кэш + const cachedResult = getCachedPriceResult(entity.code, entity.brand.name); + if (cachedResult !== null) { + if (cachedResult) { + console.log(`💨 Кэш: товар ${entity.code} (${entity.brand.name}) имеет цену`); + return entity; + } else { + console.log(`💨 Кэш: товар ${entity.code} (${entity.brand.name}) не имеет цены`); + return null; + } + } + + const searchResult = await autoEuroService.searchItems({ + code: entity.code, + brand: entity.brand.name, + with_crosses: false, + with_offers: true + }) + + // Проверяем есть ли предложения с валидной ценой + const hasValidPrice: boolean = Boolean(searchResult.success && + searchResult.data && + searchResult.data.length > 0 && + searchResult.data.some(offer => + offer.price && + parseFloat(offer.price.toString()) > 0 + )) + + // Кэшируем результат + cachePriceResult(entity.code, entity.brand.name, hasValidPrice); + + if (hasValidPrice) { + console.log(`✅ Товар ${entity.code} (${entity.brand.name}) имеет цену`); + return entity; + } else { + console.log(`❌ Товар ${entity.code} (${entity.brand.name}) не имеет цены`); + return null; + } + } catch (error) { + console.error(`❌ Ошибка проверки цены для ${entity.code}:`, error); + return null // Исключаем товары с ошибками + } + }) + + // Ждем результаты для текущего батча + const batchResults = await Promise.all(priceCheckPromises) + + // Добавляем только товары с ценами + filteredEntities.push(...batchResults.filter(entity => entity !== null)) + + // Убираем задержку между батчами для максимальной скорости + // if (i + batchSize < entities.list.length) { + // await new Promise(resolve => setTimeout(resolve, 50)) + // } + } + + console.log(`✅ Серверная фильтрация завершена. Товаров с ценами: ${filteredEntities.length} из ${entities.list.length}`) + + // Возвращаем отфильтрованный результат + return { + ...entities, + list: filteredEntities + } } catch (error) { console.error('❌ Ошибка в GraphQL resolver partsIndexCatalogEntities:', error) throw new Error('Не удалось получить товары каталога') diff --git a/src/lib/partsapi-service.ts b/src/lib/partsapi-service.ts index ecbf48f..552562c 100644 --- a/src/lib/partsapi-service.ts +++ b/src/lib/partsapi-service.ts @@ -37,7 +37,7 @@ class PartsAPIService { private mediaApiKey: string; constructor() { - this.baseURL = 'https://api.partsapi.ru'; + this.baseURL = process.env.PARTSAPI_URL || 'https://api.partsapi.ru'; // Получаем ключи API из переменных окружения this.categoriesApiKey = process.env.PARTSAPI_CATEGORIES_KEY || ''; diff --git a/src/lib/partsindex-service.ts b/src/lib/partsindex-service.ts index 63168f6..b1f1995 100644 --- a/src/lib/partsindex-service.ts +++ b/src/lib/partsindex-service.ts @@ -155,7 +155,7 @@ interface CacheEntry { } class PartsIndexService { - private baseURL = 'https://api.parts-index.com/v1'; + private baseURL = process.env.PARTSAPI_URL+"/v1" || 'https://api.parts-index.com/v1'; private apiKey = 'PI-E1C0ADB7-E4A8-4960-94A0-4D9C0A074DAE'; // Простой in-memory кэш