Обновлены компоненты управления поставками: улучшены стили и логика отображения для вкладок и карточек товаров. Добавлены проверки на наличие идентификаторов для улучшения обработки данных. Оптимизирован интерфейс с использованием новых компонентов и улучшена читаемость кода.
This commit is contained in:
@ -2,13 +2,10 @@
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { StatsCard } from "../ui/stats-card";
|
||||
import { StatsGrid } from "../ui/stats-grid";
|
||||
import {
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
Calendar,
|
||||
Package,
|
||||
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">
|
||||
<div className="overflow-auto flex-1">
|
||||
<table className="w-full">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="border-b border-white/20">
|
||||
<th className="text-left p-4 text-white font-semibold">№</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 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 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 className="text-left p-4 text-white font-semibold">
|
||||
Цена товаров
|
||||
<th className="text-left p-2 text-white font-semibold text-sm hidden lg:table-cell">
|
||||
Создана
|
||||
</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 className="text-left p-4 text-white font-semibold">
|
||||
Логистика до ФФ
|
||||
<th className="text-left p-2 text-white font-semibold text-sm">
|
||||
Факт
|
||||
</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 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>
|
||||
</tr>
|
||||
@ -408,43 +415,41 @@ export function FulfillmentGoodsTab() {
|
||||
return (
|
||||
<React.Fragment key={supply.id}>
|
||||
{/* Основная строка поставки */}
|
||||
<tr
|
||||
<tr
|
||||
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-purple-500/10 cursor-pointer"
|
||||
onClick={() => toggleSupplyExpansion(supply.id)}
|
||||
>
|
||||
<td className="p-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<span className="text-white font-normal text-lg">
|
||||
{supply.number}
|
||||
</span>
|
||||
</div>
|
||||
<td className="p-2">
|
||||
<span className="text-white font-normal text-sm">
|
||||
{supply.number}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Calendar className="h-4 w-4 text-white/40" />
|
||||
<span className="text-white font-semibold">
|
||||
<td className="p-2">
|
||||
<div className="flex items-center space-x-1">
|
||||
<Calendar className="h-3 w-3 text-white/40" />
|
||||
<span className="text-white font-semibold text-sm">
|
||||
{formatDate(supply.deliveryDate)}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-white/80">
|
||||
<td className="p-2 hidden lg:table-cell">
|
||||
<span className="text-white/80 text-sm">
|
||||
{formatDate(supply.createdDate)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-white font-semibold">
|
||||
<td className="p-2">
|
||||
<span className="text-white font-semibold text-sm">
|
||||
{supply.plannedTotal}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-white font-semibold">
|
||||
<td className="p-2">
|
||||
<span className="text-white font-semibold text-sm">
|
||||
{supply.actualTotal}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<td className="p-2">
|
||||
<span
|
||||
className={`font-semibold ${
|
||||
className={`font-semibold text-sm ${
|
||||
supply.defectTotal > 0
|
||||
? "text-red-400"
|
||||
: "text-white"
|
||||
@ -453,30 +458,30 @@ export function FulfillmentGoodsTab() {
|
||||
{supply.defectTotal}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-green-400 font-semibold">
|
||||
<td className="p-2">
|
||||
<span className="text-green-400 font-semibold text-sm">
|
||||
{formatCurrency(supply.totalProductPrice)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-blue-400 font-semibold">
|
||||
<td className="p-2 hidden lg:table-cell">
|
||||
<span className="text-blue-400 font-semibold text-sm">
|
||||
{formatCurrency(supply.totalFulfillmentPrice)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-purple-400 font-semibold">
|
||||
<td className="p-2 hidden lg:table-cell">
|
||||
<span className="text-purple-400 font-semibold text-sm">
|
||||
{formatCurrency(supply.totalLogisticsPrice)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<DollarSign className="h-4 w-4 text-white/40" />
|
||||
<span className="text-white font-bold text-lg">
|
||||
<td className="p-2">
|
||||
<div className="flex items-center space-x-1">
|
||||
<DollarSign className="h-3 w-3 text-white/40" />
|
||||
<span className="text-white font-bold text-sm">
|
||||
{formatCurrency(supply.grandTotal)}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-4">{getStatusBadge(supply.status)}</td>
|
||||
<td className="p-2">{getStatusBadge(supply.status)}</td>
|
||||
</tr>
|
||||
|
||||
{/* Развернутые уровни - аналогично оригинальному коду */}
|
||||
@ -485,47 +490,39 @@ export function FulfillmentGoodsTab() {
|
||||
const isRouteExpanded = expandedRoutes.has(route.id);
|
||||
return (
|
||||
<React.Fragment key={route.id}>
|
||||
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-blue-500/10">
|
||||
<td className="p-4 pl-12">
|
||||
<tr
|
||||
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">
|
||||
<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" />
|
||||
<span className="text-white font-medium">
|
||||
<div className="w-1 h-1 rounded-full bg-blue-400 mr-1"></div>
|
||||
<MapPin className="h-3 w-3 text-blue-400" />
|
||||
<span className="text-white font-medium text-sm">
|
||||
Маршрут
|
||||
</span>
|
||||
</div>
|
||||
<div className="absolute left-0 top-0 w-0.5 h-full bg-blue-400/30"></div>
|
||||
</td>
|
||||
<td className="p-4" colSpan={2}>
|
||||
<td className="p-2" colSpan={1}>
|
||||
<div className="text-white">
|
||||
<div className="flex items-center space-x-2 mb-1">
|
||||
<span className="font-medium">
|
||||
<span className="font-medium text-sm">
|
||||
{route.from}
|
||||
</span>
|
||||
<span className="text-white/60">→</span>
|
||||
<span className="font-medium">
|
||||
<span className="font-medium text-sm">
|
||||
{route.to}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-xs text-white/60">
|
||||
<div className="text-xs text-white/60 hidden sm:block">
|
||||
{route.fromAddress} → {route.toAddress}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-white/80">
|
||||
<td className="p-2 hidden lg:table-cell"></td>
|
||||
<td className="p-2">
|
||||
<span className="text-white/80 text-sm">
|
||||
{route.wholesalers.reduce(
|
||||
(sum, w) =>
|
||||
sum +
|
||||
@ -537,8 +534,8 @@ export function FulfillmentGoodsTab() {
|
||||
)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-white/80">
|
||||
<td className="p-2">
|
||||
<span className="text-white/80 text-sm">
|
||||
{route.wholesalers.reduce(
|
||||
(sum, w) =>
|
||||
sum +
|
||||
@ -550,8 +547,8 @@ export function FulfillmentGoodsTab() {
|
||||
)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-white/80">
|
||||
<td className="p-2">
|
||||
<span className="text-white/80 text-sm">
|
||||
{route.wholesalers.reduce(
|
||||
(sum, w) =>
|
||||
sum +
|
||||
@ -563,29 +560,29 @@ export function FulfillmentGoodsTab() {
|
||||
)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-green-400 font-medium">
|
||||
<td className="p-2">
|
||||
<span className="text-green-400 font-medium text-sm">
|
||||
{formatCurrency(route.totalProductPrice)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-blue-400 font-medium">
|
||||
<td className="p-2 hidden lg:table-cell">
|
||||
<span className="text-blue-400 font-medium text-sm">
|
||||
{formatCurrency(
|
||||
route.fulfillmentServicePrice
|
||||
)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-purple-400 font-medium">
|
||||
<td className="p-2 hidden lg:table-cell">
|
||||
<span className="text-purple-400 font-medium text-sm">
|
||||
{formatCurrency(route.logisticsPrice)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-white font-semibold">
|
||||
<td className="p-2">
|
||||
<span className="text-white font-semibold text-sm">
|
||||
{formatCurrency(route.totalAmount)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4"></td>
|
||||
<td className="p-2"></td>
|
||||
</tr>
|
||||
|
||||
{/* Остальные уровни развертывания аналогично */}
|
||||
@ -595,73 +592,66 @@ export function FulfillmentGoodsTab() {
|
||||
expandedWholesalers.has(wholesaler.id);
|
||||
return (
|
||||
<React.Fragment key={wholesaler.id}>
|
||||
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-green-500/10">
|
||||
<td className="p-4 pl-20">
|
||||
<tr
|
||||
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">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
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">
|
||||
<div className="w-1 h-1 rounded-full bg-green-400 mr-1"></div>
|
||||
<div className="w-1 h-1 rounded-full bg-green-400 mr-1"></div>
|
||||
<Building2 className="h-3 w-3 text-green-400" />
|
||||
<span className="text-white font-medium text-sm">
|
||||
Оптовик
|
||||
</span>
|
||||
</div>
|
||||
<div className="absolute left-0 top-0 w-0.5 h-full bg-green-400/30"></div>
|
||||
</td>
|
||||
<td className="p-4" colSpan={2}>
|
||||
<td className="p-2" colSpan={1}>
|
||||
<div className="text-white">
|
||||
<div className="font-medium mb-1">
|
||||
<div className="font-medium mb-1 text-sm">
|
||||
{wholesaler.name}
|
||||
</div>
|
||||
<div className="text-xs text-white/60 mb-1">
|
||||
<div className="text-xs text-white/60 mb-1 hidden sm:block">
|
||||
ИНН: {wholesaler.inn}
|
||||
</div>
|
||||
<div className="text-xs text-white/60 mb-1">
|
||||
<div className="text-xs text-white/60 mb-1 hidden lg:block">
|
||||
{wholesaler.address}
|
||||
</div>
|
||||
<div className="text-xs text-white/60">
|
||||
<div className="text-xs text-white/60 hidden sm:block">
|
||||
{wholesaler.contact}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-white/80">
|
||||
<td className="p-2 hidden lg:table-cell"></td>
|
||||
<td className="p-2">
|
||||
<span className="text-white/80 text-sm">
|
||||
{wholesaler.products.reduce(
|
||||
(sum, p) => sum + p.plannedQty,
|
||||
0
|
||||
)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-white/80">
|
||||
<td className="p-2">
|
||||
<span className="text-white/80 text-sm">
|
||||
{wholesaler.products.reduce(
|
||||
(sum, p) => sum + p.actualQty,
|
||||
0
|
||||
)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-white/80">
|
||||
<td className="p-2">
|
||||
<span className="text-white/80 text-sm">
|
||||
{wholesaler.products.reduce(
|
||||
(sum, p) => sum + p.defectQty,
|
||||
0
|
||||
)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-green-400 font-medium">
|
||||
<td className="p-2">
|
||||
<span className="text-green-400 font-medium text-sm">
|
||||
{formatCurrency(
|
||||
wholesaler.products.reduce(
|
||||
(sum, p) =>
|
||||
@ -671,9 +661,12 @@ export function FulfillmentGoodsTab() {
|
||||
)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4" colSpan={2}></td>
|
||||
<td className="p-4">
|
||||
<span className="text-white font-semibold">
|
||||
<td
|
||||
className="p-2 hidden lg:table-cell"
|
||||
colSpan={2}
|
||||
></td>
|
||||
<td className="p-2">
|
||||
<span className="text-white font-semibold text-sm">
|
||||
{formatCurrency(
|
||||
wholesaler.totalAmount
|
||||
)}
|
||||
@ -689,57 +682,53 @@ export function FulfillmentGoodsTab() {
|
||||
expandedProducts.has(product.id);
|
||||
return (
|
||||
<React.Fragment key={product.id}>
|
||||
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-yellow-500/10">
|
||||
<td className="p-4 pl-28">
|
||||
<tr
|
||||
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">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
toggleProductExpansion(
|
||||
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">
|
||||
<div className="w-1 h-1 rounded-full bg-yellow-400 mr-1"></div>
|
||||
<div className="w-1 h-1 rounded-full bg-yellow-400 mr-1"></div>
|
||||
<div className="w-1 h-1 rounded-full bg-yellow-400 mr-1"></div>
|
||||
<Package className="h-3 w-3 text-yellow-400" />
|
||||
<span className="text-white font-medium text-sm">
|
||||
Товар
|
||||
</span>
|
||||
</div>
|
||||
<div className="absolute left-0 top-0 w-0.5 h-full bg-yellow-400/30"></div>
|
||||
</td>
|
||||
<td className="p-4" colSpan={2}>
|
||||
<td className="p-2" colSpan={1}>
|
||||
<div className="text-white">
|
||||
<div className="font-medium mb-1">
|
||||
<div className="font-medium mb-1 text-sm">
|
||||
{product.name}
|
||||
</div>
|
||||
<div className="text-xs text-white/60 mb-1">
|
||||
<div className="text-xs text-white/60 mb-1 hidden sm:block">
|
||||
Артикул: {product.sku}
|
||||
</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}
|
||||
</Badge>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-white font-semibold">
|
||||
<td className="p-2 hidden lg:table-cell"></td>
|
||||
<td className="p-2">
|
||||
<span className="text-white font-semibold text-sm">
|
||||
{product.plannedQty}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-white font-semibold">
|
||||
<td className="p-2">
|
||||
<span className="text-white font-semibold text-sm">
|
||||
{product.actualQty}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<td className="p-2">
|
||||
<span
|
||||
className={`font-semibold ${
|
||||
className={`font-semibold text-sm ${
|
||||
product.defectQty > 0
|
||||
? "text-red-400"
|
||||
: "text-white"
|
||||
@ -748,16 +737,16 @@ export function FulfillmentGoodsTab() {
|
||||
{product.defectQty}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<td className="p-2">
|
||||
<div className="text-white">
|
||||
<div className="font-medium">
|
||||
<div className="font-medium text-sm">
|
||||
{formatCurrency(
|
||||
calculateProductTotal(
|
||||
product
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
<div className="text-xs text-white/60">
|
||||
<div className="text-xs text-white/60 hidden sm:block">
|
||||
{formatCurrency(
|
||||
product.productPrice
|
||||
)}{" "}
|
||||
@ -765,15 +754,18 @@ export function FulfillmentGoodsTab() {
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-4" colSpan={2}>
|
||||
<td
|
||||
className="p-2 hidden lg:table-cell"
|
||||
colSpan={2}
|
||||
>
|
||||
{getEfficiencyBadge(
|
||||
product.plannedQty,
|
||||
product.actualQty,
|
||||
product.defectQty
|
||||
)}
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="text-white font-semibold">
|
||||
<td className="p-2">
|
||||
<span className="text-white font-semibold text-sm">
|
||||
{formatCurrency(
|
||||
calculateProductTotal(
|
||||
product
|
||||
@ -781,7 +773,7 @@ export function FulfillmentGoodsTab() {
|
||||
)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4"></td>
|
||||
<td className="p-2"></td>
|
||||
</tr>
|
||||
|
||||
{/* Параметры товара */}
|
||||
@ -792,7 +784,7 @@ export function FulfillmentGoodsTab() {
|
||||
className="p-0"
|
||||
>
|
||||
<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">
|
||||
<span className="text-xs text-white/60">
|
||||
📋 Параметры товара:
|
||||
|
@ -10,7 +10,9 @@ interface FulfillmentSuppliesTabProps {
|
||||
defaultSubTab?: string;
|
||||
}
|
||||
|
||||
export function FulfillmentSuppliesTab({ defaultSubTab }: FulfillmentSuppliesTabProps) {
|
||||
export function FulfillmentSuppliesTab({
|
||||
defaultSubTab,
|
||||
}: FulfillmentSuppliesTabProps) {
|
||||
const [activeSubTab, setActiveSubTab] = useState("goods");
|
||||
|
||||
// Устанавливаем активную подвкладку при получении defaultSubTab
|
||||
@ -28,24 +30,25 @@ export function FulfillmentSuppliesTab({ defaultSubTab }: FulfillmentSuppliesTab
|
||||
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
|
||||
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
|
||||
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
|
||||
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>
|
||||
</TabsList>
|
||||
|
||||
|
@ -15,8 +15,6 @@ import {
|
||||
DollarSign,
|
||||
Wrench,
|
||||
Package2,
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
} from "lucide-react";
|
||||
|
||||
interface SupplyOrderItem {
|
||||
@ -214,7 +212,7 @@ export function RealSupplyOrdersTab() {
|
||||
Пока нет заказов расходников
|
||||
</h3>
|
||||
<p className="text-white/60">
|
||||
Создайте первый заказ расходников через кнопку "Создать поставку"
|
||||
Создайте первый заказ расходников через кнопку "Создать поставку"
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
@ -257,16 +255,9 @@ export function RealSupplyOrdersTab() {
|
||||
onClick={() => toggleOrderExpansion(order.id)}
|
||||
>
|
||||
<td className="p-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
{isOrderExpanded ? (
|
||||
<ChevronDown className="h-4 w-4 text-white/60" />
|
||||
) : (
|
||||
<ChevronRight className="h-4 w-4 text-white/60" />
|
||||
)}
|
||||
<span className="text-white font-medium">
|
||||
{order.id.slice(-8)}
|
||||
</span>
|
||||
</div>
|
||||
<span className="text-white font-medium">
|
||||
{order.id.slice(-8)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<div className="space-y-1">
|
||||
|
@ -2,13 +2,10 @@
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { StatsCard } from "../ui/stats-card";
|
||||
import { StatsGrid } from "../ui/stats-grid";
|
||||
import {
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
Calendar,
|
||||
Package,
|
||||
MapPin,
|
||||
@ -481,23 +478,12 @@ export function OzonSuppliesTab() {
|
||||
const isRouteExpanded = expandedRoutes.has(route.id);
|
||||
return (
|
||||
<React.Fragment key={route.id}>
|
||||
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-cyan-500/10">
|
||||
<td className="p-4 pl-12">
|
||||
<tr
|
||||
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">
|
||||
<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" />
|
||||
<span className="text-white font-medium">
|
||||
Маршрут
|
||||
@ -584,25 +570,14 @@ export function OzonSuppliesTab() {
|
||||
expandedWarehouses.has(warehouse.id);
|
||||
return (
|
||||
<React.Fragment key={warehouse.id}>
|
||||
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-indigo-500/10">
|
||||
<td className="p-4 pl-20">
|
||||
<tr
|
||||
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">
|
||||
<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" />
|
||||
<span className="text-white font-medium">
|
||||
Склад Ozon
|
||||
@ -675,7 +650,7 @@ export function OzonSuppliesTab() {
|
||||
key={product.id}
|
||||
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">
|
||||
<Package className="h-4 w-4 text-teal-400" />
|
||||
<span className="text-white font-medium">
|
||||
|
@ -2,13 +2,10 @@
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { StatsCard } from "../ui/stats-card";
|
||||
import { StatsGrid } from "../ui/stats-grid";
|
||||
import {
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
Calendar,
|
||||
Package,
|
||||
MapPin,
|
||||
@ -481,23 +478,12 @@ export function WildberriesSuppliesTab() {
|
||||
const isRouteExpanded = expandedRoutes.has(route.id);
|
||||
return (
|
||||
<React.Fragment key={route.id}>
|
||||
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-blue-500/10">
|
||||
<td className="p-4 pl-12">
|
||||
<tr
|
||||
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">
|
||||
<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" />
|
||||
<span className="text-white font-medium">
|
||||
Маршрут
|
||||
@ -584,25 +570,14 @@ export function WildberriesSuppliesTab() {
|
||||
expandedWarehouses.has(warehouse.id);
|
||||
return (
|
||||
<React.Fragment key={warehouse.id}>
|
||||
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-green-500/10">
|
||||
<td className="p-4 pl-20">
|
||||
<tr
|
||||
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">
|
||||
<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" />
|
||||
<span className="text-white font-medium">
|
||||
Склад WB
|
||||
@ -675,7 +650,7 @@ export function WildberriesSuppliesTab() {
|
||||
key={product.id}
|
||||
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">
|
||||
<Package className="h-4 w-4 text-yellow-400" />
|
||||
<span className="text-white font-medium">
|
||||
|
@ -23,9 +23,9 @@ export function SuppliesDashboard() {
|
||||
|
||||
// Автоматически открываем нужную вкладку при загрузке
|
||||
useEffect(() => {
|
||||
const tab = searchParams.get('tab');
|
||||
if (tab === 'consumables') {
|
||||
setActiveTab('fulfillment'); // Устанавливаем основную вкладку "Поставки на ФФ"
|
||||
const tab = searchParams.get("tab");
|
||||
if (tab === "consumables") {
|
||||
setActiveTab("fulfillment"); // Устанавливаем основную вкладку "Поставки на ФФ"
|
||||
}
|
||||
}, [searchParams]);
|
||||
|
||||
@ -33,7 +33,7 @@ export function SuppliesDashboard() {
|
||||
<div className="h-screen flex overflow-hidden">
|
||||
<Sidebar />
|
||||
<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">
|
||||
{/* Главные вкладки с кнопкой создания */}
|
||||
@ -42,28 +42,34 @@ export function SuppliesDashboard() {
|
||||
onValueChange={setActiveTab}
|
||||
className="w-full h-full flex flex-col"
|
||||
>
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<TabsList className="grid grid-cols-2 bg-white/10 backdrop-blur border-white/20 w-fit">
|
||||
<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 text-sm">
|
||||
<TabsTrigger
|
||||
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
|
||||
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>
|
||||
</TabsList>
|
||||
|
||||
<DropdownMenu>
|
||||
<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">
|
||||
<Plus className="h-4 w-4 mr-2" />
|
||||
Создать поставку
|
||||
<ChevronDown className="h-4 w-4 ml-2" />
|
||||
<Button
|
||||
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"
|
||||
>
|
||||
<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>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
@ -92,11 +98,23 @@ export function SuppliesDashboard() {
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
||||
<TabsContent value="fulfillment" className="mt-0 flex-1 overflow-hidden">
|
||||
<FulfillmentSuppliesTab defaultSubTab={searchParams.get('tab') === 'consumables' ? 'supplies' : undefined} />
|
||||
<TabsContent
|
||||
value="fulfillment"
|
||||
className="mt-0 flex-1 overflow-hidden"
|
||||
>
|
||||
<FulfillmentSuppliesTab
|
||||
defaultSubTab={
|
||||
searchParams.get("tab") === "consumables"
|
||||
? "supplies"
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="marketplace" className="mt-0 flex-1 overflow-hidden">
|
||||
<TabsContent
|
||||
value="marketplace"
|
||||
className="mt-0 flex-1 overflow-hidden"
|
||||
>
|
||||
<MarketplaceSuppliesTab />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
@ -32,27 +32,29 @@ export function StatsCard({
|
||||
return (
|
||||
<Card
|
||||
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
|
||||
)}
|
||||
>
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex items-center space-x-3 flex-1">
|
||||
<div className={cn("p-2.5 rounded-xl", iconBg)}>
|
||||
<Icon className={cn("h-5 w-5", iconColor)} />
|
||||
<div className="flex items-center space-x-2 flex-1">
|
||||
<div className={cn("p-1.5 sm:p-2 rounded-lg", iconBg)}>
|
||||
<Icon className={cn("h-3 w-3 sm:h-4 sm:w-4", iconColor)} />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-white/60 text-xs font-medium truncate">
|
||||
{title}
|
||||
</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()}
|
||||
>
|
||||
{value}
|
||||
</p>
|
||||
{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>
|
||||
@ -60,7 +62,7 @@ export function StatsCard({
|
||||
{trend && (
|
||||
<div
|
||||
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
|
||||
? "bg-green-500/20 text-green-300"
|
||||
: "bg-red-500/20 text-red-300"
|
||||
|
@ -15,13 +15,13 @@ export function StatsGrid({
|
||||
className,
|
||||
}: StatsGridProps) {
|
||||
const gridCols = {
|
||||
2: "grid-cols-1 md:grid-cols-2",
|
||||
3: "grid-cols-1 md:grid-cols-3",
|
||||
4: "grid-cols-1 md:grid-cols-2 lg:grid-cols-4",
|
||||
2: "grid-cols-2",
|
||||
3: "grid-cols-1 sm:grid-cols-3",
|
||||
4: "grid-cols-2 lg:grid-cols-4",
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cn("grid gap-4 mb-6", gridCols[columns], className)}>
|
||||
<div className={cn("grid gap-2 mb-4", gridCols[columns], className)}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
Reference in New Issue
Block a user