"use client" import React, { useState } from 'react' import { Card } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Sidebar } from '@/components/dashboard/sidebar' import { ChevronDown, ChevronRight, Plus, Calendar, Package, MapPin, Building2, TrendingUp, AlertTriangle, DollarSign } from 'lucide-react' // Типы данных для 5-уровневой структуры interface ProductParameter { id: string name: string value: string unit?: string } interface Product { id: string name: string sku: string category: string plannedQty: number actualQty: number defectQty: number productPrice: number parameters: ProductParameter[] } interface Wholesaler { id: string name: string inn: string contact: string address: string products: Product[] totalAmount: number } interface Route { id: string from: string fromAddress: string to: string toAddress: string wholesalers: Wholesaler[] totalProductPrice: number fulfillmentServicePrice: number logisticsPrice: number totalAmount: number } interface Supply { id: string number: number deliveryDate: string createdDate: string routes: Route[] plannedTotal: number actualTotal: number defectTotal: number totalProductPrice: number totalFulfillmentPrice: number totalLogisticsPrice: number grandTotal: number status: 'planned' | 'in-transit' | 'delivered' | 'completed' } // Моковые данные для 5-уровневой структуры const mockSupplies: Supply[] = [ { id: '1', number: 1, deliveryDate: '2024-01-15', createdDate: '2024-01-10', status: 'delivered', plannedTotal: 180, actualTotal: 173, defectTotal: 2, totalProductPrice: 3750000, totalFulfillmentPrice: 43000, totalLogisticsPrice: 27000, grandTotal: 3820000, routes: [ { id: 'r1', from: 'Садовод', fromAddress: 'Москва, 14-й км МКАД', to: 'SFERAV Logistics', toAddress: 'Москва, ул. Складская, 15', totalProductPrice: 3600000, fulfillmentServicePrice: 25000, logisticsPrice: 15000, totalAmount: 3640000, wholesalers: [ { id: 'w1', name: 'ООО "ТехноСнаб"', inn: '7701234567', contact: '+7 (495) 123-45-67', address: 'Москва, ул. Торговая, 1', totalAmount: 3600000, products: [ { id: 'p1', name: 'Смартфон iPhone 15', sku: 'APL-IP15-128', category: 'Электроника', plannedQty: 50, actualQty: 48, defectQty: 2, productPrice: 75000, parameters: [ { id: 'param1', name: 'Цвет', value: 'Черный' }, { id: 'param2', name: 'Память', value: '128', unit: 'ГБ' }, { id: 'param3', name: 'Гарантия', value: '12', unit: 'мес' } ] } ] } ] }, { id: 'r2', from: 'ТЯК Москва', fromAddress: 'Москва, Алтуфьевское шоссе, 27', to: 'MegaFulfillment', toAddress: 'Подольск, ул. Индустриальная, 42', totalProductPrice: 150000, fulfillmentServicePrice: 18000, logisticsPrice: 12000, totalAmount: 180000, wholesalers: [ { id: 'w2', name: 'ИП Петров А.В.', inn: '123456789012', contact: '+7 (499) 987-65-43', address: 'Москва, пр-т Мира, 45', totalAmount: 150000, products: [ { id: 'p2', name: 'Чехол для iPhone 15', sku: 'ACC-IP15-CASE', category: 'Аксессуары', plannedQty: 100, actualQty: 95, defectQty: 0, productPrice: 1500, parameters: [ { id: 'param4', name: 'Материал', value: 'Силикон' }, { id: 'param5', name: 'Цвет', value: 'Прозрачный' } ] } ] } ] } ] }, { id: '2', number: 2, deliveryDate: '2024-01-20', createdDate: '2024-01-12', status: 'in-transit', plannedTotal: 30, actualTotal: 30, defectTotal: 0, totalProductPrice: 750000, totalFulfillmentPrice: 18000, totalLogisticsPrice: 12000, grandTotal: 780000, routes: [ { id: 'r3', from: 'Садовод', fromAddress: 'Москва, 14-й км МКАД', to: 'WB Подольск', toAddress: 'Подольск, ул. Складская, 25', totalProductPrice: 750000, fulfillmentServicePrice: 18000, logisticsPrice: 12000, totalAmount: 780000, wholesalers: [ { id: 'w3', name: 'ООО "АудиоТех"', inn: '7702345678', contact: '+7 (495) 555-12-34', address: 'Москва, ул. Звуковая, 8', totalAmount: 750000, products: [ { id: 'p3', name: 'Наушники AirPods Pro', sku: 'APL-AP-PRO2', category: 'Аудио', plannedQty: 30, actualQty: 30, defectQty: 0, productPrice: 25000, parameters: [ { id: 'param6', name: 'Тип', value: 'Беспроводные' }, { id: 'param7', name: 'Шумоподавление', value: 'Активное' }, { id: 'param8', name: 'Время работы', value: '6', unit: 'ч' } ] } ] } ] } ] } ] export function SuppliesDashboard() { const [expandedSupplies, setExpandedSupplies] = useState>(new Set()) const [expandedRoutes, setExpandedRoutes] = useState>(new Set()) const [expandedWholesalers, setExpandedWholesalers] = useState>(new Set()) const [expandedProducts, setExpandedProducts] = useState>(new Set()) const toggleSupplyExpansion = (supplyId: string) => { const newExpanded = new Set(expandedSupplies) if (newExpanded.has(supplyId)) { newExpanded.delete(supplyId) } else { newExpanded.add(supplyId) } setExpandedSupplies(newExpanded) } const toggleRouteExpansion = (routeId: string) => { const newExpanded = new Set(expandedRoutes) if (newExpanded.has(routeId)) { newExpanded.delete(routeId) } else { newExpanded.add(routeId) } setExpandedRoutes(newExpanded) } const toggleWholesalerExpansion = (wholesalerId: string) => { const newExpanded = new Set(expandedWholesalers) if (newExpanded.has(wholesalerId)) { newExpanded.delete(wholesalerId) } else { newExpanded.add(wholesalerId) } setExpandedWholesalers(newExpanded) } const toggleProductExpansion = (productId: string) => { const newExpanded = new Set(expandedProducts) if (newExpanded.has(productId)) { newExpanded.delete(productId) } else { newExpanded.add(productId) } setExpandedProducts(newExpanded) } const getStatusBadge = (status: Supply['status']) => { const statusMap = { planned: { label: 'Запланирована', color: 'bg-blue-500/20 text-blue-300 border-blue-500/30' }, 'in-transit': { label: 'В пути', color: 'bg-yellow-500/20 text-yellow-300 border-yellow-500/30' }, delivered: { label: 'Доставлена', color: 'bg-green-500/20 text-green-300 border-green-500/30' }, completed: { label: 'Завершена', color: 'bg-purple-500/20 text-purple-300 border-purple-500/30' } } const { label, color } = statusMap[status] return {label} } const formatCurrency = (amount: number) => { return new Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'RUB', minimumFractionDigits: 0 }).format(amount) } const formatDate = (dateString: string) => { return new Date(dateString).toLocaleDateString('ru-RU', { day: '2-digit', month: '2-digit', year: 'numeric' }) } const calculateProductTotal = (product: Product) => { return product.actualQty * product.productPrice } const getEfficiencyBadge = (planned: number, actual: number, defect: number) => { const efficiency = ((actual - defect) / planned) * 100 if (efficiency >= 95) { return Отлично } else if (efficiency >= 90) { return Хорошо } else { return Проблемы } } return (
{/* Заголовок */}

