"use client"; import { useState, useMemo } from "react"; import { Card } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Package, TrendingUp, TrendingDown, AlertTriangle, RotateCcw, Wrench, Users, ChevronDown, ChevronUp, Box, Search, ArrowUpDown, Store, Package2, } from "lucide-react"; // Типы данных interface StoreData { id: string; name: string; logo?: string; products: number; goods: number; defects: number; sellerSupplies: number; pvzReturns: number; // Изменения за сутки productsChange: number; goodsChange: number; defectsChange: number; sellerSuppliesChange: number; pvzReturnsChange: number; } interface WarehouseStats { products: { current: number; change: number }; goods: { current: number; change: number }; defects: { current: number; change: number }; pvzReturns: { current: number; change: number }; fulfillmentSupplies: { current: number; change: number }; sellerSupplies: { current: number; change: number }; } export function FulfillmentWarehouse2Demo() { // Состояния для поиска и фильтрации const [searchTerm, setSearchTerm] = useState(""); const [sortField, setSortField] = useState("name"); const [sortOrder, setSortOrder] = useState<"asc" | "desc">("asc"); const [expandedStores, setExpandedStores] = useState>(new Set()); // Данные для статистики - показываем только реальные данные const warehouseStats: WarehouseStats = { products: { current: 0, change: 0 }, // Нет данных о продуктах goods: { current: 0, change: 0 }, // Нет данных о товарах defects: { current: 0, change: 0 }, // Нет данных о браке pvzReturns: { current: 0, change: 0 }, // Нет данных о возвратах с ПВЗ fulfillmentSupplies: { current: 0, change: 0 }, // Нет данных о расходниках ФФ sellerSupplies: { current: 0, change: 0 }, // Нет данных о расходниках селлера }; // Мок данные для магазинов const mockStoreData: StoreData[] = useMemo( () => [ { id: "1", name: "Электроника Плюс", products: 456, goods: 234, defects: 12, sellerSupplies: 89, pvzReturns: 45, productsChange: 23, goodsChange: 15, defectsChange: -3, sellerSuppliesChange: 12, pvzReturnsChange: 8, }, { id: "2", name: "Мода и Стиль", products: 678, goods: 345, defects: 8, sellerSupplies: 123, pvzReturns: 67, productsChange: 34, goodsChange: 22, defectsChange: -2, sellerSuppliesChange: 18, pvzReturnsChange: 12, }, { id: "3", name: "Дом и Сад", products: 289, goods: 156, defects: 5, sellerSupplies: 67, pvzReturns: 23, productsChange: 12, goodsChange: 8, defectsChange: -1, sellerSuppliesChange: 9, pvzReturnsChange: 4, }, { id: "4", name: "Спорт и Отдых", products: 567, goods: 289, defects: 15, sellerSupplies: 134, pvzReturns: 78, productsChange: 28, goodsChange: 19, defectsChange: -4, sellerSuppliesChange: 21, pvzReturnsChange: 15, }, { id: "5", name: "Красота и Здоровье", products: 234, goods: 123, defects: 3, sellerSupplies: 45, pvzReturns: 19, productsChange: 8, goodsChange: 5, defectsChange: 0, sellerSuppliesChange: 6, pvzReturnsChange: 3, }, ], [] ); // Фильтрация и сортировка данных const filteredAndSortedStores = useMemo(() => { const filtered = mockStoreData.filter((store) => store.name.toLowerCase().includes(searchTerm.toLowerCase()) ); filtered.sort((a, b) => { const aValue = a[sortField]; const bValue = b[sortField]; if (typeof aValue === "string" && typeof bValue === "string") { return sortOrder === "asc" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue); } if (typeof aValue === "number" && typeof bValue === "number") { return sortOrder === "asc" ? aValue - bValue : bValue - aValue; } return 0; }); return filtered; }, [searchTerm, sortField, sortOrder, mockStoreData]); // Подсчет общих сумм const totals = useMemo(() => { return filteredAndSortedStores.reduce( (acc, store) => ({ products: acc.products + store.products, goods: acc.goods + store.goods, defects: acc.defects + store.defects, sellerSupplies: acc.sellerSupplies + store.sellerSupplies, pvzReturns: acc.pvzReturns + store.pvzReturns, productsChange: acc.productsChange + store.productsChange, goodsChange: acc.goodsChange + store.goodsChange, defectsChange: acc.defectsChange + store.defectsChange, sellerSuppliesChange: acc.sellerSuppliesChange + store.sellerSuppliesChange, pvzReturnsChange: acc.pvzReturnsChange + store.pvzReturnsChange, }), { products: 0, goods: 0, defects: 0, sellerSupplies: 0, pvzReturns: 0, productsChange: 0, goodsChange: 0, defectsChange: 0, sellerSuppliesChange: 0, pvzReturnsChange: 0, } ); }, [filteredAndSortedStores]); const formatNumber = (num: number) => { return num.toLocaleString("ru-RU"); }; const formatChange = (change: number) => { const sign = change > 0 ? "+" : ""; return `${sign}${change}`; }; const toggleStoreExpansion = (storeId: string) => { const newExpanded = new Set(expandedStores); if (newExpanded.has(storeId)) { newExpanded.delete(storeId); } else { newExpanded.add(storeId); } setExpandedStores(newExpanded); }; const handleSort = (field: keyof StoreData) => { if (sortField === field) { setSortOrder(sortOrder === "asc" ? "desc" : "asc"); } else { setSortField(field); setSortOrder("asc"); } }; // Компонент компактной статистической карточки const StatCard = ({ title, icon: Icon, current, change, description, }: { title: string; icon: React.ComponentType<{ className?: string }>; current: number; change: number; description: string; }) => (
{title}
{/* Показываем изменения всегда */}
= 0 ? "bg-green-500/20" : "bg-red-500/20" }`} > {change >= 0 ? ( ) : ( )} = 0 ? "text-green-400" : "text-red-400" }`} > {formatChange(change)}
{formatNumber(current)}
{description}
); // Компонент заголовка таблицы const TableHeader = ({ field, children, sortable = false, }: { field?: keyof StoreData; children: React.ReactNode; sortable?: boolean; }) => (
handleSort(field) : undefined} > {children} {sortable && field && ( )}
); return (

Склад фулфилмент - 2

Обновленная версия компонента склада фулфилмента с оптимизацией для компактных экранов

{/* Компактная статичная верхняя секция со статистикой - максимум 30% экрана */}

Статистика склада

{/* Основная скроллируемая часть - оставшиеся 70% экрана */}
{/* Компактная шапка таблицы - максимум 10% экрана */}

Детализация по магазинам

{filteredAndSortedStores.length} магазинов
{/* Компактный поиск */}
setSearchTerm(e.target.value)} className="pl-8 h-8 text-sm glass-input text-white placeholder:text-white/40" />
{/* Фиксированные заголовки таблицы */}
№ / Магазин Продукты Товары Брак Расходники селлера Возвраты с ПВЗ Действия
{/* Строка с суммами */}
ИТОГО ({filteredAndSortedStores.length})
{formatNumber(totals.products)}
= 0 ? "text-green-400" : "text-red-400" }`} > {formatChange(totals.productsChange)}
{formatNumber(totals.goods)}
= 0 ? "text-green-400" : "text-red-400" }`} > {formatChange(totals.goodsChange)}
{formatNumber(totals.defects)}
= 0 ? "text-green-400" : "text-red-400" }`} > {formatChange(totals.defectsChange)}
{formatNumber(totals.sellerSupplies)}
= 0 ? "text-green-400" : "text-red-400" }`} > {formatChange(totals.sellerSuppliesChange)}
{formatNumber(totals.pvzReturns)}
= 0 ? "text-green-400" : "text-red-400" }`} > {formatChange(totals.pvzReturnsChange)}
{/* Скроллируемый контент таблицы - оставшееся пространство */}
{filteredAndSortedStores.map((store, index) => (
{/* Основная строка магазина */}
{index + 1}
{store.name}
{formatNumber(store.products)}
= 0 ? "text-green-400" : "text-red-400" }`} > {formatChange(store.productsChange)}
{formatNumber(store.goods)}
= 0 ? "text-green-400" : "text-red-400" }`} > {formatChange(store.goodsChange)}
{formatNumber(store.defects)}
= 0 ? "text-green-400" : "text-red-400" }`} > {formatChange(store.defectsChange)}
{formatNumber(store.sellerSupplies)}
= 0 ? "text-green-400" : "text-red-400" }`} > {formatChange(store.sellerSuppliesChange)}
{formatNumber(store.pvzReturns)}
= 0 ? "text-green-400" : "text-red-400" }`} > {formatChange(store.pvzReturnsChange)}
{/* Расширенная информация */} {expandedStores.has(store.id) && (
Продукты
{formatNumber(store.products)}
Готовые к отправке
Товары
{formatNumber(store.goods)}
В обработке
Брак
{formatNumber(store.defects)}
К утилизации
Возвраты
{formatNumber(store.pvzReturns)}
С ПВЗ
)}
))}
); }