701 lines
26 KiB
TypeScript
701 lines
26 KiB
TypeScript
"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<keyof StoreData>("name");
|
||
const [sortOrder, setSortOrder] = useState<"asc" | "desc">("asc");
|
||
const [expandedStores, setExpandedStores] = useState<Set<string>>(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;
|
||
}) => (
|
||
<div
|
||
className={`glass-card p-3 hover:bg-white/15 transition-all duration-300 relative overflow-hidden`}
|
||
>
|
||
<div className="flex items-center justify-between mb-2">
|
||
<div className="flex items-center space-x-2">
|
||
<div className="p-1.5 bg-white/10 rounded-lg">
|
||
<Icon className="h-3 w-3 text-white" />
|
||
</div>
|
||
<span className="text-white text-xs font-semibold">{title}</span>
|
||
</div>
|
||
{/* Показываем изменения всегда */}
|
||
<div
|
||
className={`flex items-center space-x-1 px-1.5 py-0.5 rounded-full ${
|
||
change >= 0 ? "bg-green-500/20" : "bg-red-500/20"
|
||
}`}
|
||
>
|
||
{change >= 0 ? (
|
||
<TrendingUp className="h-2.5 w-2.5 text-green-400" />
|
||
) : (
|
||
<TrendingDown className="h-2.5 w-2.5 text-red-400" />
|
||
)}
|
||
<span
|
||
className={`text-[10px] font-bold ${
|
||
change >= 0 ? "text-green-400" : "text-red-400"
|
||
}`}
|
||
>
|
||
{formatChange(change)}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div className="text-lg font-bold text-white mb-1">
|
||
{formatNumber(current)}
|
||
</div>
|
||
<div className="text-white/60 text-[10px]">{description}</div>
|
||
</div>
|
||
);
|
||
|
||
// Компонент заголовка таблицы
|
||
const TableHeader = ({
|
||
field,
|
||
children,
|
||
sortable = false,
|
||
}: {
|
||
field?: keyof StoreData;
|
||
children: React.ReactNode;
|
||
sortable?: boolean;
|
||
}) => (
|
||
<div
|
||
className={`px-3 py-2 text-left text-xs font-medium text-white/80 uppercase tracking-wider ${
|
||
sortable ? "cursor-pointer hover:text-white hover:bg-white/5" : ""
|
||
} flex items-center space-x-1`}
|
||
onClick={sortable && field ? () => handleSort(field) : undefined}
|
||
>
|
||
<span>{children}</span>
|
||
{sortable && field && (
|
||
<ArrowUpDown
|
||
className={`h-3 w-3 ${
|
||
sortField === field ? "text-blue-400" : "text-white/40"
|
||
}`}
|
||
/>
|
||
)}
|
||
</div>
|
||
);
|
||
|
||
return (
|
||
<div className="space-y-8">
|
||
<div>
|
||
<h2 className="text-2xl font-bold text-white mb-4">
|
||
Склад фулфилмент - 2
|
||
</h2>
|
||
<p className="text-white/70 mb-6">
|
||
Обновленная версия компонента склада фулфилмента с оптимизацией для
|
||
компактных экранов
|
||
</p>
|
||
</div>
|
||
|
||
<Card
|
||
className="glass-card p-6 overflow-hidden"
|
||
style={{ height: "700px" }}
|
||
>
|
||
<div className="h-full flex flex-col">
|
||
{/* Компактная статичная верхняя секция со статистикой - максимум 30% экрана */}
|
||
<div className="flex-shrink-0 mb-4" style={{ maxHeight: "30%" }}>
|
||
<div className="glass-card p-4">
|
||
<h3 className="text-base font-semibold text-blue-400 mb-3">
|
||
Статистика склада
|
||
</h3>
|
||
<div className="grid grid-cols-2 md:grid-cols-3 xl:grid-cols-6 gap-3">
|
||
<StatCard
|
||
title="Продукты"
|
||
icon={Box}
|
||
current={warehouseStats.products.current}
|
||
change={warehouseStats.products.change}
|
||
description="Готовые к отправке"
|
||
/>
|
||
<StatCard
|
||
title="Товары"
|
||
icon={Package}
|
||
current={warehouseStats.goods.current}
|
||
change={warehouseStats.goods.change}
|
||
description="В обработке"
|
||
/>
|
||
<StatCard
|
||
title="Брак"
|
||
icon={AlertTriangle}
|
||
current={warehouseStats.defects.current}
|
||
change={warehouseStats.defects.change}
|
||
description="Требует утилизации"
|
||
/>
|
||
<StatCard
|
||
title="Возвраты с ПВЗ"
|
||
icon={RotateCcw}
|
||
current={warehouseStats.pvzReturns.current}
|
||
change={warehouseStats.pvzReturns.change}
|
||
description="К обработке"
|
||
/>
|
||
<StatCard
|
||
title="Расходники фулфилмента"
|
||
icon={Wrench}
|
||
current={warehouseStats.fulfillmentSupplies.current}
|
||
change={warehouseStats.fulfillmentSupplies.change}
|
||
description="Расходники, этикетки"
|
||
/>
|
||
<StatCard
|
||
title="Расходники селлеров"
|
||
icon={Users}
|
||
current={warehouseStats.sellerSupplies.current}
|
||
change={warehouseStats.sellerSupplies.change}
|
||
description="Материалы клиентов"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Основная скроллируемая часть - оставшиеся 70% экрана */}
|
||
<div
|
||
className="flex-1 flex flex-col overflow-hidden"
|
||
style={{ minHeight: "60%" }}
|
||
>
|
||
<div className="glass-card flex-1 flex flex-col overflow-hidden">
|
||
{/* Компактная шапка таблицы - максимум 10% экрана */}
|
||
<div
|
||
className="p-4 border-b border-white/10 flex-shrink-0"
|
||
style={{ maxHeight: "10%" }}
|
||
>
|
||
<div className="flex items-center justify-between mb-3">
|
||
<h3 className="text-base font-semibold text-white">
|
||
Детализация по магазинам
|
||
</h3>
|
||
<Badge
|
||
variant="secondary"
|
||
className="bg-blue-500/20 text-blue-300 text-xs"
|
||
>
|
||
{filteredAndSortedStores.length} магазинов
|
||
</Badge>
|
||
</div>
|
||
|
||
{/* Компактный поиск */}
|
||
<div className="relative">
|
||
<Search className="absolute left-2.5 top-1/2 transform -translate-y-1/2 h-3.5 w-3.5 text-white/40" />
|
||
<Input
|
||
placeholder="Поиск по магазинам..."
|
||
value={searchTerm}
|
||
onChange={(e) => setSearchTerm(e.target.value)}
|
||
className="pl-8 h-8 text-sm glass-input text-white placeholder:text-white/40"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Фиксированные заголовки таблицы */}
|
||
<div className="flex-shrink-0 bg-white/5 border-b border-white/10">
|
||
<div className="grid grid-cols-7 gap-0">
|
||
<TableHeader field="name" sortable>
|
||
№ / Магазин
|
||
</TableHeader>
|
||
<TableHeader field="products" sortable>
|
||
Продукты
|
||
</TableHeader>
|
||
<TableHeader field="goods" sortable>
|
||
Товары
|
||
</TableHeader>
|
||
<TableHeader field="defects" sortable>
|
||
Брак
|
||
</TableHeader>
|
||
<TableHeader field="sellerSupplies" sortable>
|
||
Расходники селлера
|
||
</TableHeader>
|
||
<TableHeader field="pvzReturns" sortable>
|
||
Возвраты с ПВЗ
|
||
</TableHeader>
|
||
<TableHeader>Действия</TableHeader>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Строка с суммами */}
|
||
<div className="flex-shrink-0 bg-blue-500/10 border-b border-blue-500/20">
|
||
<div className="grid grid-cols-7 gap-0">
|
||
<div className="px-3 py-2 text-xs font-bold text-blue-300">
|
||
ИТОГО ({filteredAndSortedStores.length})
|
||
</div>
|
||
<div className="px-3 py-2 text-xs font-bold text-white">
|
||
{formatNumber(totals.products)}
|
||
<div
|
||
className={`text-[10px] ${
|
||
totals.productsChange >= 0
|
||
? "text-green-400"
|
||
: "text-red-400"
|
||
}`}
|
||
>
|
||
{formatChange(totals.productsChange)}
|
||
</div>
|
||
</div>
|
||
<div className="px-3 py-2 text-xs font-bold text-white">
|
||
{formatNumber(totals.goods)}
|
||
<div
|
||
className={`text-[10px] ${
|
||
totals.goodsChange >= 0
|
||
? "text-green-400"
|
||
: "text-red-400"
|
||
}`}
|
||
>
|
||
{formatChange(totals.goodsChange)}
|
||
</div>
|
||
</div>
|
||
<div className="px-3 py-2 text-xs font-bold text-white">
|
||
{formatNumber(totals.defects)}
|
||
<div
|
||
className={`text-[10px] ${
|
||
totals.defectsChange >= 0
|
||
? "text-green-400"
|
||
: "text-red-400"
|
||
}`}
|
||
>
|
||
{formatChange(totals.defectsChange)}
|
||
</div>
|
||
</div>
|
||
<div className="px-3 py-2 text-xs font-bold text-white">
|
||
{formatNumber(totals.sellerSupplies)}
|
||
<div
|
||
className={`text-[10px] ${
|
||
totals.sellerSuppliesChange >= 0
|
||
? "text-green-400"
|
||
: "text-red-400"
|
||
}`}
|
||
>
|
||
{formatChange(totals.sellerSuppliesChange)}
|
||
</div>
|
||
</div>
|
||
<div className="px-3 py-2 text-xs font-bold text-white">
|
||
{formatNumber(totals.pvzReturns)}
|
||
<div
|
||
className={`text-[10px] ${
|
||
totals.pvzReturnsChange >= 0
|
||
? "text-green-400"
|
||
: "text-red-400"
|
||
}`}
|
||
>
|
||
{formatChange(totals.pvzReturnsChange)}
|
||
</div>
|
||
</div>
|
||
<div className="px-3 py-2"></div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Скроллируемый контент таблицы - оставшееся пространство */}
|
||
<div className="flex-1 overflow-y-auto scrollbar-thin scrollbar-thumb-white/20 scrollbar-track-transparent">
|
||
{filteredAndSortedStores.map((store, index) => (
|
||
<div
|
||
key={store.id}
|
||
className="border-b border-white/10 hover:bg-white/5 transition-colors"
|
||
>
|
||
{/* Основная строка магазина */}
|
||
<div className="grid grid-cols-7 gap-0">
|
||
<div className="px-3 py-2.5 flex items-center space-x-2">
|
||
<span className="text-white/60 text-xs">
|
||
{index + 1}
|
||
</span>
|
||
<div className="flex items-center space-x-2">
|
||
<div className="w-6 h-6 bg-gradient-to-br from-blue-500 to-purple-500 rounded-md flex items-center justify-center">
|
||
<Store className="h-3 w-3 text-white" />
|
||
</div>
|
||
<div>
|
||
<div className="text-white font-medium text-xs">
|
||
{store.name}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="px-3 py-2.5">
|
||
<div className="text-white font-semibold text-sm">
|
||
{formatNumber(store.products)}
|
||
</div>
|
||
<div
|
||
className={`text-[10px] ${
|
||
store.productsChange >= 0
|
||
? "text-green-400"
|
||
: "text-red-400"
|
||
}`}
|
||
>
|
||
{formatChange(store.productsChange)}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="px-3 py-2.5">
|
||
<div className="text-white font-semibold text-sm">
|
||
{formatNumber(store.goods)}
|
||
</div>
|
||
<div
|
||
className={`text-[10px] ${
|
||
store.goodsChange >= 0
|
||
? "text-green-400"
|
||
: "text-red-400"
|
||
}`}
|
||
>
|
||
{formatChange(store.goodsChange)}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="px-3 py-2.5">
|
||
<div className="text-white font-semibold text-sm">
|
||
{formatNumber(store.defects)}
|
||
</div>
|
||
<div
|
||
className={`text-[10px] ${
|
||
store.defectsChange >= 0
|
||
? "text-green-400"
|
||
: "text-red-400"
|
||
}`}
|
||
>
|
||
{formatChange(store.defectsChange)}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="px-3 py-2.5">
|
||
<div className="text-white font-semibold text-sm">
|
||
{formatNumber(store.sellerSupplies)}
|
||
</div>
|
||
<div
|
||
className={`text-[10px] ${
|
||
store.sellerSuppliesChange >= 0
|
||
? "text-green-400"
|
||
: "text-red-400"
|
||
}`}
|
||
>
|
||
{formatChange(store.sellerSuppliesChange)}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="px-3 py-2.5">
|
||
<div className="text-white font-semibold text-sm">
|
||
{formatNumber(store.pvzReturns)}
|
||
</div>
|
||
<div
|
||
className={`text-[10px] ${
|
||
store.pvzReturnsChange >= 0
|
||
? "text-green-400"
|
||
: "text-red-400"
|
||
}`}
|
||
>
|
||
{formatChange(store.pvzReturnsChange)}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="px-3 py-2.5">
|
||
<Button
|
||
variant="ghost"
|
||
size="sm"
|
||
onClick={() => toggleStoreExpansion(store.id)}
|
||
className="text-white/60 hover:text-white hover:bg-white/10 h-6 w-6 p-0"
|
||
>
|
||
{expandedStores.has(store.id) ? (
|
||
<ChevronUp className="h-3 w-3" />
|
||
) : (
|
||
<ChevronDown className="h-3 w-3" />
|
||
)}
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Расширенная информация */}
|
||
{expandedStores.has(store.id) && (
|
||
<div className="bg-white/5 px-3 py-3 border-t border-white/10">
|
||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||
<div className="glass-secondary rounded-lg p-2">
|
||
<div className="flex items-center space-x-1.5 mb-1">
|
||
<Package2 className="h-3 w-3 text-blue-400" />
|
||
<span className="text-blue-300 text-xs font-medium">
|
||
Продукты
|
||
</span>
|
||
</div>
|
||
<div className="text-white text-sm font-bold">
|
||
{formatNumber(store.products)}
|
||
</div>
|
||
<div className="text-blue-200/60 text-[10px]">
|
||
Готовые к отправке
|
||
</div>
|
||
</div>
|
||
|
||
<div className="glass-secondary rounded-lg p-2">
|
||
<div className="flex items-center space-x-1.5 mb-1">
|
||
<Package className="h-3 w-3 text-cyan-400" />
|
||
<span className="text-cyan-300 text-xs font-medium">
|
||
Товары
|
||
</span>
|
||
</div>
|
||
<div className="text-white text-sm font-bold">
|
||
{formatNumber(store.goods)}
|
||
</div>
|
||
<div className="text-cyan-200/60 text-[10px]">
|
||
В обработке
|
||
</div>
|
||
</div>
|
||
|
||
<div className="glass-secondary rounded-lg p-2">
|
||
<div className="flex items-center space-x-1.5 mb-1">
|
||
<AlertTriangle className="h-3 w-3 text-red-400" />
|
||
<span className="text-red-300 text-xs font-medium">
|
||
Брак
|
||
</span>
|
||
</div>
|
||
<div className="text-white text-sm font-bold">
|
||
{formatNumber(store.defects)}
|
||
</div>
|
||
<div className="text-red-200/60 text-[10px]">
|
||
К утилизации
|
||
</div>
|
||
</div>
|
||
|
||
<div className="glass-secondary rounded-lg p-2">
|
||
<div className="flex items-center space-x-1.5 mb-1">
|
||
<RotateCcw className="h-3 w-3 text-yellow-400" />
|
||
<span className="text-yellow-300 text-xs font-medium">
|
||
Возвраты
|
||
</span>
|
||
</div>
|
||
<div className="text-white text-sm font-bold">
|
||
{formatNumber(store.pvzReturns)}
|
||
</div>
|
||
<div className="text-yellow-200/60 text-[10px]">
|
||
С ПВЗ
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</Card>
|
||
</div>
|
||
);
|
||
}
|