catalog prices fix

This commit is contained in:
54CHA
2025-07-17 21:22:45 +03:00
parent 5fd2cf1b8c
commit b6f9d017d6
4 changed files with 56 additions and 59 deletions

View File

@ -1,6 +1,6 @@
import { PartsIndexCatalogsResponse, PartsIndexGroup, PartsIndexEntityInfoResponse } from '@/types/partsindex';
const PARTS_INDEX_API_BASE = 'https://api.parts-index.com';
const PARTS_INDEX_API_BASE = process.env.PARTSAPI_URL+"/v1" || 'https://api.parts-index.com/v1';
const API_KEY = 'PI-E1C0ADB7-E4A8-4960-94A0-4D9C0A074DAE';
class PartsIndexService {

View File

@ -38,8 +38,8 @@ const mockData = Array(12).fill({
brand: "Borsehung",
});
const ITEMS_PER_PAGE = 50; // Целевое количество товаров на странице
const PARTSINDEX_PAGE_SIZE = 25; // Размер страницы PartsIndex API (фиксированный)
const ITEMS_PER_PAGE = 50; // Уменьшено для быстрой загрузки и лучшего UX
const PARTSINDEX_PAGE_SIZE = 25; // Синхронизировано для оптимальной скорости
const MAX_BRANDS_DISPLAY = 10; // Сколько брендов показывать изначально
export default function Catalog() {
@ -175,16 +175,17 @@ export default function Catalog() {
// Хук для загрузки цен товаров PartsIndex
const { getPrice, isLoadingPrice, ensurePriceLoaded } = useProductPrices();
// Загружаем цены для видимых товаров PartsIndex
// Загружаем цены для видимых товаров PartsIndex (для отображения конкретных цен)
useEffect(() => {
if (isPartsIndexMode && visibleEntities.length > 0) {
// Загружаем цены только для видимых товаров для отображения точных цен
visibleEntities.forEach((entity, index) => {
const productForPrice = {
id: entity.id,
code: entity.code,
brand: entity.brand.name
};
// Загружаем с небольшой задержкой чтобы не перегружать сервер
// Загружаем с небольшой задержкой
setTimeout(() => {
ensurePriceLoaded(productForPrice);
}, index * 50);
@ -284,25 +285,18 @@ export default function Catalog() {
// Восстанавливаем автоподгрузку
console.log('🔄 Автоподгрузка активна');
// Подсчитываем текущее количество товаров с предложениями
const currentEntitiesWithOffers = accumulatedEntities.filter(entity => {
const productForPrice = { id: entity.id, code: entity.code, brand: entity.brand.name };
const priceData = getPrice(productForPrice);
const isLoadingPriceData = isLoadingPrice(productForPrice);
// Товар считается "с предложениями" если у него есть реальная цена (не null и не undefined)
return (priceData && priceData.price && priceData.price > 0) || isLoadingPriceData;
});
// Подсчитываем текущее количество товаров (все уже отфильтрованы на сервере)
const currentEntitiesCount = accumulatedEntities.length;
console.log('📊 Автоподгрузка: текущее состояние:', {
накопленоТоваров: accumulatedEntities.length,
сПредложениями: currentEntitiesWithOffers.length,
накопленоТоваров: currentEntitiesCount,
целевоеКоличество: ITEMS_PER_PAGE,
естьЕщеТовары: hasMoreEntities
});
// Если у нас уже достаточно товаров с предложениями, не загружаем
if (currentEntitiesWithOffers.length >= ITEMS_PER_PAGE) {
console.log('✅ Автоподгрузка: достаточно товаров с предложениями');
// Если у нас уже достаточно товаров, не загружаем
if (currentEntitiesCount >= ITEMS_PER_PAGE) {
console.log('✅ Автоподгрузка: достаточно товаров');
return;
}
@ -444,26 +438,18 @@ export default function Catalog() {
}
}, [isPartsIndexMode, entitiesWithOffers.length, hasMoreEntities, isAutoLoading]);
// Обновляем список товаров с предложениями при изменении накопленных товаров или цен
// Обновляем список товаров при изменении накопленных товаров (серверная фильтрация)
useEffect(() => {
if (!isPartsIndexMode) {
return;
}
// Показываем все товары, но отдельно считаем те, у которых есть цены
// Все товары уже отфильтрованы на сервере - показываем все накопленные
const entitiesWithOffers = accumulatedEntities;
// Подсчитываем количество товаров с реальными ценами для автоподгрузки
const entitiesWithRealPrices = accumulatedEntities.filter(entity => {
const productForPrice = { id: entity.id, code: entity.code, brand: entity.brand.name };
const priceData = getPrice(productForPrice);
return priceData && priceData.price && priceData.price > 0;
});
console.log('📊 Обновляем entitiesWithOffers:', {
console.log('📊 Обновляем entitiesWithOffers (серверная фильтрация):', {
накопленоТоваров: accumulatedEntities.length,
отображаемыхТоваров: entitiesWithOffers.length,
сРеальнымиЦенами: entitiesWithRealPrices.length,
целевоеКоличество: ITEMS_PER_PAGE
});
@ -486,29 +472,7 @@ export default function Catalog() {
}, [isPartsIndexMode, accumulatedEntities, currentUserPage]);
// Отдельный useEffect для обновления статистики цен (без влияния на visibleEntities)
useEffect(() => {
if (!isPartsIndexMode || accumulatedEntities.length === 0) {
return;
}
// Обновляем статистику каждые 2 секунды
const timer = setTimeout(() => {
const entitiesWithRealPrices = accumulatedEntities.filter(entity => {
const productForPrice = { id: entity.id, code: entity.code, brand: entity.brand.name };
const priceData = getPrice(productForPrice);
return priceData && priceData.price && priceData.price > 0;
});
console.log('💰 Обновление статистики цен:', {
накопленоТоваров: accumulatedEntities.length,
сРеальнымиЦенами: entitiesWithRealPrices.length,
процентЗагрузки: Math.round((entitiesWithRealPrices.length / accumulatedEntities.length) * 100)
});
}, 2000);
return () => clearTimeout(timer);
}, [isPartsIndexMode, accumulatedEntities.length, getPrice]);
// Генерируем динамические фильтры для PartsAPI
const generatePartsAPIFilters = useCallback((): FilterConfig[] => {
@ -724,12 +688,18 @@ export default function Catalog() {
} else if (isPartsIndexMode && !entitiesLoading && !entitiesError) {
// Для PartsIndex показываем пустое состояние если нет товаров И данные уже загружены
const hasLoadedData = accumulatedEntities.length > 0 || Boolean(entitiesData?.partsIndexCatalogEntities?.list);
setShowEmptyState(hasLoadedData && visibleEntities.length === 0);
console.log('📊 Определяем showEmptyState для PartsIndex:', {
// Показываем пустое состояние если данные загружены и нет видимых товаров
// (товары уже отфильтрованы на сервере, поэтому не нужно ждать загрузки цен)
const shouldShowEmpty = hasLoadedData && visibleEntities.length === 0;
setShowEmptyState(shouldShowEmpty);
console.log('📊 Определяем showEmptyState для PartsIndex (серверная фильтрация):', {
hasLoadedData,
visibleEntitiesLength: visibleEntities.length,
accumulatedEntitiesLength: accumulatedEntities.length,
showEmptyState: hasLoadedData && visibleEntities.length === 0
shouldShowEmpty,
showEmptyState: shouldShowEmpty
});
} else {
setShowEmptyState(false);
@ -936,6 +906,8 @@ export default function Catalog() {
</div>
)}
{/* Сообщение об ошибке */}
{isPartsAPIMode && articlesError && (
<div className="flex justify-center items-center py-8">
@ -1001,16 +973,20 @@ export default function Catalog() {
const priceData = getPrice(productForPrice);
const isLoadingPriceData = isLoadingPrice(productForPrice);
// Определяем цену для отображения
let displayPrice = "Цена по запросу";
// Определяем цену для отображения (все товары уже отфильтрованы на сервере)
let displayPrice = "";
let displayCurrency = "RUB";
let priceElement;
if (isLoadingPriceData) {
// Показываем скелетон загрузки вместо текста
priceElement = <PriceSkeleton />;
} else if (priceData && priceData.price) {
displayPrice = `${priceData.price.toLocaleString('ru-RU')}`;
displayCurrency = priceData.currency || "RUB";
} else {
// Если нет данных о цене, показываем скелетон (товар должен загрузиться)
priceElement = <PriceSkeleton />;
}
return (
@ -1021,7 +997,7 @@ export default function Catalog() {
articleNumber={entity.code}
brandName={entity.brand.name}
image={entity.images?.[0] || ''}
price={isLoadingPriceData ? "" : displayPrice}
price={priceElement ? "" : displayPrice}
priceElement={priceElement}
oldPrice=""
discount=""

View File

@ -9,7 +9,7 @@ async function testPartsIndexAPI() {
// Получаем каталоги
console.log('\n📦 Получаем список каталогов...');
const catalogsResponse = await fetch('https://api.parts-index.com/v1/catalogs?lang=ru', {
const catalogsResponse = await fetch(process.env.PARTSAPI_URL+"/v1/catalogs?lang=ru", {
headers: {
'Accept': 'application/json',
},
@ -31,7 +31,7 @@ async function testPartsIndexAPI() {
console.log(`\n🎯 Получаем группы для каталога "${firstCatalog.name}"...`);
const groupsResponse = await fetch(
`https://api.parts-index.com/v1/catalogs/${firstCatalog.id}/groups?lang=ru`,
`${process.env.PARTSAPI_URL}/v1/catalogs/${firstCatalog.id}/groups?lang=ru`,
{
headers: {
'Accept': 'application/json',

21
user_input.py Normal file
View File

@ -0,0 +1,21 @@
def main():
while True:
print("\n" + "="*50)
user_input = input("Please provide feedback or next task (type 'stop' to exit): ").strip()
if user_input.lower() == 'stop':
print("Exiting task loop. Thank you!")
break
elif user_input.lower() == '':
print("Please provide some input or type 'stop' to exit.")
continue
else:
print(f"\nReceived input: {user_input}")
print("Processing your request...")
# Here the main process would handle the user's input
return user_input
if __name__ == "__main__":
result = main()
if result and result.lower() != 'stop':
print(f"Next task received: {result}")