Обновлены компоненты управления поставками: улучшены стили и логика отображения для вкладок и карточек товаров. Добавлены проверки на наличие идентификаторов для улучшения обработки данных. Оптимизирован интерфейс с использованием новых компонентов и улучшена читаемость кода.

This commit is contained in:
Veronika Smirnova
2025-07-26 21:07:35 +03:00
parent 25fead48e9
commit f198994400
15 changed files with 989 additions and 852 deletions

View File

@ -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 />

View File

@ -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"> {" "}
{" "}
</span>
<span className="text-white/80 truncate">
{supply.seller.phone} {supply.seller.phone}
</span> </span>
<span className="text-white/60 text-xs"> </span> </div>
<div className="flex items-center gap-1"> <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,18 +1215,20 @@ 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(
(supplier) => {
const isSupplierExpanded = const isSupplierExpanded =
expandedSuppliers.has( expandedSuppliers.has(
supplier.id supplier.id
@ -1180,11 +1240,21 @@ export function FulfillmentGoodsTab() {
> >
<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" 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"
onClick={() => onClick={() => {
if (
supplier &&
supplier.id
) {
toggleSupplierExpansion( toggleSupplierExpansion(
supplier.id supplier.id
) );
} else {
console.error(
"Supplier or supplier.id is undefined",
supplier
);
} }
}}
> >
{/* Название поставщика */} {/* Название поставщика */}
<div className="lg:col-span-2"> <div className="lg:col-span-2">
@ -1192,7 +1262,8 @@ export function FulfillmentGoodsTab() {
Поставщик Поставщик
</p> </p>
<p className="text-white font-medium text-sm"> <p className="text-white font-medium text-sm">
{supplier.name} {supplier?.name ||
"Без названия"}
</p> </p>
</div> </div>
@ -1202,7 +1273,8 @@ export function FulfillmentGoodsTab() {
ИНН ИНН
</p> </p>
<p className="text-white text-xs font-mono"> <p className="text-white text-xs font-mono">
{supplier.inn} {supplier?.inn ||
"Не указан"}
</p> </p>
</div> </div>
@ -1214,13 +1286,13 @@ export function FulfillmentGoodsTab() {
<Badge <Badge
variant="outline" variant="outline"
className={`text-xs ${ className={`text-xs ${
supplier.type === supplier?.type ===
"WHOLESALE" "WHOLESALE"
? "text-blue-300 border-blue-400/30 bg-blue-500/10" ? "text-blue-300 border-blue-400/30 bg-blue-500/10"
: "text-orange-300 border-orange-400/30 bg-orange-500/10" : "text-orange-300 border-orange-400/30 bg-orange-500/10"
}`} }`}
> >
{supplier.type === {supplier?.type ===
"WHOLESALE" "WHOLESALE"
? "Оптовик" ? "Оптовик"
: "Поставщик"} : "Поставщик"}
@ -1233,7 +1305,8 @@ export function FulfillmentGoodsTab() {
Менеджер Менеджер
</p> </p>
<p className="text-white text-xs"> <p className="text-white text-xs">
{supplier.managerName} {supplier?.managerName ||
"Не указан"}
</p> </p>
</div> </div>
@ -1244,7 +1317,8 @@ export function FulfillmentGoodsTab() {
</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> </p>
</div> </div>
@ -1255,7 +1329,8 @@ export function FulfillmentGoodsTab() {
Статус Статус
</p> </p>
{getSupplierStatusBadge( {getSupplierStatusBadge(
supplier.status supplier?.status ||
"active"
)} )}
</div> </div>
</div> </div>
@ -1269,8 +1344,9 @@ export function FulfillmentGoodsTab() {
Полное название Полное название
</p> </p>
<p className="text-white text-sm"> <p className="text-white text-sm">
{supplier.fullName || {supplier?.fullName ||
supplier.name} supplier?.name ||
"Не указано"}
</p> </p>
</div> </div>
<div> <div>
@ -1279,11 +1355,15 @@ export function FulfillmentGoodsTab() {
</p> </p>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<p className="text-white text-sm"> <p className="text-white text-sm">
{supplier.phone} {supplier?.phone ||
"Не указан"}
</p> </p>
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<a <a
href={`https://t.me/${supplier.phone.replace( href={`https://t.me/${(
supplier?.phone ||
""
).replace(
/[^\d]/g, /[^\d]/g,
"" ""
)}`} )}`}
@ -1301,7 +1381,10 @@ export function FulfillmentGoodsTab() {
</svg> </svg>
</a> </a>
<a <a
href={`https://wa.me/${supplier.phone.replace( href={`https://wa.me/${(
supplier?.phone ||
""
).replace(
/[^\d]/g, /[^\d]/g,
"" ""
)}`} )}`}
@ -1326,7 +1409,8 @@ export function FulfillmentGoodsTab() {
Email Email
</p> </p>
<p className="text-white text-sm"> <p className="text-white text-sm">
{supplier.email} {supplier?.email ||
"Не указан"}
</p> </p>
</div> </div>
</div> </div>
@ -1335,14 +1419,16 @@ export function FulfillmentGoodsTab() {
Адрес Адрес
</p> </p>
<p className="text-white text-sm"> <p className="text-white text-sm">
{supplier.address} {supplier?.address ||
"Не указан"}
</p> </p>
</div> </div>
</div> </div>
)} )}
</div> </div>
); );
})} }
)}
</div> </div>
</div> </div>
)} )}