Поставки

Управление поставками товаров

{/* Статистика */}

Всего поставок

{mockSupplies.length}

Общая сумма

{formatCurrency(mockSupplies.reduce((sum, supply) => sum + supply.grandTotal, 0))}

В пути

{mockSupplies.filter(supply => supply.status === 'in-transit').length}

С браком

{mockSupplies.filter(supply => supply.defectTotal > 0).length}

{/* Многоуровневая таблица поставок */}
{mockSupplies.map((supply) => { const isSupplyExpanded = expandedSupplies.has(supply.id) return ( {/* Уровень 1: Основная строка поставки */} {/* Уровень 2: Маршруты */} {isSupplyExpanded && supply.routes.map((route) => { const isRouteExpanded = expandedRoutes.has(route.id) return ( {/* Уровень 3: Оптовики */} {isRouteExpanded && route.wholesalers.map((wholesaler) => { const isWholesalerExpanded = expandedWholesalers.has(wholesaler.id) return ( {/* Уровень 4: Товары */} {isWholesalerExpanded && wholesaler.products.map((product) => { const isProductExpanded = expandedProducts.has(product.id) return ( {/* Уровень 5: Параметры товара */} {isProductExpanded && ( )} ) })} ) })} ) })} ) })}
Дата поставки Дата создания План Факт Брак Цена товаров Услуги ФФ Логистика до ФФ Итого сумма Статус
#{supply.number}
{formatDate(supply.deliveryDate)}
{formatDate(supply.createdDate)} {supply.plannedTotal} {supply.actualTotal} 0 ? 'text-red-400' : 'text-white'}`}> {supply.defectTotal} {formatCurrency(supply.totalProductPrice)} {formatCurrency(supply.totalFulfillmentPrice)} {formatCurrency(supply.totalLogisticsPrice)}
{formatCurrency(supply.grandTotal)}
{getStatusBadge(supply.status)}
Маршрут
{route.from} {route.to}
{route.fromAddress} → {route.toAddress}
{route.wholesalers.reduce((sum, w) => sum + w.products.reduce((pSum, p) => pSum + p.plannedQty, 0), 0 )} {route.wholesalers.reduce((sum, w) => sum + w.products.reduce((pSum, p) => pSum + p.actualQty, 0), 0 )} {route.wholesalers.reduce((sum, w) => sum + w.products.reduce((pSum, p) => pSum + p.defectQty, 0), 0 )} {formatCurrency(route.totalProductPrice)} {formatCurrency(route.fulfillmentServicePrice)} {formatCurrency(route.logisticsPrice)} {formatCurrency(route.totalAmount)}
Оптовик
{wholesaler.name}
ИНН: {wholesaler.inn}
{wholesaler.address}
{wholesaler.contact}
{wholesaler.products.reduce((sum, p) => sum + p.plannedQty, 0)} {wholesaler.products.reduce((sum, p) => sum + p.actualQty, 0)} {wholesaler.products.reduce((sum, p) => sum + p.defectQty, 0)} {formatCurrency(wholesaler.products.reduce((sum, p) => sum + calculateProductTotal(p), 0))} {formatCurrency(wholesaler.totalAmount)}
Товар
{product.name}
Артикул: {product.sku}
{product.category}
{product.plannedQty} {product.actualQty} 0 ? 'text-red-400' : 'text-white'}`}> {product.defectQty}
{formatCurrency(calculateProductTotal(product))}
{formatCurrency(product.productPrice)} за шт.
{getEfficiencyBadge(product.plannedQty, product.actualQty, product.defectQty)} {formatCurrency(calculateProductTotal(product))}

📋 Параметры товара:

{product.parameters.map((param) => (
{param.name}
{param.value} {param.unit || ''}
))}
) }