"use client" import React, { useState, useEffect } from 'react' import { useAuth } from '@/hooks/useAuth' import { Sidebar } from '@/components/dashboard/sidebar' import { useSidebar } from '@/hooks/useSidebar' import { Card } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { WildberriesService } from '@/services/wildberries-service' import { toast } from 'sonner' import { StatsCards } from './stats-cards' import { SearchBar } from './search-bar' import { TableHeader } from './table-header' import { LoadingSkeleton } from './loading-skeleton' import { StockTableRow } from './stock-table-row' import { TrendingUp, Package } from 'lucide-react' 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?: Array<{ big?: string c246x328?: string c516x688?: string square?: string tm?: string }> mediaFiles?: string[] characteristics?: Array<{ name: string value: string | string[] }> subjectName: string description: string } interface WBWarehouse { id: number name: string cargoType: number deliveryType: number } export function WBWarehouseDashboard() { const { user } = useAuth() const { isCollapsed, getSidebarMargin } = useSidebar() const [stocks, setStocks] = useState([]) const [warehouses, setWarehouses] = useState([]) const [loading, setLoading] = useState(false) const [searchTerm, setSearchTerm] = useState('') // Статистика 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([]) const hasWBApiKey = user?.wildberriesApiKey // Комбинирование карточек с индивидуальными данными аналитики // eslint-disable-next-line @typescript-eslint/no-explicit-any 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 || card.object || ''), description: String(card.description || '') } if (card.sizes && card.sizes.length > 0) { stock.price = Number(card.sizes[0].price || card.sizes[0].discountedPrice) || 0 } const analyticsData = analyticsMap.get(card.nmID) if (analyticsData?.data?.regions) { // eslint-disable-next-line @typescript-eslint/no-explicit-any analyticsData.data.regions.forEach((region: any) => { if (region.offices && region.offices.length > 0) { // eslint-disable-next-line @typescript-eslint/no-explicit-any region.offices.forEach((office: any) => { stock.stocks.push({ warehouseId: office.officeID, warehouseName: office.officeName, quantity: office.metrics?.stockCount || 0, quantityFull: office.metrics?.stockCount || 0, inWayToClient: office.metrics?.toClientCount || 0, inWayFromClient: office.metrics?.fromClientCount || 0 }) stock.totalQuantity += office.metrics?.stockCount || 0 stock.totalReserved += office.metrics?.toClientCount || 0 }) } }) } stocksMap.set(card.nmID, stock) }) return Array.from(stocksMap.values()).sort((a, b) => b.totalQuantity - a.totalQuantity) } // Извлечение информации о складах из данных const extractWarehousesFromStocks = (stocksData: WBStock[]): WBWarehouse[] => { const warehousesMap = new Map() stocksData.forEach(stock => { stock.stocks.forEach(stockInfo => { if (!warehousesMap.has(stockInfo.warehouseId)) { warehousesMap.set(stockInfo.warehouseId, { id: stockInfo.warehouseId, name: stockInfo.warehouseName, cargoType: 1, deliveryType: 1 }) } }) }) return Array.from(warehousesMap.values()) } // Обновление статистики const updateStatistics = (stocksData: WBStock[], warehousesData: WBWarehouse[]) => { setTotalProducts(stocksData.length) setTotalStocks(stocksData.reduce((sum, item) => sum + item.totalQuantity, 0)) setTotalReserved(stocksData.reduce((sum, item) => sum + item.totalReserved, 0)) 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 loadWarehouseData = async () => { if (!user?.wildberriesApiKey) return setLoading(true) try { const apiToken = user.wildberriesApiKey const wbService = new WildberriesService(apiToken) // 1. Получаем карточки товаров const cards = await WildberriesService.getAllCards(apiToken).catch(() => []) console.log('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.log('WB Warehouse: NM IDs to process:', nmIds.length) // 2. Получаем аналитику для каждого товара индивидуально const analyticsResults = [] for (const nmId of nmIds) { try { console.log(`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.log('WB Warehouse: Analytics results:', analyticsResults.length) // 3. Комбинируем данные const combinedStocks = combineCardsWithIndividualAnalytics(cards, analyticsResults) console.log('WB Warehouse: Combined stocks:', combinedStocks.length) // 4. Извлекаем склады и обновляем статистику const extractedWarehouses = extractWarehousesFromStocks(combinedStocks) setStocks(combinedStocks) setWarehouses(extractedWarehouses) updateStatistics(combinedStocks, extractedWarehouses) toast.success(`Загружено товаров: ${combinedStocks.length}`) } catch (error: any) { console.error('WB Warehouse: Error loading data:', error) toast.error('Ошибка загрузки данных: ' + (error.message || 'Неизвестная ошибка')) } finally { setLoading(false) } } useEffect(() => { if (hasWBApiKey) { loadWarehouseData() } }, [hasWBApiKey]) // Фильтрация товаров const filteredStocks = stocks.filter(item => { if (!searchTerm) return true const search = searchTerm.toLowerCase() return ( item.title.toLowerCase().includes(search) || String(item.nmId).includes(search) || item.brand.toLowerCase().includes(search) || item.vendorCode.toLowerCase().includes(search) ) }) return (
{/* Результирующие вкладки */} {/* Аналитика по складам WB */} {analyticsData.length > 0 && (

Движение товаров по складам WB

{analyticsData.map((warehouse) => (
{warehouse.warehouseName}
К клиенту: {warehouse.toClient}
От клиента: {warehouse.fromClient}
))}
)} {/* Поиск */} {/* Список товаров */}
{loading ? (
) : !hasWBApiKey ? (

Настройте API Wildberries

Для просмотра остатков добавьте API ключ Wildberries в настройках

) : filteredStocks.length === 0 ? (

Товары не найдены

Попробуйте изменить параметры поиска

) : (
{/* Таблица товаров */}
{filteredStocks.map((item, index) => ( ))}
)}
) }