'use client' /* eslint-disable @typescript-eslint/no-explicit-any */ import { useMutation, useQuery } from '@apollo/client' import { useEffect, useState } from 'react' import { toast } from 'sonner' import { Sidebar } from '@/components/dashboard/sidebar' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { SAVE_WB_WAREHOUSE_CACHE } from '@/graphql/mutations' import { GET_WB_WAREHOUSE_DATA } from '@/graphql/queries' import { useAuth } from '@/hooks/useAuth' import { useSidebar } from '@/hooks/useSidebar' import { WildberriesService } from '@/services/wildberries-service' import { FulfillmentWarehouseTab } from './fulfillment-warehouse-tab' import { MyWarehouseTab } from './my-warehouse-tab' import { WildberriesWarehouseTab } from './wildberries-warehouse-tab' interface WBStock { nmId: number vendorCode: string title: string brand: string price: number stocks: Array<{ warehouseId: number warehouseName: string quantity: number quantityFull: number inWayToClient: number inWayFromClient: number }> totalQuantity: number totalReserved: number photos: any[] mediaFiles: any[] characteristics: any[] subjectName: string description: string } interface WBWarehouse { id: number name: string cargoType: number deliveryType: number } export function WBWarehouseDashboard() { const { user } = useAuth() const { isCollapsed: _isCollapsed, getSidebarMargin } = useSidebar() const [activeTab, setActiveTab] = useState('fulfillment') // Состояние данных WB Warehouse const [stocks, setStocks] = useState([]) const [warehouses, setWarehouses] = useState([]) const [loading, setLoading] = useState(false) const [initialized, setInitialized] = useState(false) // Статистика const [totalProducts, setTotalProducts] = useState(0) const [totalStocks, setTotalStocks] = useState(0) const [totalReserved, setTotalReserved] = useState(0) const [totalFromClient, setTotalFromClient] = useState(0) const [activeWarehouses, setActiveWarehouses] = useState(0) // Analytics data const [analyticsData, setAnalyticsData] = useState([]) // Проверяем настройку API ключа const hasWBApiKey = user?.organization?.apiKeys?.find((key) => key.marketplace === 'WILDBERRIES')?.isActive // GraphQL хуки для работы с кешем const { data: _cacheData, loading: cacheLoading, refetch: refetchCache, } = useQuery(GET_WB_WAREHOUSE_DATA, { skip: !hasWBApiKey, fetchPolicy: 'cache-and-network', }) const [saveCache] = useMutation(SAVE_WB_WAREHOUSE_CACHE) // Комбинирование карточек с индивидуальными данными аналитики const combineCardsWithIndividualAnalytics = (cards: any[], analyticsResults: any[]): WBStock[] => { const stocksMap = new Map() // Создаем карту аналитических данных для быстрого поиска const analyticsMap = new Map() // Map nmId to its analytics data analyticsResults.forEach((result) => { analyticsMap.set(result.nmId, result.data) }) cards.forEach((card) => { const stock: WBStock = { nmId: card.nmID, vendorCode: String(card.vendorCode || card.supplierVendorCode || ''), title: String(card.title || card.object || `Товар ${card.nmID}`), brand: String(card.brand || ''), price: 0, stocks: [], totalQuantity: 0, totalReserved: 0, photos: Array.isArray(card.photos) ? card.photos : [], mediaFiles: Array.isArray(card.mediaFiles) ? card.mediaFiles : [], characteristics: Array.isArray(card.characteristics) ? card.characteristics : [], subjectName: String(card.subjectName || ''), description: String(card.description || ''), } // Получаем аналитические данные для данного nmId const analytics = analyticsMap.get(card.nmID) if (analytics && analytics.data && analytics.data.regions && Array.isArray(analytics.data.regions)) { analytics.data.regions.forEach((region: any) => { if (region.offices && Array.isArray(region.offices)) { region.offices.forEach((office: any) => { stock.stocks.push({ warehouseId: office.officeID || 0, warehouseName: String(office.officeName || 'Неизвестный склад'), quantity: Number(office.metrics?.stockCount) || 0, quantityFull: Number(office.metrics?.stockCount) || 0, inWayToClient: Number(office.metrics?.toClientCount) || 0, inWayFromClient: Number(office.metrics?.fromClientCount) || 0, }) }) } }) } // Подсчитываем общие показатели stock.totalQuantity = stock.stocks.reduce((sum, s) => sum + s.quantity, 0) stock.totalReserved = stock.stocks.reduce((sum, s) => sum + s.inWayToClient, 0) stocksMap.set(card.nmID, stock) }) return Array.from(stocksMap.values()) } // Извлечение складов из данных о товарах const extractWarehousesFromStocks = (stocksData: WBStock[]): WBWarehouse[] => { const warehousesMap = new Map() stocksData.forEach((item) => { item.stocks.forEach((stock) => { if (!warehousesMap.has(stock.warehouseId)) { warehousesMap.set(stock.warehouseId, { id: stock.warehouseId, name: stock.warehouseName, cargoType: 0, deliveryType: 0, }) } }) }) return Array.from(warehousesMap.values()) } // Обновление статистики const updateStatistics = (stocksData: WBStock[], _warehousesData: WBWarehouse[]) => { setTotalProducts(stocksData.length) const totalStocksCount = stocksData.reduce((sum, item) => sum + item.totalQuantity, 0) setTotalStocks(totalStocksCount) const totalReservedCount = stocksData.reduce((sum, item) => sum + item.totalReserved, 0) setTotalReserved(totalReservedCount) const totalFromClientCount = stocksData.reduce( (sum, item) => sum + item.stocks.reduce((stockSum, stock) => stockSum + stock.inWayFromClient, 0), 0, ) setTotalFromClient(totalFromClientCount) const warehousesWithStock = new Set(stocksData.flatMap((item) => item.stocks.map((s) => s.warehouseId))) setActiveWarehouses(warehousesWithStock.size) } // Загрузка данных из кеша const loadWarehouseDataFromCache = (cacheData: any) => { try { const parsedData = typeof cacheData.data === 'string' ? JSON.parse(cacheData.data) : cacheData.data const cachedStocks = parsedData.stocks || [] const cachedWarehouses = parsedData.warehouses || [] const cachedAnalytics = parsedData.analyticsData || [] setStocks(cachedStocks) setWarehouses(cachedWarehouses) setAnalyticsData(cachedAnalytics) // Обновляем статистику из кеша setTotalProducts(cacheData.totalProducts) setTotalStocks(cacheData.totalStocks) setTotalReserved(cacheData.totalReserved) const totalFromClientCount = (cachedStocks || []).reduce( (sum: number, item: WBStock) => sum + item.stocks.reduce((stockSum, stock) => stockSum + stock.inWayFromClient, 0), 0, ) setTotalFromClient(totalFromClientCount) const warehousesWithStock = new Set( (cachedStocks || []).flatMap((item: WBStock) => item.stocks.map((s) => s.warehouseId)), ) setActiveWarehouses(warehousesWithStock.size) console.warn('WB Warehouse: Data loaded from cache:', cachedStocks?.length || 0, 'items') toast.success(`Загружено из кеша: ${cachedStocks?.length || 0} товаров`) } catch (error) { console.error('WB Warehouse: Error parsing cache data:', error) toast.error('Ошибка загрузки данных из кеша') // Если кеш поврежден, загружаем из API loadWarehouseDataFromAPI() } finally { setInitialized(true) } } // Загрузка данных из API и сохранение в кеш const loadWarehouseDataFromAPI = async () => { if (!hasWBApiKey) return setLoading(true) try { const wbApiKey = user?.organization?.apiKeys?.find((key) => key.marketplace === 'WILDBERRIES') if (!wbApiKey?.isActive) { toast.error('API ключ Wildberries не настроен') return } const validationData = wbApiKey.validationData as Record const apiToken = validationData?.token || validationData?.apiKey || validationData?.key || (wbApiKey as { apiKey?: string }).apiKey if (!apiToken) { toast.error('Токен API не найден') return } const wbService = new WildberriesService(apiToken) // 1. Получаем карточки товаров const cards = await WildberriesService.getAllCards(apiToken).catch(() => []) console.warn('WB Warehouse: Loaded cards:', cards.length) if (cards.length === 0) { toast.error('Нет карточек товаров в WB') return } const nmIds = cards.map((card) => card.nmID).filter((id) => id > 0) console.warn('WB Warehouse: NM IDs to process:', nmIds.length) // 2. Получаем аналитику для каждого товара индивидуально const analyticsResults = [] for (const nmId of nmIds) { try { console.warn(`WB Warehouse: Fetching analytics for nmId ${nmId}`) const result = await wbService.getStocksReportByOffices({ nmIds: [nmId], stockType: '', }) analyticsResults.push({ nmId, data: result }) await new Promise((resolve) => setTimeout(resolve, 1000)) } catch (error) { console.error(`WB Warehouse: Error fetching analytics for nmId ${nmId}:`, error) } } console.warn('WB Warehouse: Analytics results:', analyticsResults.length) // 3. Комбинируем данные const combinedStocks = combineCardsWithIndividualAnalytics(cards, analyticsResults) console.warn('WB Warehouse: Combined stocks:', combinedStocks.length) // 4. Извлекаем склады и обновляем статистику const extractedWarehouses = extractWarehousesFromStocks(combinedStocks) // 5. Подготавливаем статистику const stats = { totalProducts: combinedStocks.length, totalStocks: combinedStocks.reduce((sum, item) => sum + item.totalQuantity, 0), totalReserved: combinedStocks.reduce((sum, item) => sum + item.totalReserved, 0), } // 6. Сохраняем в кеш try { await saveCache({ variables: { input: { data: JSON.stringify({ stocks: combinedStocks, warehouses: extractedWarehouses, analyticsData: analyticsData, }), totalProducts: stats.totalProducts, totalStocks: stats.totalStocks, totalReserved: stats.totalReserved, }, }, }) console.warn('WB Warehouse: Data saved to cache') } catch (cacheError) { console.error('WB Warehouse: Error saving to cache:', cacheError) } // 7. Обновляем состояние setStocks(combinedStocks) setWarehouses(extractedWarehouses) updateStatistics(combinedStocks, extractedWarehouses) toast.success(`Загружено товаров: ${combinedStocks.length}`) } catch (error) { console.error('WB Warehouse: Error loading data from API:', error) toast.error('Ошибка при загрузке данных из API') } finally { setLoading(false) setInitialized(true) } } // Основная функция загрузки данных const loadWarehouseData = async () => { if (!hasWBApiKey) { setInitialized(true) return } // Сначала пытаемся получить данные из кеша try { const result = await refetchCache() const cacheResponse = result.data?.getWBWarehouseData if (cacheResponse?.success && cacheResponse?.fromCache && cacheResponse?.cache) { // Данные найдены в кеше loadWarehouseDataFromCache(cacheResponse.cache) } else { // Кеша нет или он устарел, загружаем из API console.warn('WB Warehouse: No cache found, loading from API') await loadWarehouseDataFromAPI() } } catch (error) { console.error('WB Warehouse: Error checking cache:', error) // При ошибке кеша загружаем из API await loadWarehouseDataFromAPI() } } // Загружаем данные только один раз при инициализации useEffect(() => { if (!cacheLoading && user?.organization && !initialized) { loadWarehouseData() } }, [cacheLoading, user?.organization, initialized]) return (
{/* Табы */} Склад фулфилмент Склад Wildberries Мой склад
) }