View File

@ -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>

View File

@ -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>

View File

@ -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">

View File

@ -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">

View File

@ -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,6 +507,7 @@ export function FulfillmentWarehouseDashboard() {
</span> </span>
</div> </div>
</div> </div>
{showAdditionalValues && (
<div className="flex items-center justify-end space-x-1"> <div className="flex items-center justify-end space-x-1">
{/* Положительное изменение - всегда зеленое */} {/* Положительное изменение - всегда зеленое */}
<div className="flex items-center space-x-0.5"> <div className="flex items-center space-x-0.5">
@ -495,6 +528,7 @@ export function FulfillmentWarehouseDashboard() {
</span> </span>
</div> </div>
</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,6 +551,7 @@ export function FulfillmentWarehouseDashboard() {
</span> </span>
</div> </div>
</div> </div>
{showAdditionalValues && (
<div className="flex items-center justify-end space-x-1"> <div className="flex items-center justify-end space-x-1">
{/* Положительное изменение - всегда зеленое */} {/* Положительное изменение - всегда зеленое */}
<div className="flex items-center space-x-0.5"> <div className="flex items-center space-x-0.5">
@ -537,6 +572,7 @@ export function FulfillmentWarehouseDashboard() {
</span> </span>
</div> </div>
</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,6 +598,7 @@ export function FulfillmentWarehouseDashboard() {
</span> </span>
</div> </div>
</div> </div>
{showAdditionalValues && (
<div className="flex items-center justify-end space-x-1"> <div className="flex items-center justify-end space-x-1">
{/* Положительное изменение - всегда зеленое */} {/* Положительное изменение - всегда зеленое */}
<div className="flex items-center space-x-0.5"> <div className="flex items-center space-x-0.5">
@ -582,6 +619,7 @@ export function FulfillmentWarehouseDashboard() {
</span> </span>
</div> </div>
</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,6 +646,7 @@ export function FulfillmentWarehouseDashboard() {
</span> </span>
</div> </div>
</div> </div>
{showAdditionalValues && (
<div className="flex items-center justify-end space-x-1"> <div className="flex items-center justify-end space-x-1">
{/* Положительное изменение - всегда зеленое */} {/* Положительное изменение - всегда зеленое */}
<div className="flex items-center space-x-0.5"> <div className="flex items-center space-x-0.5">
@ -634,6 +673,7 @@ export function FulfillmentWarehouseDashboard() {
</span> </span>
</div> </div>
</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,6 +699,7 @@ export function FulfillmentWarehouseDashboard() {
</span> </span>
</div> </div>
</div> </div>
{showAdditionalValues && (
<div className="flex items-center justify-end space-x-1"> <div className="flex items-center justify-end space-x-1">
{/* Положительное изменение - всегда зеленое */} {/* Положительное изменение - всегда зеленое */}
<div className="flex items-center space-x-0.5"> <div className="flex items-center space-x-0.5">
@ -679,6 +720,7 @@ export function FulfillmentWarehouseDashboard() {
</span> </span>
</div> </div>
</div> </div>
)}
</div> </div>
</div> </div>
</div> </div>
@ -716,19 +758,24 @@ 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>
{showAdditionalValues && (
<div className="flex items-center space-x-1"> <div className="flex items-center space-x-1">
{/* Положительное изменение - всегда зеленое */} {/* Положительное изменение - всегда зеленое */}
<div className="flex items-center space-x-0.5"> <div className="flex items-center space-x-0.5">
<span className="text-[9px] font-bold text-green-400"> <span className="text-[9px] font-bold text-green-400">
+ +
{Math.abs(Math.floor(store.productsChange * 0.6))} {Math.abs(
Math.floor(store.productsChange * 0.6)
)}
</span> </span>
</div> </div>
{/* Отрицательное изменение - всегда красное */} {/* Отрицательное изменение - всегда красное */}
<div className="flex items-center space-x-0.5"> <div className="flex items-center space-x-0.5">
<span className="text-[9px] font-bold text-red-400"> <span className="text-[9px] font-bold text-red-400">
- -
{Math.abs(Math.floor(store.productsChange * 0.4))} {Math.abs(
Math.floor(store.productsChange * 0.4)
)}
</span> </span>
</div> </div>
{/* Результирующее изменение */} {/* Результирующее изменение */}
@ -738,6 +785,7 @@ export function FulfillmentWarehouseDashboard() {
</span> </span>
</div> </div>
</div> </div>
)}
</div> </div>
</div> </div>
@ -746,6 +794,7 @@ 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>
{showAdditionalValues && (
<div className="flex items-center space-x-1"> <div className="flex items-center space-x-1">
{/* Положительное изменение - всегда зеленое */} {/* Положительное изменение - всегда зеленое */}
<div className="flex items-center space-x-0.5"> <div className="flex items-center space-x-0.5">
@ -766,6 +815,7 @@ export function FulfillmentWarehouseDashboard() {
</span> </span>
</div> </div>
</div> </div>
)}
</div> </div>
</div> </div>
@ -774,17 +824,24 @@ 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>
{showAdditionalValues && (
<div className="flex items-center space-x-1"> <div className="flex items-center space-x-1">
{/* Положительное изменение - всегда зеленое */} {/* Положительное изменение - всегда зеленое */}
<div className="flex items-center space-x-0.5"> <div className="flex items-center space-x-0.5">
<span className="text-[9px] font-bold text-green-400"> <span className="text-[9px] font-bold text-green-400">
+{Math.abs(Math.floor(store.defectsChange * 0.6))} +
{Math.abs(
Math.floor(store.defectsChange * 0.6)
)}
</span> </span>
</div> </div>
{/* Отрицательное изменение - всегда красное */} {/* Отрицательное изменение - всегда красное */}
<div className="flex items-center space-x-0.5"> <div className="flex items-center space-x-0.5">
<span className="text-[9px] font-bold text-red-400"> <span className="text-[9px] font-bold text-red-400">
-{Math.abs(Math.floor(store.defectsChange * 0.4))} -
{Math.abs(
Math.floor(store.defectsChange * 0.4)
)}
</span> </span>
</div> </div>
{/* Результирующее изменение */} {/* Результирующее изменение */}
@ -794,6 +851,7 @@ export function FulfillmentWarehouseDashboard() {
</span> </span>
</div> </div>
</div> </div>
)}
</div> </div>
</div> </div>
@ -802,6 +860,7 @@ 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>
{showAdditionalValues && (
<div className="flex items-center space-x-1"> <div className="flex items-center space-x-1">
{/* Положительное изменение - всегда зеленое */} {/* Положительное изменение - всегда зеленое */}
<div className="flex items-center space-x-0.5"> <div className="flex items-center space-x-0.5">
@ -828,6 +887,7 @@ export function FulfillmentWarehouseDashboard() {
</span> </span>
</div> </div>
</div> </div>
)}
</div> </div>
</div> </div>
@ -836,6 +896,7 @@ 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>
{showAdditionalValues && (
<div className="flex items-center space-x-1"> <div className="flex items-center space-x-1">
{/* Положительное изменение - всегда зеленое */} {/* Положительное изменение - всегда зеленое */}
<div className="flex items-center space-x-0.5"> <div className="flex items-center space-x-0.5">
@ -862,6 +923,7 @@ export function FulfillmentWarehouseDashboard() {
</span> </span>
</div> </div>
</div> </div>
)}
</div> </div>
</div> </div>
</div> </div>

View File

@ -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"
<div className="flex items-center space-x-2"> onClick={() => toggleRouteExpansion(route.id)}
<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 ? ( <td className="p-2 relative">
<ChevronDown className="h-4 w-4" /> <div className="flex items-center space-x-2">
) : ( <div className="w-1 h-1 rounded-full bg-blue-400 mr-1"></div>
<ChevronRight className="h-4 w-4" /> <MapPin className="h-3 w-3 text-blue-400" />
)} <span className="text-white font-medium text-sm">
</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"
<div className="flex items-center space-x-2">
<Button
variant="ghost"
size="sm"
onClick={() => onClick={() =>
toggleWholesalerExpansion( toggleWholesalerExpansion(wholesaler.id)
wholesaler.id
)
} }
className="h-6 w-6 p-0 text-white/60 hover:text-white hover:bg-white/10"
> >
{isWholesalerExpanded ? ( <td className="p-2 relative">
<ChevronDown className="h-4 w-4" /> <div className="flex items-center space-x-2">
) : ( <div className="w-1 h-1 rounded-full bg-green-400 mr-1"></div>
<ChevronRight className="h-4 w-4" /> <div className="w-1 h-1 rounded-full bg-green-400 mr-1"></div>
)} <Building2 className="h-3 w-3 text-green-400" />
</Button> <span className="text-white font-medium text-sm">
<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"
<div className="flex items-center space-x-2">
<Button
variant="ghost"
size="sm"
onClick={() => onClick={() =>
toggleProductExpansion( toggleProductExpansion(
product.id product.id
) )
} }
className="h-6 w-6 p-0 text-white/60 hover:text-white hover:bg-white/10"
> >
{isProductExpanded ? ( <td className="p-2 relative">
<ChevronDown className="h-4 w-4" /> <div className="flex items-center space-x-2">
) : ( <div className="w-1 h-1 rounded-full bg-yellow-400 mr-1"></div>
<ChevronRight className="h-4 w-4" /> <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>
</Button> <Package className="h-3 w-3 text-yellow-400" />
<Package className="h-4 w-4 text-yellow-400" /> <span className="text-white font-medium text-sm">
<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">
📋 Параметры товара: 📋 Параметры товара:

View File

@ -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>

View File

@ -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">
Создайте первый заказ расходников через кнопку "Создать поставку" Создайте первый заказ расходников через кнопку &quot;Создать поставку&quot;
</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">
{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"> <span className="text-white font-medium">
{order.id.slice(-8)} {order.id.slice(-8)}
</span> </span>
</div>
</td> </td>
<td className="p-4"> <td className="p-4">
<div className="space-y-1"> <div className="space-y-1">

View File

@ -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"
<div className="flex items-center space-x-2"> onClick={() => toggleRouteExpansion(route.id)}
<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 ? ( <td className="p-4">
<ChevronDown className="h-4 w-4" /> <div className="flex items-center space-x-2">
) : (
<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"
<div className="flex items-center space-x-2">
<Button
variant="ghost"
size="sm"
onClick={() => onClick={() =>
toggleWarehouseExpansion( toggleWarehouseExpansion(warehouse.id)
warehouse.id
)
} }
className="h-6 w-6 p-0 text-white/60 hover:text-white hover:bg-white/10"
> >
{isWarehouseExpanded ? ( <td className="p-4">
<ChevronDown className="h-4 w-4" /> <div className="flex items-center space-x-2">
) : (
<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">

View File

@ -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"
<div className="flex items-center space-x-2"> onClick={() => toggleRouteExpansion(route.id)}
<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 ? ( <td className="p-4">
<ChevronDown className="h-4 w-4" /> <div className="flex items-center space-x-2">
) : (
<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"
<div className="flex items-center space-x-2">
<Button
variant="ghost"
size="sm"
onClick={() => onClick={() =>
toggleWarehouseExpansion( toggleWarehouseExpansion(warehouse.id)
warehouse.id
)
} }
className="h-6 w-6 p-0 text-white/60 hover:text-white hover:bg-white/10"
> >
{isWarehouseExpanded ? ( <td className="p-4">
<ChevronDown className="h-4 w-4" /> <div className="flex items-center space-x-2">
) : (
<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">

View File

@ -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>

View File

@ -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"

View File

@ -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>
); );