Обновлены компоненты управления поставками: улучшены стили и логика отображения для вкладок и карточек товаров. Добавлены проверки на наличие идентификаторов для улучшения обработки данных. Оптимизирован интерфейс с использованием новых компонентов и улучшена читаемость кода.
This commit is contained in:
@ -19,7 +19,7 @@ export function FulfillmentSuppliesDashboard() {
|
|||||||
<div className="h-screen flex overflow-hidden">
|
<div className="h-screen flex overflow-hidden">
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<main
|
<main
|
||||||
className={`flex-1 ${getSidebarMargin()} px-4 py-3 overflow-hidden transition-all duration-300`}
|
className={`flex-1 ${getSidebarMargin()} px-2 xl:px-4 py-2 xl:py-3 overflow-hidden transition-all duration-300`}
|
||||||
>
|
>
|
||||||
<div className="h-full w-full flex flex-col">
|
<div className="h-full w-full flex flex-col">
|
||||||
{/* Основной контент с табами */}
|
{/* Основной контент с табами */}
|
||||||
@ -29,26 +29,32 @@ export function FulfillmentSuppliesDashboard() {
|
|||||||
onValueChange={setActiveTab}
|
onValueChange={setActiveTab}
|
||||||
className="h-full flex flex-col"
|
className="h-full flex flex-col"
|
||||||
>
|
>
|
||||||
<TabsList className="grid w-full grid-cols-2 bg-white/5 backdrop-blur border-white/10 flex-shrink-0 h-10">
|
<TabsList className="grid w-full grid-cols-2 bg-white/5 backdrop-blur border-white/10 flex-shrink-0 h-8 xl:h-10">
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="fulfillment"
|
value="fulfillment"
|
||||||
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 text-sm"
|
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 text-xs xl:text-sm"
|
||||||
>
|
>
|
||||||
<Building2 className="h-3 w-3" />
|
<Building2 className="h-3 w-3" />
|
||||||
Поставки на фулфилмент
|
<span className="hidden sm:inline">
|
||||||
|
Поставки на фулфилмент
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Фулфилмент</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="marketplace"
|
value="marketplace"
|
||||||
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 text-sm"
|
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 text-xs xl:text-sm"
|
||||||
>
|
>
|
||||||
<ShoppingCart className="h-3 w-3" />
|
<ShoppingCart className="h-3 w-3" />
|
||||||
Поставки на маркетплейсы
|
<span className="hidden sm:inline">
|
||||||
|
Поставки на маркетплейсы
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Маркетплейсы</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
<TabsContent
|
<TabsContent
|
||||||
value="fulfillment"
|
value="fulfillment"
|
||||||
className="flex-1 overflow-hidden mt-3"
|
className="flex-1 overflow-hidden mt-2 xl:mt-3"
|
||||||
>
|
>
|
||||||
<Card className="glass-card h-full overflow-hidden p-0">
|
<Card className="glass-card h-full overflow-hidden p-0">
|
||||||
<FulfillmentSuppliesTab />
|
<FulfillmentSuppliesTab />
|
||||||
@ -57,7 +63,7 @@ export function FulfillmentSuppliesDashboard() {
|
|||||||
|
|
||||||
<TabsContent
|
<TabsContent
|
||||||
value="marketplace"
|
value="marketplace"
|
||||||
className="flex-1 overflow-hidden mt-3"
|
className="flex-1 overflow-hidden mt-2 xl:mt-3"
|
||||||
>
|
>
|
||||||
<Card className="glass-card h-full overflow-hidden p-0">
|
<Card className="glass-card h-full overflow-hidden p-0">
|
||||||
<MarketplaceSuppliesTab />
|
<MarketplaceSuppliesTab />
|
||||||
|
@ -421,6 +421,11 @@ export function FulfillmentGoodsTab() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const toggleSellerExpansion = (sellerId: string) => {
|
const toggleSellerExpansion = (sellerId: string) => {
|
||||||
|
if (!sellerId) {
|
||||||
|
console.error("SellerId is undefined or null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const newExpanded = new Set(expandedSellers);
|
const newExpanded = new Set(expandedSellers);
|
||||||
if (newExpanded.has(sellerId)) {
|
if (newExpanded.has(sellerId)) {
|
||||||
newExpanded.delete(sellerId);
|
newExpanded.delete(sellerId);
|
||||||
@ -431,6 +436,11 @@ export function FulfillmentGoodsTab() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const toggleSupplyExpansion = (supplyId: string) => {
|
const toggleSupplyExpansion = (supplyId: string) => {
|
||||||
|
if (!supplyId) {
|
||||||
|
console.error("SupplyId is undefined or null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const newExpanded = new Set(expandedSupplies);
|
const newExpanded = new Set(expandedSupplies);
|
||||||
if (newExpanded.has(supplyId)) {
|
if (newExpanded.has(supplyId)) {
|
||||||
newExpanded.delete(supplyId);
|
newExpanded.delete(supplyId);
|
||||||
@ -441,6 +451,11 @@ export function FulfillmentGoodsTab() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const toggleRouteExpansion = (routeId: string) => {
|
const toggleRouteExpansion = (routeId: string) => {
|
||||||
|
if (!routeId) {
|
||||||
|
console.error("RouteId is undefined or null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const newExpanded = new Set(expandedRoutes);
|
const newExpanded = new Set(expandedRoutes);
|
||||||
if (newExpanded.has(routeId)) {
|
if (newExpanded.has(routeId)) {
|
||||||
newExpanded.delete(routeId);
|
newExpanded.delete(routeId);
|
||||||
@ -451,6 +466,11 @@ export function FulfillmentGoodsTab() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const toggleSupplierExpansion = (supplierId: string) => {
|
const toggleSupplierExpansion = (supplierId: string) => {
|
||||||
|
if (!supplierId) {
|
||||||
|
console.error("SupplierId is undefined or null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const newExpanded = new Set(expandedSuppliers);
|
const newExpanded = new Set(expandedSuppliers);
|
||||||
if (newExpanded.has(supplierId)) {
|
if (newExpanded.has(supplierId)) {
|
||||||
newExpanded.delete(supplierId);
|
newExpanded.delete(supplierId);
|
||||||
@ -634,34 +654,37 @@ export function FulfillmentGoodsTab() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col p-4">
|
<div className="h-full flex flex-col p-2 xl:p-4">
|
||||||
<Tabs
|
<Tabs
|
||||||
value={activeTab}
|
value={activeTab}
|
||||||
onValueChange={setActiveTab}
|
onValueChange={setActiveTab}
|
||||||
className="h-full flex flex-col"
|
className="h-full flex flex-col"
|
||||||
>
|
>
|
||||||
{/* Вкладки товаров */}
|
{/* Вкладки товаров */}
|
||||||
<TabsList className="grid w-full grid-cols-3 bg-white/10 backdrop-blur border-white/10 flex-shrink-0 h-10 mb-4">
|
<TabsList className="grid w-full grid-cols-3 bg-white/10 backdrop-blur border-white/10 flex-shrink-0 h-8 xl:h-10 mb-2 xl:mb-4">
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="new"
|
value="new"
|
||||||
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-2 text-sm"
|
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 xl:gap-2 text-xs xl:text-sm"
|
||||||
>
|
>
|
||||||
<Clock className="h-4 w-4" />
|
<Clock className="h-3 w-3 xl:h-4 xl:w-4" />
|
||||||
Новые
|
<span className="hidden sm:inline">Новые</span>
|
||||||
|
<span className="sm:hidden">Н</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="receiving"
|
value="receiving"
|
||||||
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-2 text-sm"
|
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 xl:gap-2 text-xs xl:text-sm"
|
||||||
>
|
>
|
||||||
<FileText className="h-4 w-4" />
|
<FileText className="h-3 w-3 xl:h-4 xl:w-4" />
|
||||||
Приёмка
|
<span className="hidden sm:inline">Приёмка</span>
|
||||||
|
<span className="sm:hidden">П</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="received"
|
value="received"
|
||||||
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-2 text-sm"
|
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 xl:gap-2 text-xs xl:text-sm"
|
||||||
>
|
>
|
||||||
<CheckCircle className="h-4 w-4" />
|
<CheckCircle className="h-3 w-3 xl:h-4 xl:w-4" />
|
||||||
Принято
|
<span className="hidden sm:inline">Принято</span>
|
||||||
|
<span className="sm:hidden">Пр</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
@ -705,60 +728,66 @@ export function FulfillmentGoodsTab() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col space-y-4">
|
<div className="h-full flex flex-col space-y-2 xl:space-y-4">
|
||||||
{/* Статистика с кнопкой */}
|
{/* Статистика с кнопкой */}
|
||||||
<div className="flex items-center justify-between gap-4">
|
<div className="flex flex-col xl:flex-row xl:items-center xl:justify-between gap-3 xl:gap-4">
|
||||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3 flex-1">
|
<div className="grid grid-cols-2 xl:grid-cols-4 gap-2 xl:gap-3 flex-1">
|
||||||
<Card className="glass-card p-3 h-[60px]">
|
<Card className="glass-card p-2 xl:p-3 h-[50px] xl:h-[60px]">
|
||||||
<div className="flex items-center space-x-2 h-full">
|
<div className="flex items-center space-x-1.5 xl:space-x-2 h-full">
|
||||||
<div className="p-1.5 bg-blue-500/20 rounded">
|
<div className="p-1 xl:p-1.5 bg-blue-500/20 rounded">
|
||||||
<Package className="h-3 w-3 text-blue-400" />
|
<Package className="h-2.5 w-2.5 xl:h-3 xl:w-3 text-blue-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-white/60 text-xs">Поставок</p>
|
<p className="text-white/60 text-[10px] xl:text-xs">
|
||||||
<p className="text-lg font-bold text-white">
|
Поставок
|
||||||
|
</p>
|
||||||
|
<p className="text-sm xl:text-lg font-bold text-white">
|
||||||
{tabFilteredSupplies.length}
|
{tabFilteredSupplies.length}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="glass-card p-3 h-[60px]">
|
<Card className="glass-card p-2 xl:p-3 h-[50px] xl:h-[60px]">
|
||||||
<div className="flex items-center space-x-2 h-full">
|
<div className="flex items-center space-x-1.5 xl:space-x-2 h-full">
|
||||||
<div className="p-1.5 bg-green-500/20 rounded">
|
<div className="p-1 xl:p-1.5 bg-green-500/20 rounded">
|
||||||
<TrendingUp className="h-3 w-3 text-green-400" />
|
<TrendingUp className="h-2.5 w-2.5 xl:h-3 xl:w-3 text-green-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="min-w-0 flex-1">
|
||||||
<p className="text-white/60 text-xs">Стоимость</p>
|
<p className="text-white/60 text-[10px] xl:text-xs">
|
||||||
<p className="text-lg font-bold text-white">
|
Стоимость
|
||||||
|
</p>
|
||||||
|
<p className="text-sm xl:text-lg font-bold text-white truncate">
|
||||||
{formatCurrency(getTabTotalValue())}
|
{formatCurrency(getTabTotalValue())}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="glass-card p-3 h-[60px]">
|
<Card className="glass-card p-2 xl:p-3 h-[50px] xl:h-[60px]">
|
||||||
<div className="flex items-center space-x-2 h-full">
|
<div className="flex items-center space-x-1.5 xl:space-x-2 h-full">
|
||||||
<div className="p-1.5 bg-purple-500/20 rounded">
|
<div className="p-1 xl:p-1.5 bg-purple-500/20 rounded">
|
||||||
<Package2 className="h-3 w-3 text-purple-400" />
|
<Package2 className="h-2.5 w-2.5 xl:h-3 xl:w-3 text-purple-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-white/60 text-xs">Товаров</p>
|
<p className="text-white/60 text-[10px] xl:text-xs">
|
||||||
<p className="text-lg font-bold text-white">
|
Товаров
|
||||||
|
</p>
|
||||||
|
<p className="text-sm xl:text-lg font-bold text-white">
|
||||||
{getTabTotalQuantity()} ед.
|
{getTabTotalQuantity()} ед.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="glass-card p-3 h-[60px]">
|
<Card className="glass-card p-2 xl:p-3 h-[50px] xl:h-[60px]">
|
||||||
<div className="flex items-center space-x-2 h-full">
|
<div className="flex items-center space-x-1.5 xl:space-x-2 h-full">
|
||||||
<div className="p-1.5 bg-orange-500/20 rounded">
|
<div className="p-1 xl:p-1.5 bg-orange-500/20 rounded">
|
||||||
<Boxes className="h-3 w-3 text-orange-400" />
|
<Boxes className="h-2.5 w-2.5 xl:h-3 xl:w-3 text-orange-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-white/60 text-xs">Объём</p>
|
<p className="text-white/60 text-[10px] xl:text-xs">Объём</p>
|
||||||
<p className="text-lg font-bold text-white">
|
<p className="text-sm xl:text-lg font-bold text-white">
|
||||||
{getTabTotalVolume().toFixed(1)} м³
|
{getTabTotalVolume().toFixed(1)} м³
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -768,29 +797,30 @@ export function FulfillmentGoodsTab() {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
className="bg-gradient-to-r from-blue-500 to-purple-500 hover:from-blue-600 hover:to-purple-600 text-white text-sm px-6 h-[60px] whitespace-nowrap"
|
className="bg-gradient-to-r from-blue-500 to-purple-500 hover:from-blue-600 hover:to-purple-600 text-white text-xs xl:text-sm px-3 xl:px-6 h-[50px] xl:h-[60px] whitespace-nowrap w-full xl:w-auto"
|
||||||
>
|
>
|
||||||
<Plus className="h-4 w-4 mr-2" />
|
<Plus className="h-3 w-3 xl:h-4 xl:w-4 mr-1 xl:mr-2" />
|
||||||
Создать поставку
|
<span className="hidden sm:inline">Создать поставку</span>
|
||||||
|
<span className="sm:hidden">Создать</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Фильтры */}
|
{/* Фильтры */}
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-2 xl:gap-3">
|
||||||
<div className="relative flex-1 max-w-md">
|
<div className="relative flex-1 max-w-md">
|
||||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-white/40" />
|
<Search className="absolute left-2 xl:left-3 top-1/2 transform -translate-y-1/2 h-3 w-3 xl:h-4 xl:w-4 text-white/40" />
|
||||||
<Input
|
<Input
|
||||||
placeholder="Поиск по номеру, магазину, ИНН..."
|
placeholder="Поиск по номеру, магазину, ИНН..."
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
className="glass-input pl-10 text-white placeholder:text-white/40"
|
className="glass-input pl-8 xl:pl-10 text-white placeholder:text-white/40 text-xs xl:text-sm h-8 xl:h-auto"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
value={statusFilter}
|
value={statusFilter}
|
||||||
onChange={(e) => setStatusFilter(e.target.value)}
|
onChange={(e) => setStatusFilter(e.target.value)}
|
||||||
className="glass-input text-white text-sm px-3 py-2 rounded-lg bg-white/5 border border-white/10"
|
className="glass-input text-white text-xs xl:text-sm px-2 xl:px-3 py-1.5 xl:py-2 rounded-lg bg-white/5 border border-white/10 h-8 xl:h-auto"
|
||||||
>
|
>
|
||||||
<option value="all">Все статусы</option>
|
<option value="all">Все статусы</option>
|
||||||
<option value="planned">Запланировано</option>
|
<option value="planned">Запланировано</option>
|
||||||
@ -802,7 +832,7 @@ export function FulfillmentGoodsTab() {
|
|||||||
|
|
||||||
{/* Список поставок */}
|
{/* Список поставок */}
|
||||||
<div className="flex-1 overflow-hidden">
|
<div className="flex-1 overflow-hidden">
|
||||||
<div className="h-full overflow-y-auto space-y-3">
|
<div className="h-full overflow-y-auto space-y-2 xl:space-y-3">
|
||||||
{tabFilteredSupplies.map((supply, index) => {
|
{tabFilteredSupplies.map((supply, index) => {
|
||||||
const isSellerExpanded = expandedSellers.has(supply.seller.id);
|
const isSellerExpanded = expandedSellers.has(supply.seller.id);
|
||||||
const isSupplyExpanded = expandedSupplies.has(supply.id);
|
const isSupplyExpanded = expandedSupplies.has(supply.id);
|
||||||
@ -810,32 +840,44 @@ export function FulfillmentGoodsTab() {
|
|||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
key={supply.id}
|
key={supply.id}
|
||||||
className="glass-card p-4 hover:bg-white/10 transition-colors"
|
className="glass-card p-2 xl:p-4 hover:bg-white/10 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="space-y-3">
|
<div className="space-y-2 xl:space-y-3">
|
||||||
{/* Компактный блок с названием магазина */}
|
{/* Компактный блок с названием магазина */}
|
||||||
<div
|
<div
|
||||||
className="flex items-center justify-between bg-white/5 rounded-lg p-2 cursor-pointer hover:bg-white/10 transition-colors"
|
className="flex flex-col xl:flex-row xl:items-center xl:justify-between bg-white/5 rounded-lg p-1.5 xl:p-2 cursor-pointer hover:bg-white/10 transition-colors gap-2 xl:gap-0"
|
||||||
onClick={() => toggleSellerExpansion(supply.seller.id)}
|
onClick={() => {
|
||||||
|
if (supply?.seller?.id) {
|
||||||
|
toggleSellerExpansion(supply.seller.id);
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
"Supply seller or seller.id is undefined",
|
||||||
|
supply
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-2 xl:gap-3">
|
||||||
<div className="p-1.5 bg-green-500/20 rounded">
|
<div className="p-1 xl:p-1.5 bg-green-500/20 rounded">
|
||||||
<Store className="h-3 w-3 text-green-400" />
|
<Store className="h-2.5 w-2.5 xl:h-3 xl:w-3 text-green-400" />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex flex-col xl:flex-row xl:items-center gap-1 xl:gap-2 min-w-0 flex-1">
|
||||||
<span className="text-white font-medium text-sm">
|
<span className="text-white font-medium text-xs xl:text-sm truncate">
|
||||||
{supply.seller.storeName}
|
{supply.seller.storeName}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-white/60 text-xs"> • </span>
|
<div className="flex items-center gap-1 xl:gap-2 text-[10px] xl:text-xs">
|
||||||
<span className="text-white/80 text-xs">
|
<span className="text-white/80 truncate">
|
||||||
{supply.seller.managerName}
|
{supply.seller.managerName}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-white/60 text-xs"> • </span>
|
<span className="text-white/60 hidden xl:inline">
|
||||||
<span className="text-white/80 text-xs">
|
{" "}
|
||||||
{supply.seller.phone}
|
•{" "}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-white/60 text-xs"> • </span>
|
<span className="text-white/80 truncate">
|
||||||
<div className="flex items-center gap-1">
|
{supply.seller.phone}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-1 xl:hidden">
|
||||||
<a
|
<a
|
||||||
href={`https://t.me/${supply.seller.phone.replace(
|
href={`https://t.me/${supply.seller.phone.replace(
|
||||||
/[^\d]/g,
|
/[^\d]/g,
|
||||||
@ -920,7 +962,16 @@ export function FulfillmentGoodsTab() {
|
|||||||
{/* Единый блок со всеми параметрами в одной строке */}
|
{/* Единый блок со всеми параметрами в одной строке */}
|
||||||
<div
|
<div
|
||||||
className="bg-white/5 rounded-lg p-4 cursor-pointer hover:bg-white/10 transition-colors"
|
className="bg-white/5 rounded-lg p-4 cursor-pointer hover:bg-white/10 transition-colors"
|
||||||
onClick={() => toggleSupplyExpansion(supply.id)}
|
onClick={() => {
|
||||||
|
if (supply?.id) {
|
||||||
|
toggleSupplyExpansion(supply.id);
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
"Supply or supply.id is undefined",
|
||||||
|
supply
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className="grid grid-cols-2 lg:grid-cols-9 gap-4 items-center">
|
<div className="grid grid-cols-2 lg:grid-cols-9 gap-4 items-center">
|
||||||
{/* Порядковый номер */}
|
{/* Порядковый номер */}
|
||||||
@ -1079,9 +1130,16 @@ export function FulfillmentGoodsTab() {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="grid grid-cols-1 lg:grid-cols-8 gap-3 items-center cursor-pointer hover:bg-white/5 transition-colors rounded-lg p-1"
|
className="grid grid-cols-1 lg:grid-cols-8 gap-3 items-center cursor-pointer hover:bg-white/5 transition-colors rounded-lg p-1"
|
||||||
onClick={() =>
|
onClick={() => {
|
||||||
toggleRouteExpansion(route.id)
|
if (route && route.id) {
|
||||||
}
|
toggleRouteExpansion(route.id);
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
"Route or route.id is undefined",
|
||||||
|
route
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{/* Название маршрута */}
|
{/* Название маршрута */}
|
||||||
<div className="lg:col-span-2">
|
<div className="lg:col-span-2">
|
||||||
@ -1089,7 +1147,7 @@ export function FulfillmentGoodsTab() {
|
|||||||
Маршрут
|
Маршрут
|
||||||
</p>
|
</p>
|
||||||
<p className="text-white font-medium text-sm">
|
<p className="text-white font-medium text-sm">
|
||||||
{route.routeName}
|
{route?.routeName || "Без названия"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -1099,7 +1157,7 @@ export function FulfillmentGoodsTab() {
|
|||||||
Откуда
|
Откуда
|
||||||
</p>
|
</p>
|
||||||
<p className="text-white text-xs">
|
<p className="text-white text-xs">
|
||||||
{route.fromAddress}
|
{route?.fromAddress || "Не указано"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -1109,7 +1167,7 @@ export function FulfillmentGoodsTab() {
|
|||||||
Куда
|
Куда
|
||||||
</p>
|
</p>
|
||||||
<p className="text-white text-xs">
|
<p className="text-white text-xs">
|
||||||
{route.toAddress}
|
{route?.toAddress || "Не указано"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -1119,7 +1177,7 @@ export function FulfillmentGoodsTab() {
|
|||||||
Расстояние
|
Расстояние
|
||||||
</p>
|
</p>
|
||||||
<p className="text-white font-semibold text-sm">
|
<p className="text-white font-semibold text-sm">
|
||||||
{route.distance} км
|
{route?.distance || 0} км
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -1129,7 +1187,7 @@ export function FulfillmentGoodsTab() {
|
|||||||
Время
|
Время
|
||||||
</p>
|
</p>
|
||||||
<p className="text-white font-semibold text-sm">
|
<p className="text-white font-semibold text-sm">
|
||||||
{route.estimatedTime}
|
{route?.estimatedTime || "Не указано"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -1157,192 +1215,220 @@ export function FulfillmentGoodsTab() {
|
|||||||
|
|
||||||
{/* Третий уровень - Поставщики/Оптовики */}
|
{/* Третий уровень - Поставщики/Оптовики */}
|
||||||
{isRouteExpanded &&
|
{isRouteExpanded &&
|
||||||
route.suppliers &&
|
route?.suppliers &&
|
||||||
|
Array.isArray(route.suppliers) &&
|
||||||
route.suppliers.length > 0 && (
|
route.suppliers.length > 0 && (
|
||||||
<div className="mt-4 pt-4 border-t border-white/10">
|
<div className="mt-4 pt-4 border-t border-white/10">
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<h5 className="text-white font-medium text-sm flex items-center gap-2">
|
<h5 className="text-white font-medium text-sm flex items-center gap-2">
|
||||||
<Building2 className="h-4 w-4 text-purple-400" />
|
<Building2 className="h-4 w-4 text-purple-400" />
|
||||||
Поставщики/Оптовики (
|
Поставщики/Оптовики (
|
||||||
{route.suppliers.length})
|
{route?.suppliers?.length || 0})
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{route.suppliers.map((supplier) => {
|
{(route?.suppliers || []).map(
|
||||||
const isSupplierExpanded =
|
(supplier) => {
|
||||||
expandedSuppliers.has(
|
const isSupplierExpanded =
|
||||||
supplier.id
|
expandedSuppliers.has(
|
||||||
);
|
supplier.id
|
||||||
return (
|
);
|
||||||
<div
|
return (
|
||||||
key={supplier.id}
|
|
||||||
className="bg-white/5 rounded-lg p-3 border border-white/5"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
className="grid grid-cols-1 lg:grid-cols-7 gap-3 items-center cursor-pointer hover:bg-white/5 transition-colors rounded-lg p-1"
|
key={supplier.id}
|
||||||
onClick={() =>
|
className="bg-white/5 rounded-lg p-3 border border-white/5"
|
||||||
toggleSupplierExpansion(
|
|
||||||
supplier.id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{/* Название поставщика */}
|
<div
|
||||||
<div className="lg:col-span-2">
|
className="grid grid-cols-1 lg:grid-cols-7 gap-3 items-center cursor-pointer hover:bg-white/5 transition-colors rounded-lg p-1"
|
||||||
<p className="text-white/60 text-xs mb-1">
|
onClick={() => {
|
||||||
Поставщик
|
if (
|
||||||
</p>
|
supplier &&
|
||||||
<p className="text-white font-medium text-sm">
|
supplier.id
|
||||||
{supplier.name}
|
) {
|
||||||
</p>
|
toggleSupplierExpansion(
|
||||||
</div>
|
supplier.id
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
"Supplier or supplier.id is undefined",
|
||||||
|
supplier
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Название поставщика */}
|
||||||
|
<div className="lg:col-span-2">
|
||||||
|
<p className="text-white/60 text-xs mb-1">
|
||||||
|
Поставщик
|
||||||
|
</p>
|
||||||
|
<p className="text-white font-medium text-sm">
|
||||||
|
{supplier?.name ||
|
||||||
|
"Без названия"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* ИНН */}
|
{/* ИНН */}
|
||||||
<div>
|
<div>
|
||||||
<p className="text-white/60 text-xs mb-1">
|
<p className="text-white/60 text-xs mb-1">
|
||||||
ИНН
|
ИНН
|
||||||
</p>
|
</p>
|
||||||
<p className="text-white text-xs font-mono">
|
<p className="text-white text-xs font-mono">
|
||||||
{supplier.inn}
|
{supplier?.inn ||
|
||||||
</p>
|
"Не указан"}
|
||||||
</div>
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Тип */}
|
{/* Тип */}
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<p className="text-white/60 text-xs mb-1">
|
<p className="text-white/60 text-xs mb-1">
|
||||||
Тип
|
Тип
|
||||||
</p>
|
</p>
|
||||||
<Badge
|
<Badge
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className={`text-xs ${
|
className={`text-xs ${
|
||||||
supplier.type ===
|
supplier?.type ===
|
||||||
|
"WHOLESALE"
|
||||||
|
? "text-blue-300 border-blue-400/30 bg-blue-500/10"
|
||||||
|
: "text-orange-300 border-orange-400/30 bg-orange-500/10"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{supplier?.type ===
|
||||||
"WHOLESALE"
|
"WHOLESALE"
|
||||||
? "text-blue-300 border-blue-400/30 bg-blue-500/10"
|
? "Оптовик"
|
||||||
: "text-orange-300 border-orange-400/30 bg-orange-500/10"
|
: "Поставщик"}
|
||||||
}`}
|
</Badge>
|
||||||
>
|
</div>
|
||||||
{supplier.type ===
|
|
||||||
"WHOLESALE"
|
|
||||||
? "Оптовик"
|
|
||||||
: "Поставщик"}
|
|
||||||
</Badge>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Менеджер */}
|
{/* Менеджер */}
|
||||||
<div>
|
<div>
|
||||||
<p className="text-white/60 text-xs mb-1">
|
<p className="text-white/60 text-xs mb-1">
|
||||||
Менеджер
|
Менеджер
|
||||||
</p>
|
</p>
|
||||||
<p className="text-white text-xs">
|
<p className="text-white text-xs">
|
||||||
{supplier.managerName}
|
{supplier?.managerName ||
|
||||||
</p>
|
"Не указан"}
|
||||||
</div>
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Стоимость */}
|
{/* Стоимость */}
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<p className="text-white/60 text-xs mb-1">
|
<p className="text-white/60 text-xs mb-1">
|
||||||
Стоимость
|
Стоимость
|
||||||
</p>
|
</p>
|
||||||
<p className="text-green-400 font-semibold text-sm">
|
<p className="text-green-400 font-semibold text-sm">
|
||||||
{formatCurrency(
|
{formatCurrency(
|
||||||
supplier.totalValue
|
supplier?.totalValue ||
|
||||||
|
0
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Статус */}
|
||||||
|
<div className="text-center">
|
||||||
|
<p className="text-white/60 text-xs mb-1">
|
||||||
|
Статус
|
||||||
|
</p>
|
||||||
|
{getSupplierStatusBadge(
|
||||||
|
supplier?.status ||
|
||||||
|
"active"
|
||||||
)}
|
)}
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Статус */}
|
{/* Детальная информация о поставщике */}
|
||||||
<div className="text-center">
|
{isSupplierExpanded && (
|
||||||
<p className="text-white/60 text-xs mb-1">
|
<div className="mt-3 pt-3 border-t border-white/5">
|
||||||
Статус
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
||||||
</p>
|
<div>
|
||||||
{getSupplierStatusBadge(
|
<p className="text-white/60 text-xs mb-1">
|
||||||
supplier.status
|
Полное название
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Детальная информация о поставщике */}
|
|
||||||
{isSupplierExpanded && (
|
|
||||||
<div className="mt-3 pt-3 border-t border-white/5">
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
|
||||||
<div>
|
|
||||||
<p className="text-white/60 text-xs mb-1">
|
|
||||||
Полное название
|
|
||||||
</p>
|
|
||||||
<p className="text-white text-sm">
|
|
||||||
{supplier.fullName ||
|
|
||||||
supplier.name}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-white/60 text-xs mb-1">
|
|
||||||
Телефон
|
|
||||||
</p>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<p className="text-white text-sm">
|
|
||||||
{supplier.phone}
|
|
||||||
</p>
|
</p>
|
||||||
<div className="flex items-center gap-1">
|
<p className="text-white text-sm">
|
||||||
<a
|
{supplier?.fullName ||
|
||||||
href={`https://t.me/${supplier.phone.replace(
|
supplier?.name ||
|
||||||
/[^\d]/g,
|
"Не указано"}
|
||||||
""
|
</p>
|
||||||
)}`}
|
</div>
|
||||||
target="_blank"
|
<div>
|
||||||
rel="noopener noreferrer"
|
<p className="text-white/60 text-xs mb-1">
|
||||||
className="p-1 bg-blue-500/20 rounded hover:bg-blue-500/30 transition-colors"
|
Телефон
|
||||||
title="Написать в Telegram"
|
</p>
|
||||||
>
|
<div className="flex items-center gap-2">
|
||||||
<svg
|
<p className="text-white text-sm">
|
||||||
className="h-3 w-3 text-blue-400"
|
{supplier?.phone ||
|
||||||
viewBox="0 0 24 24"
|
"Не указан"}
|
||||||
fill="currentColor"
|
</p>
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<a
|
||||||
|
href={`https://t.me/${(
|
||||||
|
supplier?.phone ||
|
||||||
|
""
|
||||||
|
).replace(
|
||||||
|
/[^\d]/g,
|
||||||
|
""
|
||||||
|
)}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="p-1 bg-blue-500/20 rounded hover:bg-blue-500/30 transition-colors"
|
||||||
|
title="Написать в Telegram"
|
||||||
>
|
>
|
||||||
<path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z" />
|
<svg
|
||||||
</svg>
|
className="h-3 w-3 text-blue-400"
|
||||||
</a>
|
viewBox="0 0 24 24"
|
||||||
<a
|
fill="currentColor"
|
||||||
href={`https://wa.me/${supplier.phone.replace(
|
>
|
||||||
/[^\d]/g,
|
<path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z" />
|
||||||
""
|
</svg>
|
||||||
)}`}
|
</a>
|
||||||
target="_blank"
|
<a
|
||||||
rel="noopener noreferrer"
|
href={`https://wa.me/${(
|
||||||
className="p-1 bg-green-500/20 rounded hover:bg-green-500/30 transition-colors"
|
supplier?.phone ||
|
||||||
title="Написать в WhatsApp"
|
""
|
||||||
>
|
).replace(
|
||||||
<svg
|
/[^\d]/g,
|
||||||
className="h-3 w-3 text-green-400"
|
""
|
||||||
viewBox="0 0 24 24"
|
)}`}
|
||||||
fill="currentColor"
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="p-1 bg-green-500/20 rounded hover:bg-green-500/30 transition-colors"
|
||||||
|
title="Написать в WhatsApp"
|
||||||
>
|
>
|
||||||
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893A11.821 11.821 0 0020.885 3.488" />
|
<svg
|
||||||
</svg>
|
className="h-3 w-3 text-green-400"
|
||||||
</a>
|
viewBox="0 0 24 24"
|
||||||
|
fill="currentColor"
|
||||||
|
>
|
||||||
|
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893A11.821 11.821 0 0020.885 3.488" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-white/60 text-xs mb-1">
|
||||||
|
Email
|
||||||
|
</p>
|
||||||
|
<p className="text-white text-sm">
|
||||||
|
{supplier?.email ||
|
||||||
|
"Не указан"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="mt-3">
|
||||||
<p className="text-white/60 text-xs mb-1">
|
<p className="text-white/60 text-xs mb-1">
|
||||||
Email
|
Адрес
|
||||||
</p>
|
</p>
|
||||||
<p className="text-white text-sm">
|
<p className="text-white text-sm">
|
||||||
{supplier.email}
|
{supplier?.address ||
|
||||||
|
"Не указан"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-3">
|
)}
|
||||||
<p className="text-white/60 text-xs mb-1">
|
</div>
|
||||||
Адрес
|
);
|
||||||
</p>
|
}
|
||||||
<p className="text-white text-sm">
|
)}
|
||||||
{supplier.address}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -21,7 +21,12 @@ export function FulfillmentSuppliesTab() {
|
|||||||
// Проверяем URL параметр при загрузке
|
// Проверяем URL параметр при загрузке
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const tabParam = searchParams.get("tab");
|
const tabParam = searchParams.get("tab");
|
||||||
if (tabParam && ["goods", "detailed-supplies", "consumables", "returns"].includes(tabParam)) {
|
if (
|
||||||
|
tabParam &&
|
||||||
|
["goods", "detailed-supplies", "consumables", "returns"].includes(
|
||||||
|
tabParam
|
||||||
|
)
|
||||||
|
) {
|
||||||
setActiveTab(tabParam);
|
setActiveTab(tabParam);
|
||||||
}
|
}
|
||||||
}, [searchParams]);
|
}, [searchParams]);
|
||||||
@ -41,34 +46,40 @@ export function FulfillmentSuppliesTab() {
|
|||||||
onValueChange={handleTabChange}
|
onValueChange={handleTabChange}
|
||||||
className="h-full flex flex-col"
|
className="h-full flex flex-col"
|
||||||
>
|
>
|
||||||
<TabsList className="grid w-full grid-cols-4 bg-white/10 backdrop-blur border-white/10 flex-shrink-0 h-10 mb-3 mx-4 mt-4">
|
<TabsList className="grid w-full grid-cols-4 bg-white/10 backdrop-blur border-white/10 flex-shrink-0 h-8 xl:h-10 mb-2 xl:mb-3 mx-2 xl:mx-4 mt-2 xl:mt-4">
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="goods"
|
value="goods"
|
||||||
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 text-xs"
|
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 text-[10px] xl:text-xs"
|
||||||
>
|
>
|
||||||
<Package className="h-3 w-3" />
|
<Package className="h-2.5 w-2.5 xl:h-3 xl:w-3" />
|
||||||
Товар
|
<span className="hidden sm:inline">Товар</span>
|
||||||
|
<span className="sm:hidden">Т</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="detailed-supplies"
|
value="detailed-supplies"
|
||||||
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 text-xs"
|
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 text-[10px] xl:text-xs"
|
||||||
>
|
>
|
||||||
<Building2 className="h-3 w-3" />
|
<Building2 className="h-2.5 w-2.5 xl:h-3 xl:w-3" />
|
||||||
Наши расходники
|
<span className="hidden md:inline">Наши расходники</span>
|
||||||
|
<span className="md:hidden hidden sm:inline">Наши</span>
|
||||||
|
<span className="sm:hidden">Н</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="consumables"
|
value="consumables"
|
||||||
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 text-xs"
|
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 text-[10px] xl:text-xs"
|
||||||
>
|
>
|
||||||
<Wrench className="h-3 w-3" />
|
<Wrench className="h-2.5 w-2.5 xl:h-3 xl:w-3" />
|
||||||
Расходники селлеров
|
<span className="hidden md:inline">Расходники селлеров</span>
|
||||||
|
<span className="md:hidden hidden sm:inline">Селлеры</span>
|
||||||
|
<span className="sm:hidden">С</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="returns"
|
value="returns"
|
||||||
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 text-xs"
|
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 text-[10px] xl:text-xs"
|
||||||
>
|
>
|
||||||
<RotateCcw className="h-3 w-3" />
|
<RotateCcw className="h-2.5 w-2.5 xl:h-3 xl:w-3" />
|
||||||
Возвраты с ПВЗ
|
<span className="hidden sm:inline">Возвраты с ПВЗ</span>
|
||||||
|
<span className="sm:hidden">В</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
@ -80,13 +91,13 @@ export function FulfillmentSuppliesTab() {
|
|||||||
value="detailed-supplies"
|
value="detailed-supplies"
|
||||||
className="flex-1 overflow-hidden"
|
className="flex-1 overflow-hidden"
|
||||||
>
|
>
|
||||||
<div className="h-full p-4 overflow-y-auto">
|
<div className="h-full p-2 xl:p-4 overflow-y-auto">
|
||||||
<FulfillmentDetailedSuppliesTab />
|
<FulfillmentDetailedSuppliesTab />
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="consumables" className="flex-1 overflow-hidden">
|
<TabsContent value="consumables" className="flex-1 overflow-hidden">
|
||||||
<div className="h-full p-4 overflow-y-auto">
|
<div className="h-full p-2 xl:p-4 overflow-y-auto">
|
||||||
<FulfillmentConsumablesOrdersTab />
|
<FulfillmentConsumablesOrdersTab />
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
@ -18,24 +18,30 @@ export function MarketplaceSuppliesTab() {
|
|||||||
onValueChange={setActiveTab}
|
onValueChange={setActiveTab}
|
||||||
className="h-full flex flex-col"
|
className="h-full flex flex-col"
|
||||||
>
|
>
|
||||||
<TabsList className="grid w-full grid-cols-2 bg-white/10 backdrop-blur border-white/10 flex-shrink-0 h-10 mb-3 mx-4 mt-4">
|
<TabsList className="grid w-full grid-cols-2 bg-white/10 backdrop-blur border-white/10 flex-shrink-0 h-8 xl:h-10 mb-2 xl:mb-3 mx-2 xl:mx-4 mt-2 xl:mt-4">
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="wildberries"
|
value="wildberries"
|
||||||
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-2 text-xs"
|
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 xl:gap-2 text-[10px] xl:text-xs"
|
||||||
>
|
>
|
||||||
<div className="w-3 h-3 bg-purple-500 rounded-sm flex items-center justify-center">
|
<div className="w-2.5 h-2.5 xl:w-3 xl:h-3 bg-purple-500 rounded-sm flex items-center justify-center">
|
||||||
<span className="text-white text-[8px] font-bold">W</span>
|
<span className="text-white text-[6px] xl:text-[8px] font-bold">
|
||||||
|
W
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
Wildberries
|
<span className="hidden sm:inline">Wildberries</span>
|
||||||
|
<span className="sm:hidden">WB</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="ozon"
|
value="ozon"
|
||||||
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-2 text-xs"
|
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 flex items-center gap-1 xl:gap-2 text-[10px] xl:text-xs"
|
||||||
>
|
>
|
||||||
<div className="w-3 h-3 bg-blue-500 rounded-sm flex items-center justify-center">
|
<div className="w-2.5 h-2.5 xl:w-3 xl:h-3 bg-blue-500 rounded-sm flex items-center justify-center">
|
||||||
<span className="text-white text-[8px] font-bold">O</span>
|
<span className="text-white text-[6px] xl:text-[8px] font-bold">
|
||||||
|
O
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
Ozon
|
<span className="hidden sm:inline">Ozon</span>
|
||||||
|
<span className="sm:hidden">OZ</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ import {
|
|||||||
AlertCircle,
|
AlertCircle,
|
||||||
Eye,
|
Eye,
|
||||||
Calendar,
|
Calendar,
|
||||||
|
Package2,
|
||||||
|
Box,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
// Мок данные для поставок на Ozon
|
// Мок данные для поставок на Ozon
|
||||||
@ -143,60 +145,62 @@ export function OzonSuppliesTab() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col space-y-4 p-4">
|
<div className="h-full flex flex-col space-y-2 xl:space-y-4 p-2 xl:p-4">
|
||||||
{/* Статистика с кнопкой */}
|
{/* Статистика с кнопкой */}
|
||||||
<div className="flex items-center justify-between gap-4">
|
<div className="flex flex-col xl:flex-row xl:items-center xl:justify-between gap-3 xl:gap-4">
|
||||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3 flex-1">
|
<div className="grid grid-cols-2 xl:grid-cols-4 gap-2 xl:gap-3 flex-1">
|
||||||
<Card className="glass-card p-3 h-[60px]">
|
<Card className="glass-card p-2 xl:p-3 h-[50px] xl:h-[60px]">
|
||||||
<div className="flex items-center space-x-2 h-full">
|
<div className="flex items-center space-x-1.5 xl:space-x-2 h-full">
|
||||||
<div className="p-1.5 bg-blue-500/20 rounded">
|
<div className="p-1 xl:p-1.5 bg-blue-500/20 rounded">
|
||||||
<Package className="h-3 w-3 text-blue-400" />
|
<Package className="h-2.5 w-2.5 xl:h-3 xl:w-3 text-blue-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-white/60 text-xs">Поставок</p>
|
<p className="text-white/60 text-[10px] xl:text-xs">Поставок</p>
|
||||||
<p className="text-lg font-bold text-white">
|
<p className="text-sm xl:text-lg font-bold text-white">
|
||||||
{filteredSupplies.length}
|
{filteredSupplies.length}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="glass-card p-3 h-[60px]">
|
<Card className="glass-card p-2 xl:p-3 h-[50px] xl:h-[60px]">
|
||||||
<div className="flex items-center space-x-2 h-full">
|
<div className="flex items-center space-x-1.5 xl:space-x-2 h-full">
|
||||||
<div className="p-1.5 bg-green-500/20 rounded">
|
<div className="p-1 xl:p-1.5 bg-green-500/20 rounded">
|
||||||
<TrendingUp className="h-3 w-3 text-green-400" />
|
<TrendingUp className="h-2.5 w-2.5 xl:h-3 xl:w-3 text-green-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="min-w-0 flex-1">
|
||||||
<p className="text-white/60 text-xs">Стоимость</p>
|
<p className="text-white/60 text-[10px] xl:text-xs">
|
||||||
<p className="text-lg font-bold text-white">
|
Стоимость
|
||||||
|
</p>
|
||||||
|
<p className="text-sm xl:text-lg font-bold text-white truncate">
|
||||||
{formatCurrency(getTotalValue())}
|
{formatCurrency(getTotalValue())}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="glass-card p-3 h-[60px]">
|
<Card className="glass-card p-2 xl:p-3 h-[50px] xl:h-[60px]">
|
||||||
<div className="flex items-center space-x-2 h-full">
|
<div className="flex items-center space-x-1.5 xl:space-x-2 h-full">
|
||||||
<div className="p-1.5 bg-purple-500/20 rounded">
|
<div className="p-1 xl:p-1.5 bg-purple-500/20 rounded">
|
||||||
<AlertCircle className="h-3 w-3 text-purple-400" />
|
<Package2 className="h-2.5 w-2.5 xl:h-3 xl:w-3 text-purple-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-white/60 text-xs">Товаров</p>
|
<p className="text-white/60 text-[10px] xl:text-xs">Товаров</p>
|
||||||
<p className="text-lg font-bold text-white">
|
<p className="text-sm xl:text-lg font-bold text-white">
|
||||||
{getTotalItems()}
|
{getTotalItems()}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="glass-card p-3 h-[60px]">
|
<Card className="glass-card p-2 xl:p-3 h-[50px] xl:h-[60px]">
|
||||||
<div className="flex items-center space-x-2 h-full">
|
<div className="flex items-center space-x-1.5 xl:space-x-2 h-full">
|
||||||
<div className="p-1.5 bg-orange-500/20 rounded">
|
<div className="p-1 xl:p-1.5 bg-orange-500/20 rounded">
|
||||||
<Package className="h-3 w-3 text-orange-400" />
|
<Box className="h-2.5 w-2.5 xl:h-3 xl:w-3 text-orange-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-white/60 text-xs">Коробок</p>
|
<p className="text-white/60 text-[10px] xl:text-xs">Коробок</p>
|
||||||
<p className="text-lg font-bold text-white">
|
<p className="text-sm xl:text-lg font-bold text-white">
|
||||||
{getTotalBoxes()}
|
{getTotalBoxes()}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -206,46 +210,47 @@ export function OzonSuppliesTab() {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
className="bg-gradient-to-r from-blue-500 to-indigo-500 hover:from-blue-600 hover:to-indigo-600 text-white text-sm px-6 h-[60px] whitespace-nowrap"
|
className="bg-gradient-to-r from-blue-500 to-cyan-500 hover:from-blue-600 hover:to-cyan-600 text-white text-xs xl:text-sm px-3 xl:px-6 h-[50px] xl:h-[60px] whitespace-nowrap w-full xl:w-auto"
|
||||||
>
|
>
|
||||||
<Plus className="h-4 w-4 mr-2" />
|
<Plus className="h-3 w-3 xl:h-4 xl:w-4 mr-1 xl:mr-2" />
|
||||||
Создать поставку
|
<span className="hidden sm:inline">Создать поставку</span>
|
||||||
|
<span className="sm:hidden">Создать</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Фильтры */}
|
{/* Фильтры */}
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-2 xl:gap-3">
|
||||||
<div className="relative flex-1 max-w-md">
|
<div className="relative flex-1 max-w-md">
|
||||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-white/40" />
|
<Search className="absolute left-2 xl:left-3 top-1/2 transform -translate-y-1/2 h-3 w-3 xl:h-4 xl:w-4 text-white/40" />
|
||||||
<Input
|
<Input
|
||||||
placeholder="Поиск по ID поставки, складу, товарам..."
|
placeholder="Поиск по ID поставки..."
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
className="glass-input pl-10 text-white placeholder:text-white/40"
|
className="glass-input pl-8 xl:pl-10 text-white placeholder:text-white/40 text-xs xl:text-sm h-8 xl:h-auto"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
value={statusFilter}
|
value={statusFilter}
|
||||||
onChange={(e) => setStatusFilter(e.target.value)}
|
onChange={(e) => setStatusFilter(e.target.value)}
|
||||||
className="glass-input text-white text-sm px-3 py-2 rounded-lg bg-white/5 border border-white/10"
|
className="glass-input text-white text-xs xl:text-sm px-2 xl:px-3 py-1.5 xl:py-2 rounded-lg bg-white/5 border border-white/10 h-8 xl:h-auto"
|
||||||
>
|
>
|
||||||
<option value="all">Все статусы</option>
|
<option value="all">Все статусы</option>
|
||||||
<option value="awaiting_packaging">Ожидает упаковки</option>
|
<option value="created">Создана</option>
|
||||||
<option value="sent_to_delivery">Отправлена</option>
|
<option value="confirmed">Подтверждена</option>
|
||||||
|
<option value="in-transit">В пути</option>
|
||||||
<option value="delivered">Доставлена</option>
|
<option value="delivered">Доставлена</option>
|
||||||
<option value="cancelled">Отменена</option>
|
<option value="accepted">Принята</option>
|
||||||
<option value="arbitration">Арбитраж</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Список поставок */}
|
{/* Список поставок */}
|
||||||
<div className="flex-1 overflow-hidden">
|
<div className="flex-1 overflow-hidden">
|
||||||
<div className="h-full overflow-y-auto space-y-3">
|
<div className="h-full overflow-y-auto space-y-2 xl:space-y-3">
|
||||||
{filteredSupplies.map((supply) => (
|
{filteredSupplies.map((supply) => (
|
||||||
<Card
|
<Card
|
||||||
key={supply.id}
|
key={supply.id}
|
||||||
className="glass-card p-4 hover:bg-white/10 transition-colors"
|
className="glass-card p-2 xl:p-4 hover:bg-white/10 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
|
@ -13,6 +13,8 @@ import {
|
|||||||
AlertCircle,
|
AlertCircle,
|
||||||
Eye,
|
Eye,
|
||||||
Calendar,
|
Calendar,
|
||||||
|
Package2,
|
||||||
|
Box,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
// Мок данные для поставок на Wildberries
|
// Мок данные для поставок на Wildberries
|
||||||
@ -139,60 +141,62 @@ export function WildberriesSuppliesTab() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col space-y-4 p-4">
|
<div className="h-full flex flex-col space-y-2 xl:space-y-4 p-2 xl:p-4">
|
||||||
{/* Статистика с кнопкой */}
|
{/* Статистика с кнопкой */}
|
||||||
<div className="flex items-center justify-between gap-4">
|
<div className="flex flex-col xl:flex-row xl:items-center xl:justify-between gap-3 xl:gap-4">
|
||||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3 flex-1">
|
<div className="grid grid-cols-2 xl:grid-cols-4 gap-2 xl:gap-3 flex-1">
|
||||||
<Card className="glass-card p-3 h-[60px]">
|
<Card className="glass-card p-2 xl:p-3 h-[50px] xl:h-[60px]">
|
||||||
<div className="flex items-center space-x-2 h-full">
|
<div className="flex items-center space-x-1.5 xl:space-x-2 h-full">
|
||||||
<div className="p-1.5 bg-purple-500/20 rounded">
|
<div className="p-1 xl:p-1.5 bg-purple-500/20 rounded">
|
||||||
<Package className="h-3 w-3 text-purple-400" />
|
<Package className="h-2.5 w-2.5 xl:h-3 xl:w-3 text-purple-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-white/60 text-xs">Поставок</p>
|
<p className="text-white/60 text-[10px] xl:text-xs">Поставок</p>
|
||||||
<p className="text-lg font-bold text-white">
|
<p className="text-sm xl:text-lg font-bold text-white">
|
||||||
{filteredSupplies.length}
|
{filteredSupplies.length}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="glass-card p-3 h-[60px]">
|
<Card className="glass-card p-2 xl:p-3 h-[50px] xl:h-[60px]">
|
||||||
<div className="flex items-center space-x-2 h-full">
|
<div className="flex items-center space-x-1.5 xl:space-x-2 h-full">
|
||||||
<div className="p-1.5 bg-green-500/20 rounded">
|
<div className="p-1 xl:p-1.5 bg-green-500/20 rounded">
|
||||||
<TrendingUp className="h-3 w-3 text-green-400" />
|
<TrendingUp className="h-2.5 w-2.5 xl:h-3 xl:w-3 text-green-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="min-w-0 flex-1">
|
||||||
<p className="text-white/60 text-xs">Стоимость</p>
|
<p className="text-white/60 text-[10px] xl:text-xs">
|
||||||
<p className="text-lg font-bold text-white">
|
Стоимость
|
||||||
|
</p>
|
||||||
|
<p className="text-sm xl:text-lg font-bold text-white truncate">
|
||||||
{formatCurrency(getTotalValue())}
|
{formatCurrency(getTotalValue())}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="glass-card p-3 h-[60px]">
|
<Card className="glass-card p-2 xl:p-3 h-[50px] xl:h-[60px]">
|
||||||
<div className="flex items-center space-x-2 h-full">
|
<div className="flex items-center space-x-1.5 xl:space-x-2 h-full">
|
||||||
<div className="p-1.5 bg-blue-500/20 rounded">
|
<div className="p-1 xl:p-1.5 bg-blue-500/20 rounded">
|
||||||
<AlertCircle className="h-3 w-3 text-blue-400" />
|
<Package2 className="h-2.5 w-2.5 xl:h-3 xl:w-3 text-blue-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-white/60 text-xs">Товаров</p>
|
<p className="text-white/60 text-[10px] xl:text-xs">Товаров</p>
|
||||||
<p className="text-lg font-bold text-white">
|
<p className="text-sm xl:text-lg font-bold text-white">
|
||||||
{getTotalItems()}
|
{getTotalItems()}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="glass-card p-3 h-[60px]">
|
<Card className="glass-card p-2 xl:p-3 h-[50px] xl:h-[60px]">
|
||||||
<div className="flex items-center space-x-2 h-full">
|
<div className="flex items-center space-x-1.5 xl:space-x-2 h-full">
|
||||||
<div className="p-1.5 bg-orange-500/20 rounded">
|
<div className="p-1 xl:p-1.5 bg-orange-500/20 rounded">
|
||||||
<Package className="h-3 w-3 text-orange-400" />
|
<Box className="h-2.5 w-2.5 xl:h-3 xl:w-3 text-orange-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-white/60 text-xs">Коробок</p>
|
<p className="text-white/60 text-[10px] xl:text-xs">Коробок</p>
|
||||||
<p className="text-lg font-bold text-white">
|
<p className="text-sm xl:text-lg font-bold text-white">
|
||||||
{getTotalBoxes()}
|
{getTotalBoxes()}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -202,46 +206,47 @@ export function WildberriesSuppliesTab() {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
className="bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white text-sm px-6 h-[60px] whitespace-nowrap"
|
className="bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white text-xs xl:text-sm px-3 xl:px-6 h-[50px] xl:h-[60px] whitespace-nowrap w-full xl:w-auto"
|
||||||
>
|
>
|
||||||
<Plus className="h-4 w-4 mr-2" />
|
<Plus className="h-3 w-3 xl:h-4 xl:w-4 mr-1 xl:mr-2" />
|
||||||
Создать поставку
|
<span className="hidden sm:inline">Создать поставку</span>
|
||||||
|
<span className="sm:hidden">Создать</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Фильтры */}
|
{/* Фильтры */}
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-2 xl:gap-3">
|
||||||
<div className="relative flex-1 max-w-md">
|
<div className="relative flex-1 max-w-md">
|
||||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-white/40" />
|
<Search className="absolute left-2 xl:left-3 top-1/2 transform -translate-y-1/2 h-3 w-3 xl:h-4 xl:w-4 text-white/40" />
|
||||||
<Input
|
<Input
|
||||||
placeholder="Поиск по ID поставки, складу, товарам..."
|
placeholder="Поиск по ID поставки..."
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
className="glass-input pl-10 text-white placeholder:text-white/40"
|
className="glass-input pl-8 xl:pl-10 text-white placeholder:text-white/40 text-xs xl:text-sm h-8 xl:h-auto"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
value={statusFilter}
|
value={statusFilter}
|
||||||
onChange={(e) => setStatusFilter(e.target.value)}
|
onChange={(e) => setStatusFilter(e.target.value)}
|
||||||
className="glass-input text-white text-sm px-3 py-2 rounded-lg bg-white/5 border border-white/10"
|
className="glass-input text-white text-xs xl:text-sm px-2 xl:px-3 py-1.5 xl:py-2 rounded-lg bg-white/5 border border-white/10 h-8 xl:h-auto"
|
||||||
>
|
>
|
||||||
<option value="all">Все статусы</option>
|
<option value="all">Все статусы</option>
|
||||||
<option value="created">Создана</option>
|
<option value="created">Создана</option>
|
||||||
<option value="confirmed">Подтверждена</option>
|
<option value="confirmed">Подтверждена</option>
|
||||||
<option value="shipped">Отправлена</option>
|
<option value="in-transit">В пути</option>
|
||||||
<option value="delivered">Доставлена</option>
|
<option value="delivered">Доставлена</option>
|
||||||
<option value="cancelled">Отменена</option>
|
<option value="accepted">Принята</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Список поставок */}
|
{/* Список поставок */}
|
||||||
<div className="flex-1 overflow-hidden">
|
<div className="flex-1 overflow-hidden">
|
||||||
<div className="h-full overflow-y-auto space-y-3">
|
<div className="h-full overflow-y-auto space-y-2 xl:space-y-3">
|
||||||
{filteredSupplies.map((supply) => (
|
{filteredSupplies.map((supply) => (
|
||||||
<Card
|
<Card
|
||||||
key={supply.id}
|
key={supply.id}
|
||||||
className="glass-card p-4 hover:bg-white/10 transition-colors"
|
className="glass-card p-2 xl:p-4 hover:bg-white/10 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
|
@ -20,6 +20,8 @@ import {
|
|||||||
ArrowUpDown,
|
ArrowUpDown,
|
||||||
Store,
|
Store,
|
||||||
Package2,
|
Package2,
|
||||||
|
Eye,
|
||||||
|
EyeOff,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
// Типы данных
|
// Типы данных
|
||||||
@ -57,6 +59,7 @@ export function FulfillmentWarehouseDashboard() {
|
|||||||
const [sortField, setSortField] = useState<keyof StoreData>("name");
|
const [sortField, setSortField] = useState<keyof StoreData>("name");
|
||||||
const [sortOrder, setSortOrder] = useState<"asc" | "desc">("asc");
|
const [sortOrder, setSortOrder] = useState<"asc" | "desc">("asc");
|
||||||
const [expandedStores, setExpandedStores] = useState<Set<string>>(new Set());
|
const [expandedStores, setExpandedStores] = useState<Set<string>>(new Set());
|
||||||
|
const [showAdditionalValues, setShowAdditionalValues] = useState(true);
|
||||||
|
|
||||||
// Мок данные для статистики
|
// Мок данные для статистики
|
||||||
const warehouseStats: WarehouseStats = {
|
const warehouseStats: WarehouseStats = {
|
||||||
@ -324,6 +327,26 @@ export function FulfillmentWarehouseDashboard() {
|
|||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{field === "pvzReturns" && (
|
||||||
|
<button
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setShowAdditionalValues(!showAdditionalValues);
|
||||||
|
}}
|
||||||
|
className="p-1 rounded hover:bg-orange-500/20 transition-colors border border-orange-500/30 bg-orange-500/10 ml-2"
|
||||||
|
title={
|
||||||
|
showAdditionalValues
|
||||||
|
? "Скрыть дополнительные значения"
|
||||||
|
: "Показать дополнительные значения"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{showAdditionalValues ? (
|
||||||
|
<Eye className="h-3 w-3 text-orange-400 hover:text-orange-300" />
|
||||||
|
) : (
|
||||||
|
<EyeOff className="h-3 w-3 text-orange-400 hover:text-orange-300" />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -397,10 +420,30 @@ export function FulfillmentWarehouseDashboard() {
|
|||||||
className="p-4 border-b border-white/10 flex-shrink-0"
|
className="p-4 border-b border-white/10 flex-shrink-0"
|
||||||
style={{ maxHeight: "10vh" }}
|
style={{ maxHeight: "10vh" }}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between mb-3">
|
<div className="flex items-center justify-between">
|
||||||
<h2 className="text-base font-semibold text-white">
|
<h2 className="text-base font-semibold text-white">
|
||||||
Детализация по магазинам
|
Детализация по магазинам
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
|
{/* Компактный поиск */}
|
||||||
|
<div className="relative mx-2.5 flex-1 max-w-xs">
|
||||||
|
<Search className="absolute left-2.5 top-1/2 transform -translate-y-1/2 h-3.5 w-3.5 text-white/40" />
|
||||||
|
<div className="flex space-x-2">
|
||||||
|
<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 flex-1"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
className="h-8 px-2 bg-blue-500/20 hover:bg-blue-500/30 text-blue-300 border border-blue-500/30 text-xs"
|
||||||
|
>
|
||||||
|
Поиск
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Badge
|
<Badge
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
className="bg-blue-500/20 text-blue-300 text-xs"
|
className="bg-blue-500/20 text-blue-300 text-xs"
|
||||||
@ -408,17 +451,6 @@ export function FulfillmentWarehouseDashboard() {
|
|||||||
{filteredAndSortedStores.length} магазинов
|
{filteredAndSortedStores.length} магазинов
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</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>
|
||||||
|
|
||||||
{/* Фиксированные заголовки таблицы */}
|
{/* Фиксированные заголовки таблицы */}
|
||||||
@ -475,26 +507,28 @@ export function FulfillmentWarehouseDashboard() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-end space-x-1">
|
{showAdditionalValues && (
|
||||||
{/* Положительное изменение - всегда зеленое */}
|
<div className="flex items-center justify-end space-x-1">
|
||||||
<div className="flex items-center space-x-0.5">
|
{/* Положительное изменение - всегда зеленое */}
|
||||||
<span className="text-[9px] font-bold text-green-400">
|
<div className="flex items-center space-x-0.5">
|
||||||
+{Math.abs(Math.floor(totals.productsChange * 0.6))}
|
<span className="text-[9px] font-bold text-green-400">
|
||||||
</span>
|
+{Math.abs(Math.floor(totals.productsChange * 0.6))}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Отрицательное изменение - всегда красное */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-red-400">
|
||||||
|
-{Math.abs(Math.floor(totals.productsChange * 0.4))}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Результирующее изменение */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-white">
|
||||||
|
{Math.abs(totals.productsChange)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Отрицательное изменение - всегда красное */}
|
)}
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-red-400">
|
|
||||||
-{Math.abs(Math.floor(totals.productsChange * 0.4))}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/* Результирующее изменение */}
|
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-white">
|
|
||||||
{Math.abs(totals.productsChange)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="px-3 py-2 text-xs font-bold text-white">
|
<div className="px-3 py-2 text-xs font-bold text-white">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
@ -517,26 +551,28 @@ export function FulfillmentWarehouseDashboard() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-end space-x-1">
|
{showAdditionalValues && (
|
||||||
{/* Положительное изменение - всегда зеленое */}
|
<div className="flex items-center justify-end space-x-1">
|
||||||
<div className="flex items-center space-x-0.5">
|
{/* Положительное изменение - всегда зеленое */}
|
||||||
<span className="text-[9px] font-bold text-green-400">
|
<div className="flex items-center space-x-0.5">
|
||||||
+{Math.abs(Math.floor(totals.goodsChange * 0.6))}
|
<span className="text-[9px] font-bold text-green-400">
|
||||||
</span>
|
+{Math.abs(Math.floor(totals.goodsChange * 0.6))}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Отрицательное изменение - всегда красное */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-red-400">
|
||||||
|
-{Math.abs(Math.floor(totals.goodsChange * 0.4))}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Результирующее изменение */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-white">
|
||||||
|
{Math.abs(totals.goodsChange)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Отрицательное изменение - всегда красное */}
|
)}
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-red-400">
|
|
||||||
-{Math.abs(Math.floor(totals.goodsChange * 0.4))}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/* Результирующее изменение */}
|
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-white">
|
|
||||||
{Math.abs(totals.goodsChange)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="px-3 py-2 text-xs font-bold text-white">
|
<div className="px-3 py-2 text-xs font-bold text-white">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
@ -562,26 +598,28 @@ export function FulfillmentWarehouseDashboard() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-end space-x-1">
|
{showAdditionalValues && (
|
||||||
{/* Положительное изменение - всегда зеленое */}
|
<div className="flex items-center justify-end space-x-1">
|
||||||
<div className="flex items-center space-x-0.5">
|
{/* Положительное изменение - всегда зеленое */}
|
||||||
<span className="text-[9px] font-bold text-green-400">
|
<div className="flex items-center space-x-0.5">
|
||||||
+{Math.abs(Math.floor(totals.defectsChange * 0.6))}
|
<span className="text-[9px] font-bold text-green-400">
|
||||||
</span>
|
+{Math.abs(Math.floor(totals.defectsChange * 0.6))}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Отрицательное изменение - всегда красное */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-red-400">
|
||||||
|
-{Math.abs(Math.floor(totals.defectsChange * 0.4))}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Результирующее изменение */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-white">
|
||||||
|
{Math.abs(totals.defectsChange)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Отрицательное изменение - всегда красное */}
|
)}
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-red-400">
|
|
||||||
-{Math.abs(Math.floor(totals.defectsChange * 0.4))}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/* Результирующее изменение */}
|
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-white">
|
|
||||||
{Math.abs(totals.defectsChange)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="px-3 py-2 text-xs font-bold text-white">
|
<div className="px-3 py-2 text-xs font-bold text-white">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
@ -608,32 +646,34 @@ export function FulfillmentWarehouseDashboard() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-end space-x-1">
|
{showAdditionalValues && (
|
||||||
{/* Положительное изменение - всегда зеленое */}
|
<div className="flex items-center justify-end space-x-1">
|
||||||
<div className="flex items-center space-x-0.5">
|
{/* Положительное изменение - всегда зеленое */}
|
||||||
<span className="text-[9px] font-bold text-green-400">
|
<div className="flex items-center space-x-0.5">
|
||||||
+
|
<span className="text-[9px] font-bold text-green-400">
|
||||||
{Math.abs(
|
+
|
||||||
Math.floor(totals.sellerSuppliesChange * 0.6)
|
{Math.abs(
|
||||||
)}
|
Math.floor(totals.sellerSuppliesChange * 0.6)
|
||||||
</span>
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Отрицательное изменение - всегда красное */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-red-400">
|
||||||
|
-
|
||||||
|
{Math.abs(
|
||||||
|
Math.floor(totals.sellerSuppliesChange * 0.4)
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Результирующее изменение */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-white">
|
||||||
|
{Math.abs(totals.sellerSuppliesChange)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Отрицательное изменение - всегда красное */}
|
)}
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-red-400">
|
|
||||||
-
|
|
||||||
{Math.abs(
|
|
||||||
Math.floor(totals.sellerSuppliesChange * 0.4)
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/* Результирующее изменение */}
|
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-white">
|
|
||||||
{Math.abs(totals.sellerSuppliesChange)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="px-3 py-2 text-xs font-bold text-white">
|
<div className="px-3 py-2 text-xs font-bold text-white">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
@ -659,26 +699,28 @@ export function FulfillmentWarehouseDashboard() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-end space-x-1">
|
{showAdditionalValues && (
|
||||||
{/* Положительное изменение - всегда зеленое */}
|
<div className="flex items-center justify-end space-x-1">
|
||||||
<div className="flex items-center space-x-0.5">
|
{/* Положительное изменение - всегда зеленое */}
|
||||||
<span className="text-[9px] font-bold text-green-400">
|
<div className="flex items-center space-x-0.5">
|
||||||
+{Math.abs(Math.floor(totals.pvzReturnsChange * 0.6))}
|
<span className="text-[9px] font-bold text-green-400">
|
||||||
</span>
|
+{Math.abs(Math.floor(totals.pvzReturnsChange * 0.6))}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Отрицательное изменение - всегда красное */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-red-400">
|
||||||
|
-{Math.abs(Math.floor(totals.pvzReturnsChange * 0.4))}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Результирующее изменение */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-white">
|
||||||
|
{Math.abs(totals.pvzReturnsChange)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Отрицательное изменение - всегда красное */}
|
)}
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-red-400">
|
|
||||||
-{Math.abs(Math.floor(totals.pvzReturnsChange * 0.4))}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/* Результирующее изменение */}
|
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-white">
|
|
||||||
{Math.abs(totals.pvzReturnsChange)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -716,28 +758,34 @@ export function FulfillmentWarehouseDashboard() {
|
|||||||
<div className="text-white font-semibold text-sm">
|
<div className="text-white font-semibold text-sm">
|
||||||
{formatNumber(store.products)}
|
{formatNumber(store.products)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-1">
|
{showAdditionalValues && (
|
||||||
{/* Положительное изменение - всегда зеленое */}
|
<div className="flex items-center space-x-1">
|
||||||
<div className="flex items-center space-x-0.5">
|
{/* Положительное изменение - всегда зеленое */}
|
||||||
<span className="text-[9px] font-bold text-green-400">
|
<div className="flex items-center space-x-0.5">
|
||||||
+
|
<span className="text-[9px] font-bold text-green-400">
|
||||||
{Math.abs(Math.floor(store.productsChange * 0.6))}
|
+
|
||||||
</span>
|
{Math.abs(
|
||||||
|
Math.floor(store.productsChange * 0.6)
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Отрицательное изменение - всегда красное */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-red-400">
|
||||||
|
-
|
||||||
|
{Math.abs(
|
||||||
|
Math.floor(store.productsChange * 0.4)
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Результирующее изменение */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-white">
|
||||||
|
{Math.abs(store.productsChange)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Отрицательное изменение - всегда красное */}
|
)}
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-red-400">
|
|
||||||
-
|
|
||||||
{Math.abs(Math.floor(store.productsChange * 0.4))}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/* Результирующее изменение */}
|
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-white">
|
|
||||||
{Math.abs(store.productsChange)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -746,26 +794,28 @@ export function FulfillmentWarehouseDashboard() {
|
|||||||
<div className="text-white font-semibold text-sm">
|
<div className="text-white font-semibold text-sm">
|
||||||
{formatNumber(store.goods)}
|
{formatNumber(store.goods)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-1">
|
{showAdditionalValues && (
|
||||||
{/* Положительное изменение - всегда зеленое */}
|
<div className="flex items-center space-x-1">
|
||||||
<div className="flex items-center space-x-0.5">
|
{/* Положительное изменение - всегда зеленое */}
|
||||||
<span className="text-[9px] font-bold text-green-400">
|
<div className="flex items-center space-x-0.5">
|
||||||
+{Math.abs(Math.floor(store.goodsChange * 0.6))}
|
<span className="text-[9px] font-bold text-green-400">
|
||||||
</span>
|
+{Math.abs(Math.floor(store.goodsChange * 0.6))}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Отрицательное изменение - всегда красное */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-red-400">
|
||||||
|
-{Math.abs(Math.floor(store.goodsChange * 0.4))}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Результирующее изменение */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-white">
|
||||||
|
{Math.abs(store.goodsChange)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Отрицательное изменение - всегда красное */}
|
)}
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-red-400">
|
|
||||||
-{Math.abs(Math.floor(store.goodsChange * 0.4))}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/* Результирующее изменение */}
|
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-white">
|
|
||||||
{Math.abs(store.goodsChange)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -774,26 +824,34 @@ export function FulfillmentWarehouseDashboard() {
|
|||||||
<div className="text-white font-semibold text-sm">
|
<div className="text-white font-semibold text-sm">
|
||||||
{formatNumber(store.defects)}
|
{formatNumber(store.defects)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-1">
|
{showAdditionalValues && (
|
||||||
{/* Положительное изменение - всегда зеленое */}
|
<div className="flex items-center space-x-1">
|
||||||
<div className="flex items-center space-x-0.5">
|
{/* Положительное изменение - всегда зеленое */}
|
||||||
<span className="text-[9px] font-bold text-green-400">
|
<div className="flex items-center space-x-0.5">
|
||||||
+{Math.abs(Math.floor(store.defectsChange * 0.6))}
|
<span className="text-[9px] font-bold text-green-400">
|
||||||
</span>
|
+
|
||||||
|
{Math.abs(
|
||||||
|
Math.floor(store.defectsChange * 0.6)
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Отрицательное изменение - всегда красное */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-red-400">
|
||||||
|
-
|
||||||
|
{Math.abs(
|
||||||
|
Math.floor(store.defectsChange * 0.4)
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Результирующее изменение */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-white">
|
||||||
|
{Math.abs(store.defectsChange)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Отрицательное изменение - всегда красное */}
|
)}
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-red-400">
|
|
||||||
-{Math.abs(Math.floor(store.defectsChange * 0.4))}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/* Результирующее изменение */}
|
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-white">
|
|
||||||
{Math.abs(store.defectsChange)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -802,32 +860,34 @@ export function FulfillmentWarehouseDashboard() {
|
|||||||
<div className="text-white font-semibold text-sm">
|
<div className="text-white font-semibold text-sm">
|
||||||
{formatNumber(store.sellerSupplies)}
|
{formatNumber(store.sellerSupplies)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-1">
|
{showAdditionalValues && (
|
||||||
{/* Положительное изменение - всегда зеленое */}
|
<div className="flex items-center space-x-1">
|
||||||
<div className="flex items-center space-x-0.5">
|
{/* Положительное изменение - всегда зеленое */}
|
||||||
<span className="text-[9px] font-bold text-green-400">
|
<div className="flex items-center space-x-0.5">
|
||||||
+
|
<span className="text-[9px] font-bold text-green-400">
|
||||||
{Math.abs(
|
+
|
||||||
Math.floor(store.sellerSuppliesChange * 0.6)
|
{Math.abs(
|
||||||
)}
|
Math.floor(store.sellerSuppliesChange * 0.6)
|
||||||
</span>
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Отрицательное изменение - всегда красное */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-red-400">
|
||||||
|
-
|
||||||
|
{Math.abs(
|
||||||
|
Math.floor(store.sellerSuppliesChange * 0.4)
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Результирующее изменение */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-white">
|
||||||
|
{Math.abs(store.sellerSuppliesChange)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Отрицательное изменение - всегда красное */}
|
)}
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-red-400">
|
|
||||||
-
|
|
||||||
{Math.abs(
|
|
||||||
Math.floor(store.sellerSuppliesChange * 0.4)
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/* Результирующее изменение */}
|
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-white">
|
|
||||||
{Math.abs(store.sellerSuppliesChange)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -836,32 +896,34 @@ export function FulfillmentWarehouseDashboard() {
|
|||||||
<div className="text-white font-semibold text-sm">
|
<div className="text-white font-semibold text-sm">
|
||||||
{formatNumber(store.pvzReturns)}
|
{formatNumber(store.pvzReturns)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-1">
|
{showAdditionalValues && (
|
||||||
{/* Положительное изменение - всегда зеленое */}
|
<div className="flex items-center space-x-1">
|
||||||
<div className="flex items-center space-x-0.5">
|
{/* Положительное изменение - всегда зеленое */}
|
||||||
<span className="text-[9px] font-bold text-green-400">
|
<div className="flex items-center space-x-0.5">
|
||||||
+
|
<span className="text-[9px] font-bold text-green-400">
|
||||||
{Math.abs(
|
+
|
||||||
Math.floor(store.pvzReturnsChange * 0.6)
|
{Math.abs(
|
||||||
)}
|
Math.floor(store.pvzReturnsChange * 0.6)
|
||||||
</span>
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Отрицательное изменение - всегда красное */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-red-400">
|
||||||
|
-
|
||||||
|
{Math.abs(
|
||||||
|
Math.floor(store.pvzReturnsChange * 0.4)
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* Результирующее изменение */}
|
||||||
|
<div className="flex items-center space-x-0.5">
|
||||||
|
<span className="text-[9px] font-bold text-white">
|
||||||
|
{Math.abs(store.pvzReturnsChange)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Отрицательное изменение - всегда красное */}
|
)}
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-red-400">
|
|
||||||
-
|
|
||||||
{Math.abs(
|
|
||||||
Math.floor(store.pvzReturnsChange * 0.4)
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/* Результирующее изменение */}
|
|
||||||
<div className="flex items-center space-x-0.5">
|
|
||||||
<span className="text-[9px] font-bold text-white">
|
|
||||||
{Math.abs(store.pvzReturnsChange)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,13 +2,10 @@
|
|||||||
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Card } from "@/components/ui/card";
|
import { Card } from "@/components/ui/card";
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { StatsCard } from "../ui/stats-card";
|
import { StatsCard } from "../ui/stats-card";
|
||||||
import { StatsGrid } from "../ui/stats-grid";
|
import { StatsGrid } from "../ui/stats-grid";
|
||||||
import {
|
import {
|
||||||
ChevronDown,
|
|
||||||
ChevronRight,
|
|
||||||
Calendar,
|
Calendar,
|
||||||
Package,
|
Package,
|
||||||
MapPin,
|
MapPin,
|
||||||
@ -371,32 +368,42 @@ export function FulfillmentGoodsTab() {
|
|||||||
{/* Таблица поставок товаров ФФ */}
|
{/* Таблица поставок товаров ФФ */}
|
||||||
<Card className="bg-white/10 backdrop-blur border-white/20 overflow-hidden flex-1 flex flex-col">
|
<Card className="bg-white/10 backdrop-blur border-white/20 overflow-hidden flex-1 flex flex-col">
|
||||||
<div className="overflow-auto flex-1">
|
<div className="overflow-auto flex-1">
|
||||||
<table className="w-full">
|
<table className="w-full text-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="border-b border-white/20">
|
<tr className="border-b border-white/20">
|
||||||
<th className="text-left p-4 text-white font-semibold">№</th>
|
<th className="text-left p-2 text-white font-semibold text-sm">
|
||||||
<th className="text-left p-4 text-white font-semibold">
|
№
|
||||||
Дата поставки
|
|
||||||
</th>
|
</th>
|
||||||
<th className="text-left p-4 text-white font-semibold">
|
<th className="text-left p-2 text-white font-semibold text-sm">
|
||||||
Дата создания
|
<span className="hidden sm:inline">Дата поставки</span>
|
||||||
|
<span className="sm:hidden">Поставка</span>
|
||||||
</th>
|
</th>
|
||||||
<th className="text-left p-4 text-white font-semibold">План</th>
|
<th className="text-left p-2 text-white font-semibold text-sm hidden lg:table-cell">
|
||||||
<th className="text-left p-4 text-white font-semibold">Факт</th>
|
Создана
|
||||||
<th className="text-left p-4 text-white font-semibold">Брак</th>
|
|
||||||
<th className="text-left p-4 text-white font-semibold">
|
|
||||||
Цена товаров
|
|
||||||
</th>
|
</th>
|
||||||
<th className="text-left p-4 text-white font-semibold">
|
<th className="text-left p-2 text-white font-semibold text-sm">
|
||||||
Услуги ФФ
|
План
|
||||||
</th>
|
</th>
|
||||||
<th className="text-left p-4 text-white font-semibold">
|
<th className="text-left p-2 text-white font-semibold text-sm">
|
||||||
Логистика до ФФ
|
Факт
|
||||||
</th>
|
</th>
|
||||||
<th className="text-left p-4 text-white font-semibold">
|
<th className="text-left p-2 text-white font-semibold text-sm">
|
||||||
Итого сумма
|
Брак
|
||||||
</th>
|
</th>
|
||||||
<th className="text-left p-4 text-white font-semibold">
|
<th className="text-left p-2 text-white font-semibold text-sm">
|
||||||
|
<span className="hidden md:inline">Цена товаров</span>
|
||||||
|
<span className="md:hidden">Цена</span>
|
||||||
|
</th>
|
||||||
|
<th className="text-left p-2 text-white font-semibold text-sm hidden lg:table-cell">
|
||||||
|
ФФ
|
||||||
|
</th>
|
||||||
|
<th className="text-left p-2 text-white font-semibold text-sm hidden lg:table-cell">
|
||||||
|
Логистика
|
||||||
|
</th>
|
||||||
|
<th className="text-left p-2 text-white font-semibold text-sm">
|
||||||
|
Итого
|
||||||
|
</th>
|
||||||
|
<th className="text-left p-2 text-white font-semibold text-sm">
|
||||||
Статус
|
Статус
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -412,39 +419,37 @@ export function FulfillmentGoodsTab() {
|
|||||||
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-purple-500/10 cursor-pointer"
|
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-purple-500/10 cursor-pointer"
|
||||||
onClick={() => toggleSupplyExpansion(supply.id)}
|
onClick={() => toggleSupplyExpansion(supply.id)}
|
||||||
>
|
>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<div className="flex items-center space-x-2">
|
<span className="text-white font-normal text-sm">
|
||||||
<span className="text-white font-normal text-lg">
|
{supply.number}
|
||||||
{supply.number}
|
</span>
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-1">
|
||||||
<Calendar className="h-4 w-4 text-white/40" />
|
<Calendar className="h-3 w-3 text-white/40" />
|
||||||
<span className="text-white font-semibold">
|
<span className="text-white font-semibold text-sm">
|
||||||
{formatDate(supply.deliveryDate)}
|
{formatDate(supply.deliveryDate)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2 hidden lg:table-cell">
|
||||||
<span className="text-white/80">
|
<span className="text-white/80 text-sm">
|
||||||
{formatDate(supply.createdDate)}
|
{formatDate(supply.createdDate)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<span className="text-white font-semibold">
|
<span className="text-white font-semibold text-sm">
|
||||||
{supply.plannedTotal}
|
{supply.plannedTotal}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<span className="text-white font-semibold">
|
<span className="text-white font-semibold text-sm">
|
||||||
{supply.actualTotal}
|
{supply.actualTotal}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<span
|
<span
|
||||||
className={`font-semibold ${
|
className={`font-semibold text-sm ${
|
||||||
supply.defectTotal > 0
|
supply.defectTotal > 0
|
||||||
? "text-red-400"
|
? "text-red-400"
|
||||||
: "text-white"
|
: "text-white"
|
||||||
@ -453,30 +458,30 @@ export function FulfillmentGoodsTab() {
|
|||||||
{supply.defectTotal}
|
{supply.defectTotal}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<span className="text-green-400 font-semibold">
|
<span className="text-green-400 font-semibold text-sm">
|
||||||
{formatCurrency(supply.totalProductPrice)}
|
{formatCurrency(supply.totalProductPrice)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2 hidden lg:table-cell">
|
||||||
<span className="text-blue-400 font-semibold">
|
<span className="text-blue-400 font-semibold text-sm">
|
||||||
{formatCurrency(supply.totalFulfillmentPrice)}
|
{formatCurrency(supply.totalFulfillmentPrice)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2 hidden lg:table-cell">
|
||||||
<span className="text-purple-400 font-semibold">
|
<span className="text-purple-400 font-semibold text-sm">
|
||||||
{formatCurrency(supply.totalLogisticsPrice)}
|
{formatCurrency(supply.totalLogisticsPrice)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-1">
|
||||||
<DollarSign className="h-4 w-4 text-white/40" />
|
<DollarSign className="h-3 w-3 text-white/40" />
|
||||||
<span className="text-white font-bold text-lg">
|
<span className="text-white font-bold text-sm">
|
||||||
{formatCurrency(supply.grandTotal)}
|
{formatCurrency(supply.grandTotal)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">{getStatusBadge(supply.status)}</td>
|
<td className="p-2">{getStatusBadge(supply.status)}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{/* Развернутые уровни - аналогично оригинальному коду */}
|
{/* Развернутые уровни - аналогично оригинальному коду */}
|
||||||
@ -485,47 +490,39 @@ export function FulfillmentGoodsTab() {
|
|||||||
const isRouteExpanded = expandedRoutes.has(route.id);
|
const isRouteExpanded = expandedRoutes.has(route.id);
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={route.id}>
|
<React.Fragment key={route.id}>
|
||||||
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-blue-500/10">
|
<tr
|
||||||
<td className="p-4 pl-12">
|
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-blue-500/10 cursor-pointer"
|
||||||
|
onClick={() => toggleRouteExpansion(route.id)}
|
||||||
|
>
|
||||||
|
<td className="p-2 relative">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Button
|
<div className="w-1 h-1 rounded-full bg-blue-400 mr-1"></div>
|
||||||
variant="ghost"
|
<MapPin className="h-3 w-3 text-blue-400" />
|
||||||
size="sm"
|
<span className="text-white font-medium text-sm">
|
||||||
onClick={() =>
|
|
||||||
toggleRouteExpansion(route.id)
|
|
||||||
}
|
|
||||||
className="h-6 w-6 p-0 text-white/60 hover:text-white hover:bg-white/10"
|
|
||||||
>
|
|
||||||
{isRouteExpanded ? (
|
|
||||||
<ChevronDown className="h-4 w-4" />
|
|
||||||
) : (
|
|
||||||
<ChevronRight className="h-4 w-4" />
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
<MapPin className="h-4 w-4 text-blue-400" />
|
|
||||||
<span className="text-white font-medium">
|
|
||||||
Маршрут
|
Маршрут
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="absolute left-0 top-0 w-0.5 h-full bg-blue-400/30"></div>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4" colSpan={2}>
|
<td className="p-2" colSpan={1}>
|
||||||
<div className="text-white">
|
<div className="text-white">
|
||||||
<div className="flex items-center space-x-2 mb-1">
|
<div className="flex items-center space-x-2 mb-1">
|
||||||
<span className="font-medium">
|
<span className="font-medium text-sm">
|
||||||
{route.from}
|
{route.from}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-white/60">→</span>
|
<span className="text-white/60">→</span>
|
||||||
<span className="font-medium">
|
<span className="font-medium text-sm">
|
||||||
{route.to}
|
{route.to}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-white/60">
|
<div className="text-xs text-white/60 hidden sm:block">
|
||||||
{route.fromAddress} → {route.toAddress}
|
{route.fromAddress} → {route.toAddress}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2 hidden lg:table-cell"></td>
|
||||||
<span className="text-white/80">
|
<td className="p-2">
|
||||||
|
<span className="text-white/80 text-sm">
|
||||||
{route.wholesalers.reduce(
|
{route.wholesalers.reduce(
|
||||||
(sum, w) =>
|
(sum, w) =>
|
||||||
sum +
|
sum +
|
||||||
@ -537,8 +534,8 @@ export function FulfillmentGoodsTab() {
|
|||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<span className="text-white/80">
|
<span className="text-white/80 text-sm">
|
||||||
{route.wholesalers.reduce(
|
{route.wholesalers.reduce(
|
||||||
(sum, w) =>
|
(sum, w) =>
|
||||||
sum +
|
sum +
|
||||||
@ -550,8 +547,8 @@ export function FulfillmentGoodsTab() {
|
|||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<span className="text-white/80">
|
<span className="text-white/80 text-sm">
|
||||||
{route.wholesalers.reduce(
|
{route.wholesalers.reduce(
|
||||||
(sum, w) =>
|
(sum, w) =>
|
||||||
sum +
|
sum +
|
||||||
@ -563,29 +560,29 @@ export function FulfillmentGoodsTab() {
|
|||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<span className="text-green-400 font-medium">
|
<span className="text-green-400 font-medium text-sm">
|
||||||
{formatCurrency(route.totalProductPrice)}
|
{formatCurrency(route.totalProductPrice)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2 hidden lg:table-cell">
|
||||||
<span className="text-blue-400 font-medium">
|
<span className="text-blue-400 font-medium text-sm">
|
||||||
{formatCurrency(
|
{formatCurrency(
|
||||||
route.fulfillmentServicePrice
|
route.fulfillmentServicePrice
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2 hidden lg:table-cell">
|
||||||
<span className="text-purple-400 font-medium">
|
<span className="text-purple-400 font-medium text-sm">
|
||||||
{formatCurrency(route.logisticsPrice)}
|
{formatCurrency(route.logisticsPrice)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<span className="text-white font-semibold">
|
<span className="text-white font-semibold text-sm">
|
||||||
{formatCurrency(route.totalAmount)}
|
{formatCurrency(route.totalAmount)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4"></td>
|
<td className="p-2"></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{/* Остальные уровни развертывания аналогично */}
|
{/* Остальные уровни развертывания аналогично */}
|
||||||
@ -595,73 +592,66 @@ export function FulfillmentGoodsTab() {
|
|||||||
expandedWholesalers.has(wholesaler.id);
|
expandedWholesalers.has(wholesaler.id);
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={wholesaler.id}>
|
<React.Fragment key={wholesaler.id}>
|
||||||
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-green-500/10">
|
<tr
|
||||||
<td className="p-4 pl-20">
|
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-green-500/10 cursor-pointer"
|
||||||
|
onClick={() =>
|
||||||
|
toggleWholesalerExpansion(wholesaler.id)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<td className="p-2 relative">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Button
|
<div className="w-1 h-1 rounded-full bg-green-400 mr-1"></div>
|
||||||
variant="ghost"
|
<div className="w-1 h-1 rounded-full bg-green-400 mr-1"></div>
|
||||||
size="sm"
|
<Building2 className="h-3 w-3 text-green-400" />
|
||||||
onClick={() =>
|
<span className="text-white font-medium text-sm">
|
||||||
toggleWholesalerExpansion(
|
|
||||||
wholesaler.id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
className="h-6 w-6 p-0 text-white/60 hover:text-white hover:bg-white/10"
|
|
||||||
>
|
|
||||||
{isWholesalerExpanded ? (
|
|
||||||
<ChevronDown className="h-4 w-4" />
|
|
||||||
) : (
|
|
||||||
<ChevronRight className="h-4 w-4" />
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
<Building2 className="h-4 w-4 text-green-400" />
|
|
||||||
<span className="text-white font-medium">
|
|
||||||
Оптовик
|
Оптовик
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="absolute left-0 top-0 w-0.5 h-full bg-green-400/30"></div>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4" colSpan={2}>
|
<td className="p-2" colSpan={1}>
|
||||||
<div className="text-white">
|
<div className="text-white">
|
||||||
<div className="font-medium mb-1">
|
<div className="font-medium mb-1 text-sm">
|
||||||
{wholesaler.name}
|
{wholesaler.name}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-white/60 mb-1">
|
<div className="text-xs text-white/60 mb-1 hidden sm:block">
|
||||||
ИНН: {wholesaler.inn}
|
ИНН: {wholesaler.inn}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-white/60 mb-1">
|
<div className="text-xs text-white/60 mb-1 hidden lg:block">
|
||||||
{wholesaler.address}
|
{wholesaler.address}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-white/60">
|
<div className="text-xs text-white/60 hidden sm:block">
|
||||||
{wholesaler.contact}
|
{wholesaler.contact}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2 hidden lg:table-cell"></td>
|
||||||
<span className="text-white/80">
|
<td className="p-2">
|
||||||
|
<span className="text-white/80 text-sm">
|
||||||
{wholesaler.products.reduce(
|
{wholesaler.products.reduce(
|
||||||
(sum, p) => sum + p.plannedQty,
|
(sum, p) => sum + p.plannedQty,
|
||||||
0
|
0
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<span className="text-white/80">
|
<span className="text-white/80 text-sm">
|
||||||
{wholesaler.products.reduce(
|
{wholesaler.products.reduce(
|
||||||
(sum, p) => sum + p.actualQty,
|
(sum, p) => sum + p.actualQty,
|
||||||
0
|
0
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<span className="text-white/80">
|
<span className="text-white/80 text-sm">
|
||||||
{wholesaler.products.reduce(
|
{wholesaler.products.reduce(
|
||||||
(sum, p) => sum + p.defectQty,
|
(sum, p) => sum + p.defectQty,
|
||||||
0
|
0
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<span className="text-green-400 font-medium">
|
<span className="text-green-400 font-medium text-sm">
|
||||||
{formatCurrency(
|
{formatCurrency(
|
||||||
wholesaler.products.reduce(
|
wholesaler.products.reduce(
|
||||||
(sum, p) =>
|
(sum, p) =>
|
||||||
@ -671,9 +661,12 @@ export function FulfillmentGoodsTab() {
|
|||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4" colSpan={2}></td>
|
<td
|
||||||
<td className="p-4">
|
className="p-2 hidden lg:table-cell"
|
||||||
<span className="text-white font-semibold">
|
colSpan={2}
|
||||||
|
></td>
|
||||||
|
<td className="p-2">
|
||||||
|
<span className="text-white font-semibold text-sm">
|
||||||
{formatCurrency(
|
{formatCurrency(
|
||||||
wholesaler.totalAmount
|
wholesaler.totalAmount
|
||||||
)}
|
)}
|
||||||
@ -689,57 +682,53 @@ export function FulfillmentGoodsTab() {
|
|||||||
expandedProducts.has(product.id);
|
expandedProducts.has(product.id);
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={product.id}>
|
<React.Fragment key={product.id}>
|
||||||
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-yellow-500/10">
|
<tr
|
||||||
<td className="p-4 pl-28">
|
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-yellow-500/10 cursor-pointer"
|
||||||
|
onClick={() =>
|
||||||
|
toggleProductExpansion(
|
||||||
|
product.id
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<td className="p-2 relative">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Button
|
<div className="w-1 h-1 rounded-full bg-yellow-400 mr-1"></div>
|
||||||
variant="ghost"
|
<div className="w-1 h-1 rounded-full bg-yellow-400 mr-1"></div>
|
||||||
size="sm"
|
<div className="w-1 h-1 rounded-full bg-yellow-400 mr-1"></div>
|
||||||
onClick={() =>
|
<Package className="h-3 w-3 text-yellow-400" />
|
||||||
toggleProductExpansion(
|
<span className="text-white font-medium text-sm">
|
||||||
product.id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
className="h-6 w-6 p-0 text-white/60 hover:text-white hover:bg-white/10"
|
|
||||||
>
|
|
||||||
{isProductExpanded ? (
|
|
||||||
<ChevronDown className="h-4 w-4" />
|
|
||||||
) : (
|
|
||||||
<ChevronRight className="h-4 w-4" />
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
<Package className="h-4 w-4 text-yellow-400" />
|
|
||||||
<span className="text-white font-medium">
|
|
||||||
Товар
|
Товар
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="absolute left-0 top-0 w-0.5 h-full bg-yellow-400/30"></div>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4" colSpan={2}>
|
<td className="p-2" colSpan={1}>
|
||||||
<div className="text-white">
|
<div className="text-white">
|
||||||
<div className="font-medium mb-1">
|
<div className="font-medium mb-1 text-sm">
|
||||||
{product.name}
|
{product.name}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-white/60 mb-1">
|
<div className="text-xs text-white/60 mb-1 hidden sm:block">
|
||||||
Артикул: {product.sku}
|
Артикул: {product.sku}
|
||||||
</div>
|
</div>
|
||||||
<Badge className="bg-gray-500/20 text-gray-300 border-gray-500/30 border text-xs">
|
<Badge className="bg-gray-500/20 text-gray-300 border-gray-500/30 border text-xs hidden sm:inline-flex">
|
||||||
{product.category}
|
{product.category}
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2 hidden lg:table-cell"></td>
|
||||||
<span className="text-white font-semibold">
|
<td className="p-2">
|
||||||
|
<span className="text-white font-semibold text-sm">
|
||||||
{product.plannedQty}
|
{product.plannedQty}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<span className="text-white font-semibold">
|
<span className="text-white font-semibold text-sm">
|
||||||
{product.actualQty}
|
{product.actualQty}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<span
|
<span
|
||||||
className={`font-semibold ${
|
className={`font-semibold text-sm ${
|
||||||
product.defectQty > 0
|
product.defectQty > 0
|
||||||
? "text-red-400"
|
? "text-red-400"
|
||||||
: "text-white"
|
: "text-white"
|
||||||
@ -748,16 +737,16 @@ export function FulfillmentGoodsTab() {
|
|||||||
{product.defectQty}
|
{product.defectQty}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<div className="text-white">
|
<div className="text-white">
|
||||||
<div className="font-medium">
|
<div className="font-medium text-sm">
|
||||||
{formatCurrency(
|
{formatCurrency(
|
||||||
calculateProductTotal(
|
calculateProductTotal(
|
||||||
product
|
product
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-white/60">
|
<div className="text-xs text-white/60 hidden sm:block">
|
||||||
{formatCurrency(
|
{formatCurrency(
|
||||||
product.productPrice
|
product.productPrice
|
||||||
)}{" "}
|
)}{" "}
|
||||||
@ -765,15 +754,18 @@ export function FulfillmentGoodsTab() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4" colSpan={2}>
|
<td
|
||||||
|
className="p-2 hidden lg:table-cell"
|
||||||
|
colSpan={2}
|
||||||
|
>
|
||||||
{getEfficiencyBadge(
|
{getEfficiencyBadge(
|
||||||
product.plannedQty,
|
product.plannedQty,
|
||||||
product.actualQty,
|
product.actualQty,
|
||||||
product.defectQty
|
product.defectQty
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-2">
|
||||||
<span className="text-white font-semibold">
|
<span className="text-white font-semibold text-sm">
|
||||||
{formatCurrency(
|
{formatCurrency(
|
||||||
calculateProductTotal(
|
calculateProductTotal(
|
||||||
product
|
product
|
||||||
@ -781,7 +773,7 @@ export function FulfillmentGoodsTab() {
|
|||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4"></td>
|
<td className="p-2"></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{/* Параметры товара */}
|
{/* Параметры товара */}
|
||||||
@ -792,7 +784,7 @@ export function FulfillmentGoodsTab() {
|
|||||||
className="p-0"
|
className="p-0"
|
||||||
>
|
>
|
||||||
<div className="bg-white/5 border-t border-white/10">
|
<div className="bg-white/5 border-t border-white/10">
|
||||||
<div className="p-4 pl-36">
|
<div className="p-4">
|
||||||
<h4 className="text-white font-medium mb-3 flex items-center space-x-2">
|
<h4 className="text-white font-medium mb-3 flex items-center space-x-2">
|
||||||
<span className="text-xs text-white/60">
|
<span className="text-xs text-white/60">
|
||||||
📋 Параметры товара:
|
📋 Параметры товара:
|
||||||
|
@ -10,7 +10,9 @@ interface FulfillmentSuppliesTabProps {
|
|||||||
defaultSubTab?: string;
|
defaultSubTab?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FulfillmentSuppliesTab({ defaultSubTab }: FulfillmentSuppliesTabProps) {
|
export function FulfillmentSuppliesTab({
|
||||||
|
defaultSubTab,
|
||||||
|
}: FulfillmentSuppliesTabProps) {
|
||||||
const [activeSubTab, setActiveSubTab] = useState("goods");
|
const [activeSubTab, setActiveSubTab] = useState("goods");
|
||||||
|
|
||||||
// Устанавливаем активную подвкладку при получении defaultSubTab
|
// Устанавливаем активную подвкладку при получении defaultSubTab
|
||||||
@ -28,24 +30,25 @@ export function FulfillmentSuppliesTab({ defaultSubTab }: FulfillmentSuppliesTab
|
|||||||
className="w-full h-full flex flex-col overflow-hidden"
|
className="w-full h-full flex flex-col overflow-hidden"
|
||||||
>
|
>
|
||||||
{/* Подвкладки для ФФ */}
|
{/* Подвкладки для ФФ */}
|
||||||
<TabsList className="grid grid-cols-3 bg-white/5 backdrop-blur border-white/10 mb-4 w-fit">
|
<TabsList className="grid grid-cols-3 bg-white/5 backdrop-blur border-white/10 mb-2 w-fit text-sm">
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="goods"
|
value="goods"
|
||||||
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/60 px-6"
|
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/60 px-3 sm:px-4"
|
||||||
>
|
>
|
||||||
Товар
|
Товар
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="supplies"
|
value="supplies"
|
||||||
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/60 px-6"
|
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/60 px-3 sm:px-4"
|
||||||
>
|
>
|
||||||
Расходники
|
Расходники
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="returns"
|
value="returns"
|
||||||
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/60 px-6"
|
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/60 px-3 sm:px-4"
|
||||||
>
|
>
|
||||||
Возвраты с ПВЗ
|
<span className="hidden sm:inline">Возвраты с ПВЗ</span>
|
||||||
|
<span className="sm:hidden">Возвраты</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
|
@ -15,8 +15,6 @@ import {
|
|||||||
DollarSign,
|
DollarSign,
|
||||||
Wrench,
|
Wrench,
|
||||||
Package2,
|
Package2,
|
||||||
ChevronDown,
|
|
||||||
ChevronRight,
|
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
interface SupplyOrderItem {
|
interface SupplyOrderItem {
|
||||||
@ -214,7 +212,7 @@ export function RealSupplyOrdersTab() {
|
|||||||
Пока нет заказов расходников
|
Пока нет заказов расходников
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-white/60">
|
<p className="text-white/60">
|
||||||
Создайте первый заказ расходников через кнопку "Создать поставку"
|
Создайте первый заказ расходников через кнопку "Создать поставку"
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
@ -257,16 +255,9 @@ export function RealSupplyOrdersTab() {
|
|||||||
onClick={() => toggleOrderExpansion(order.id)}
|
onClick={() => toggleOrderExpansion(order.id)}
|
||||||
>
|
>
|
||||||
<td className="p-4">
|
<td className="p-4">
|
||||||
<div className="flex items-center space-x-2">
|
<span className="text-white font-medium">
|
||||||
{isOrderExpanded ? (
|
{order.id.slice(-8)}
|
||||||
<ChevronDown className="h-4 w-4 text-white/60" />
|
</span>
|
||||||
) : (
|
|
||||||
<ChevronRight className="h-4 w-4 text-white/60" />
|
|
||||||
)}
|
|
||||||
<span className="text-white font-medium">
|
|
||||||
{order.id.slice(-8)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
<td className="p-4">
|
<td className="p-4">
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
|
@ -2,13 +2,10 @@
|
|||||||
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Card } from "@/components/ui/card";
|
import { Card } from "@/components/ui/card";
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { StatsCard } from "../ui/stats-card";
|
import { StatsCard } from "../ui/stats-card";
|
||||||
import { StatsGrid } from "../ui/stats-grid";
|
import { StatsGrid } from "../ui/stats-grid";
|
||||||
import {
|
import {
|
||||||
ChevronDown,
|
|
||||||
ChevronRight,
|
|
||||||
Calendar,
|
Calendar,
|
||||||
Package,
|
Package,
|
||||||
MapPin,
|
MapPin,
|
||||||
@ -481,23 +478,12 @@ export function OzonSuppliesTab() {
|
|||||||
const isRouteExpanded = expandedRoutes.has(route.id);
|
const isRouteExpanded = expandedRoutes.has(route.id);
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={route.id}>
|
<React.Fragment key={route.id}>
|
||||||
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-cyan-500/10">
|
<tr
|
||||||
<td className="p-4 pl-12">
|
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-cyan-500/10 cursor-pointer"
|
||||||
|
onClick={() => toggleRouteExpansion(route.id)}
|
||||||
|
>
|
||||||
|
<td className="p-4">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="sm"
|
|
||||||
onClick={() =>
|
|
||||||
toggleRouteExpansion(route.id)
|
|
||||||
}
|
|
||||||
className="h-6 w-6 p-0 text-white/60 hover:text-white hover:bg-white/10"
|
|
||||||
>
|
|
||||||
{isRouteExpanded ? (
|
|
||||||
<ChevronDown className="h-4 w-4" />
|
|
||||||
) : (
|
|
||||||
<ChevronRight className="h-4 w-4" />
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
<MapPin className="h-4 w-4 text-cyan-400" />
|
<MapPin className="h-4 w-4 text-cyan-400" />
|
||||||
<span className="text-white font-medium">
|
<span className="text-white font-medium">
|
||||||
Маршрут
|
Маршрут
|
||||||
@ -584,25 +570,14 @@ export function OzonSuppliesTab() {
|
|||||||
expandedWarehouses.has(warehouse.id);
|
expandedWarehouses.has(warehouse.id);
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={warehouse.id}>
|
<React.Fragment key={warehouse.id}>
|
||||||
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-indigo-500/10">
|
<tr
|
||||||
<td className="p-4 pl-20">
|
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-indigo-500/10 cursor-pointer"
|
||||||
|
onClick={() =>
|
||||||
|
toggleWarehouseExpansion(warehouse.id)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<td className="p-4">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="sm"
|
|
||||||
onClick={() =>
|
|
||||||
toggleWarehouseExpansion(
|
|
||||||
warehouse.id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
className="h-6 w-6 p-0 text-white/60 hover:text-white hover:bg-white/10"
|
|
||||||
>
|
|
||||||
{isWarehouseExpanded ? (
|
|
||||||
<ChevronDown className="h-4 w-4" />
|
|
||||||
) : (
|
|
||||||
<ChevronRight className="h-4 w-4" />
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
<Truck className="h-4 w-4 text-indigo-400" />
|
<Truck className="h-4 w-4 text-indigo-400" />
|
||||||
<span className="text-white font-medium">
|
<span className="text-white font-medium">
|
||||||
Склад Ozon
|
Склад Ozon
|
||||||
@ -675,7 +650,7 @@ export function OzonSuppliesTab() {
|
|||||||
key={product.id}
|
key={product.id}
|
||||||
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-teal-500/10"
|
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-teal-500/10"
|
||||||
>
|
>
|
||||||
<td className="p-4 pl-28">
|
<td className="p-4">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Package className="h-4 w-4 text-teal-400" />
|
<Package className="h-4 w-4 text-teal-400" />
|
||||||
<span className="text-white font-medium">
|
<span className="text-white font-medium">
|
||||||
|
@ -2,13 +2,10 @@
|
|||||||
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Card } from "@/components/ui/card";
|
import { Card } from "@/components/ui/card";
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { StatsCard } from "../ui/stats-card";
|
import { StatsCard } from "../ui/stats-card";
|
||||||
import { StatsGrid } from "../ui/stats-grid";
|
import { StatsGrid } from "../ui/stats-grid";
|
||||||
import {
|
import {
|
||||||
ChevronDown,
|
|
||||||
ChevronRight,
|
|
||||||
Calendar,
|
Calendar,
|
||||||
Package,
|
Package,
|
||||||
MapPin,
|
MapPin,
|
||||||
@ -481,23 +478,12 @@ export function WildberriesSuppliesTab() {
|
|||||||
const isRouteExpanded = expandedRoutes.has(route.id);
|
const isRouteExpanded = expandedRoutes.has(route.id);
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={route.id}>
|
<React.Fragment key={route.id}>
|
||||||
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-blue-500/10">
|
<tr
|
||||||
<td className="p-4 pl-12">
|
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-blue-500/10 cursor-pointer"
|
||||||
|
onClick={() => toggleRouteExpansion(route.id)}
|
||||||
|
>
|
||||||
|
<td className="p-4">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="sm"
|
|
||||||
onClick={() =>
|
|
||||||
toggleRouteExpansion(route.id)
|
|
||||||
}
|
|
||||||
className="h-6 w-6 p-0 text-white/60 hover:text-white hover:bg-white/10"
|
|
||||||
>
|
|
||||||
{isRouteExpanded ? (
|
|
||||||
<ChevronDown className="h-4 w-4" />
|
|
||||||
) : (
|
|
||||||
<ChevronRight className="h-4 w-4" />
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
<MapPin className="h-4 w-4 text-blue-400" />
|
<MapPin className="h-4 w-4 text-blue-400" />
|
||||||
<span className="text-white font-medium">
|
<span className="text-white font-medium">
|
||||||
Маршрут
|
Маршрут
|
||||||
@ -584,25 +570,14 @@ export function WildberriesSuppliesTab() {
|
|||||||
expandedWarehouses.has(warehouse.id);
|
expandedWarehouses.has(warehouse.id);
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={warehouse.id}>
|
<React.Fragment key={warehouse.id}>
|
||||||
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-green-500/10">
|
<tr
|
||||||
<td className="p-4 pl-20">
|
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-green-500/10 cursor-pointer"
|
||||||
|
onClick={() =>
|
||||||
|
toggleWarehouseExpansion(warehouse.id)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<td className="p-4">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="sm"
|
|
||||||
onClick={() =>
|
|
||||||
toggleWarehouseExpansion(
|
|
||||||
warehouse.id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
className="h-6 w-6 p-0 text-white/60 hover:text-white hover:bg-white/10"
|
|
||||||
>
|
|
||||||
{isWarehouseExpanded ? (
|
|
||||||
<ChevronDown className="h-4 w-4" />
|
|
||||||
) : (
|
|
||||||
<ChevronRight className="h-4 w-4" />
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
<Truck className="h-4 w-4 text-green-400" />
|
<Truck className="h-4 w-4 text-green-400" />
|
||||||
<span className="text-white font-medium">
|
<span className="text-white font-medium">
|
||||||
Склад WB
|
Склад WB
|
||||||
@ -675,7 +650,7 @@ export function WildberriesSuppliesTab() {
|
|||||||
key={product.id}
|
key={product.id}
|
||||||
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-yellow-500/10"
|
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-yellow-500/10"
|
||||||
>
|
>
|
||||||
<td className="p-4 pl-28">
|
<td className="p-4">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Package className="h-4 w-4 text-yellow-400" />
|
<Package className="h-4 w-4 text-yellow-400" />
|
||||||
<span className="text-white font-medium">
|
<span className="text-white font-medium">
|
||||||
|
@ -23,9 +23,9 @@ export function SuppliesDashboard() {
|
|||||||
|
|
||||||
// Автоматически открываем нужную вкладку при загрузке
|
// Автоматически открываем нужную вкладку при загрузке
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const tab = searchParams.get('tab');
|
const tab = searchParams.get("tab");
|
||||||
if (tab === 'consumables') {
|
if (tab === "consumables") {
|
||||||
setActiveTab('fulfillment'); // Устанавливаем основную вкладку "Поставки на ФФ"
|
setActiveTab("fulfillment"); // Устанавливаем основную вкладку "Поставки на ФФ"
|
||||||
}
|
}
|
||||||
}, [searchParams]);
|
}, [searchParams]);
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ export function SuppliesDashboard() {
|
|||||||
<div className="h-screen flex overflow-hidden">
|
<div className="h-screen flex overflow-hidden">
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<main
|
<main
|
||||||
className={`flex-1 ${getSidebarMargin()} px-4 py-4 overflow-hidden transition-all duration-300`}
|
className={`flex-1 ${getSidebarMargin()} px-2 py-2 overflow-hidden transition-all duration-300`}
|
||||||
>
|
>
|
||||||
<div className="h-full">
|
<div className="h-full">
|
||||||
{/* Главные вкладки с кнопкой создания */}
|
{/* Главные вкладки с кнопкой создания */}
|
||||||
@ -42,28 +42,34 @@ export function SuppliesDashboard() {
|
|||||||
onValueChange={setActiveTab}
|
onValueChange={setActiveTab}
|
||||||
className="w-full h-full flex flex-col"
|
className="w-full h-full flex flex-col"
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between mb-2">
|
<div className="flex items-center justify-between mb-1 flex-wrap gap-2">
|
||||||
<TabsList className="grid grid-cols-2 bg-white/10 backdrop-blur border-white/20 w-fit">
|
<TabsList className="grid grid-cols-2 bg-white/10 backdrop-blur border-white/20 w-fit text-sm">
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="fulfillment"
|
value="fulfillment"
|
||||||
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-purple-500 data-[state=active]:to-pink-500 data-[state=active]:text-white text-white/60 px-8"
|
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-purple-500 data-[state=active]:to-pink-500 data-[state=active]:text-white text-white/60 px-3 sm:px-6"
|
||||||
>
|
>
|
||||||
Поставки на ФФ
|
<span className="hidden sm:inline">Поставки на ФФ</span>
|
||||||
|
<span className="sm:hidden">ФФ</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="marketplace"
|
value="marketplace"
|
||||||
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-purple-500 data-[state=active]:to-pink-500 data-[state=active]:text-white text-white/60 px-8"
|
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-purple-500 data-[state=active]:to-pink-500 data-[state=active]:text-white text-white/60 px-3 sm:px-6"
|
||||||
>
|
>
|
||||||
Поставки на Маркетплейсы
|
<span className="hidden sm:inline">Поставки на Маркетплейсы</span>
|
||||||
|
<span className="sm:hidden">МП</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button className="bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white shadow-lg">
|
<Button
|
||||||
<Plus className="h-4 w-4 mr-2" />
|
size="sm"
|
||||||
Создать поставку
|
className="bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white shadow-lg"
|
||||||
<ChevronDown className="h-4 w-4 ml-2" />
|
>
|
||||||
|
<Plus className="h-3 w-3 mr-1" />
|
||||||
|
<span className="hidden sm:inline">Создать поставку</span>
|
||||||
|
<span className="sm:hidden">Создать</span>
|
||||||
|
<ChevronDown className="h-3 w-3 ml-1" />
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent
|
<DropdownMenuContent
|
||||||
@ -92,11 +98,23 @@ export function SuppliesDashboard() {
|
|||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TabsContent value="fulfillment" className="mt-0 flex-1 overflow-hidden">
|
<TabsContent
|
||||||
<FulfillmentSuppliesTab defaultSubTab={searchParams.get('tab') === 'consumables' ? 'supplies' : undefined} />
|
value="fulfillment"
|
||||||
|
className="mt-0 flex-1 overflow-hidden"
|
||||||
|
>
|
||||||
|
<FulfillmentSuppliesTab
|
||||||
|
defaultSubTab={
|
||||||
|
searchParams.get("tab") === "consumables"
|
||||||
|
? "supplies"
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="marketplace" className="mt-0 flex-1 overflow-hidden">
|
<TabsContent
|
||||||
|
value="marketplace"
|
||||||
|
className="mt-0 flex-1 overflow-hidden"
|
||||||
|
>
|
||||||
<MarketplaceSuppliesTab />
|
<MarketplaceSuppliesTab />
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
@ -32,27 +32,29 @@ export function StatsCard({
|
|||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-white/10 backdrop-blur border-white/20 p-4 hover:bg-white/15 transition-all duration-300 hover:scale-105 hover:shadow-lg",
|
"bg-white/10 backdrop-blur border-white/20 p-2 sm:p-3 hover:bg-white/15 transition-all duration-300",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex items-start justify-between">
|
<div className="flex items-start justify-between">
|
||||||
<div className="flex items-center space-x-3 flex-1">
|
<div className="flex items-center space-x-2 flex-1">
|
||||||
<div className={cn("p-2.5 rounded-xl", iconBg)}>
|
<div className={cn("p-1.5 sm:p-2 rounded-lg", iconBg)}>
|
||||||
<Icon className={cn("h-5 w-5", iconColor)} />
|
<Icon className={cn("h-3 w-3 sm:h-4 sm:w-4", iconColor)} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<p className="text-white/60 text-xs font-medium truncate">
|
<p className="text-white/60 text-xs font-medium truncate">
|
||||||
{title}
|
{title}
|
||||||
</p>
|
</p>
|
||||||
<p
|
<p
|
||||||
className="text-xl font-bold text-white mt-1 truncate"
|
className="text-sm sm:text-lg font-bold text-white mt-0.5 truncate"
|
||||||
title={value.toString()}
|
title={value.toString()}
|
||||||
>
|
>
|
||||||
{value}
|
{value}
|
||||||
</p>
|
</p>
|
||||||
{subtitle && (
|
{subtitle && (
|
||||||
<p className="text-white/40 text-xs mt-1 truncate">{subtitle}</p>
|
<p className="text-white/40 text-xs mt-0.5 truncate hidden sm:block">
|
||||||
|
{subtitle}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -60,7 +62,7 @@ export function StatsCard({
|
|||||||
{trend && (
|
{trend && (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center space-x-1 px-2 py-1 rounded-full text-xs font-medium",
|
"flex items-center space-x-1 px-1.5 py-0.5 rounded-full text-xs font-medium hidden sm:flex",
|
||||||
trend.isPositive
|
trend.isPositive
|
||||||
? "bg-green-500/20 text-green-300"
|
? "bg-green-500/20 text-green-300"
|
||||||
: "bg-red-500/20 text-red-300"
|
: "bg-red-500/20 text-red-300"
|
||||||
|
@ -15,13 +15,13 @@ export function StatsGrid({
|
|||||||
className,
|
className,
|
||||||
}: StatsGridProps) {
|
}: StatsGridProps) {
|
||||||
const gridCols = {
|
const gridCols = {
|
||||||
2: "grid-cols-1 md:grid-cols-2",
|
2: "grid-cols-2",
|
||||||
3: "grid-cols-1 md:grid-cols-3",
|
3: "grid-cols-1 sm:grid-cols-3",
|
||||||
4: "grid-cols-1 md:grid-cols-2 lg:grid-cols-4",
|
4: "grid-cols-2 lg:grid-cols-4",
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn("grid gap-4 mb-6", gridCols[columns], className)}>
|
<div className={cn("grid gap-2 mb-4", gridCols[columns], className)}>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user