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

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

@ -2,13 +2,10 @@
import React, { useState } from "react";
import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { StatsCard } from "../ui/stats-card";
import { StatsGrid } from "../ui/stats-grid";
import {
ChevronDown,
ChevronRight,
Calendar,
Package,
MapPin,
@ -371,32 +368,42 @@ export function FulfillmentGoodsTab() {
{/* Таблица поставок товаров ФФ */}
<Card className="bg-white/10 backdrop-blur border-white/20 overflow-hidden flex-1 flex flex-col">
<div className="overflow-auto flex-1">
<table className="w-full">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-white/20">
<th className="text-left p-4 text-white font-semibold"></th>
<th className="text-left p-4 text-white font-semibold">
Дата поставки
<th className="text-left p-2 text-white font-semibold text-sm">
</th>
<th className="text-left p-4 text-white font-semibold">
Дата создания
<th className="text-left p-2 text-white font-semibold text-sm">
<span className="hidden sm:inline">Дата поставки</span>
<span className="sm:hidden">Поставка</span>
</th>
<th className="text-left p-4 text-white font-semibold">План</th>
<th className="text-left p-4 text-white font-semibold">Факт</th>
<th className="text-left p-4 text-white font-semibold">Брак</th>
<th className="text-left p-4 text-white font-semibold">
Цена товаров
<th className="text-left p-2 text-white font-semibold text-sm hidden lg:table-cell">
Создана
</th>
<th className="text-left p-4 text-white font-semibold">
Услуги ФФ
<th className="text-left p-2 text-white font-semibold text-sm">
План
</th>
<th className="text-left p-4 text-white font-semibold">
Логистика до ФФ
<th className="text-left p-2 text-white font-semibold text-sm">
Факт
</th>
<th className="text-left p-4 text-white font-semibold">
Итого сумма
<th className="text-left p-2 text-white font-semibold text-sm">
Брак
</th>
<th className="text-left p-4 text-white font-semibold">
<th className="text-left p-2 text-white font-semibold text-sm">
<span className="hidden md:inline">Цена товаров</span>
<span className="md:hidden">Цена</span>
</th>
<th className="text-left p-2 text-white font-semibold text-sm hidden lg:table-cell">
ФФ
</th>
<th className="text-left p-2 text-white font-semibold text-sm hidden lg:table-cell">
Логистика
</th>
<th className="text-left p-2 text-white font-semibold text-sm">
Итого
</th>
<th className="text-left p-2 text-white font-semibold text-sm">
Статус
</th>
</tr>
@ -408,43 +415,41 @@ export function FulfillmentGoodsTab() {
return (
<React.Fragment key={supply.id}>
{/* Основная строка поставки */}
<tr
<tr
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-purple-500/10 cursor-pointer"
onClick={() => toggleSupplyExpansion(supply.id)}
>
<td className="p-4">
<div className="flex items-center space-x-2">
<span className="text-white font-normal text-lg">
{supply.number}
</span>
</div>
<td className="p-2">
<span className="text-white font-normal text-sm">
{supply.number}
</span>
</td>
<td className="p-4">
<div className="flex items-center space-x-2">
<Calendar className="h-4 w-4 text-white/40" />
<span className="text-white font-semibold">
<td className="p-2">
<div className="flex items-center space-x-1">
<Calendar className="h-3 w-3 text-white/40" />
<span className="text-white font-semibold text-sm">
{formatDate(supply.deliveryDate)}
</span>
</div>
</td>
<td className="p-4">
<span className="text-white/80">
<td className="p-2 hidden lg:table-cell">
<span className="text-white/80 text-sm">
{formatDate(supply.createdDate)}
</span>
</td>
<td className="p-4">
<span className="text-white font-semibold">
<td className="p-2">
<span className="text-white font-semibold text-sm">
{supply.plannedTotal}
</span>
</td>
<td className="p-4">
<span className="text-white font-semibold">
<td className="p-2">
<span className="text-white font-semibold text-sm">
{supply.actualTotal}
</span>
</td>
<td className="p-4">
<td className="p-2">
<span
className={`font-semibold ${
className={`font-semibold text-sm ${
supply.defectTotal > 0
? "text-red-400"
: "text-white"
@ -453,30 +458,30 @@ export function FulfillmentGoodsTab() {
{supply.defectTotal}
</span>
</td>
<td className="p-4">
<span className="text-green-400 font-semibold">
<td className="p-2">
<span className="text-green-400 font-semibold text-sm">
{formatCurrency(supply.totalProductPrice)}
</span>
</td>
<td className="p-4">
<span className="text-blue-400 font-semibold">
<td className="p-2 hidden lg:table-cell">
<span className="text-blue-400 font-semibold text-sm">
{formatCurrency(supply.totalFulfillmentPrice)}
</span>
</td>
<td className="p-4">
<span className="text-purple-400 font-semibold">
<td className="p-2 hidden lg:table-cell">
<span className="text-purple-400 font-semibold text-sm">
{formatCurrency(supply.totalLogisticsPrice)}
</span>
</td>
<td className="p-4">
<div className="flex items-center space-x-2">
<DollarSign className="h-4 w-4 text-white/40" />
<span className="text-white font-bold text-lg">
<td className="p-2">
<div className="flex items-center space-x-1">
<DollarSign className="h-3 w-3 text-white/40" />
<span className="text-white font-bold text-sm">
{formatCurrency(supply.grandTotal)}
</span>
</div>
</td>
<td className="p-4">{getStatusBadge(supply.status)}</td>
<td className="p-2">{getStatusBadge(supply.status)}</td>
</tr>
{/* Развернутые уровни - аналогично оригинальному коду */}
@ -485,47 +490,39 @@ export function FulfillmentGoodsTab() {
const isRouteExpanded = expandedRoutes.has(route.id);
return (
<React.Fragment key={route.id}>
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-blue-500/10">
<td className="p-4 pl-12">
<tr
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-blue-500/10 cursor-pointer"
onClick={() => toggleRouteExpansion(route.id)}
>
<td className="p-2 relative">
<div className="flex items-center space-x-2">
<Button
variant="ghost"
size="sm"
onClick={() =>
toggleRouteExpansion(route.id)
}
className="h-6 w-6 p-0 text-white/60 hover:text-white hover:bg-white/10"
>
{isRouteExpanded ? (
<ChevronDown className="h-4 w-4" />
) : (
<ChevronRight className="h-4 w-4" />
)}
</Button>
<MapPin className="h-4 w-4 text-blue-400" />
<span className="text-white font-medium">
<div className="w-1 h-1 rounded-full bg-blue-400 mr-1"></div>
<MapPin className="h-3 w-3 text-blue-400" />
<span className="text-white font-medium text-sm">
Маршрут
</span>
</div>
<div className="absolute left-0 top-0 w-0.5 h-full bg-blue-400/30"></div>
</td>
<td className="p-4" colSpan={2}>
<td className="p-2" colSpan={1}>
<div className="text-white">
<div className="flex items-center space-x-2 mb-1">
<span className="font-medium">
<span className="font-medium text-sm">
{route.from}
</span>
<span className="text-white/60"></span>
<span className="font-medium">
<span className="font-medium text-sm">
{route.to}
</span>
</div>
<div className="text-xs text-white/60">
<div className="text-xs text-white/60 hidden sm:block">
{route.fromAddress} {route.toAddress}
</div>
</div>
</td>
<td className="p-4">
<span className="text-white/80">
<td className="p-2 hidden lg:table-cell"></td>
<td className="p-2">
<span className="text-white/80 text-sm">
{route.wholesalers.reduce(
(sum, w) =>
sum +
@ -537,8 +534,8 @@ export function FulfillmentGoodsTab() {
)}
</span>
</td>
<td className="p-4">
<span className="text-white/80">
<td className="p-2">
<span className="text-white/80 text-sm">
{route.wholesalers.reduce(
(sum, w) =>
sum +
@ -550,8 +547,8 @@ export function FulfillmentGoodsTab() {
)}
</span>
</td>
<td className="p-4">
<span className="text-white/80">
<td className="p-2">
<span className="text-white/80 text-sm">
{route.wholesalers.reduce(
(sum, w) =>
sum +
@ -563,29 +560,29 @@ export function FulfillmentGoodsTab() {
)}
</span>
</td>
<td className="p-4">
<span className="text-green-400 font-medium">
<td className="p-2">
<span className="text-green-400 font-medium text-sm">
{formatCurrency(route.totalProductPrice)}
</span>
</td>
<td className="p-4">
<span className="text-blue-400 font-medium">
<td className="p-2 hidden lg:table-cell">
<span className="text-blue-400 font-medium text-sm">
{formatCurrency(
route.fulfillmentServicePrice
)}
</span>
</td>
<td className="p-4">
<span className="text-purple-400 font-medium">
<td className="p-2 hidden lg:table-cell">
<span className="text-purple-400 font-medium text-sm">
{formatCurrency(route.logisticsPrice)}
</span>
</td>
<td className="p-4">
<span className="text-white font-semibold">
<td className="p-2">
<span className="text-white font-semibold text-sm">
{formatCurrency(route.totalAmount)}
</span>
</td>
<td className="p-4"></td>
<td className="p-2"></td>
</tr>
{/* Остальные уровни развертывания аналогично */}
@ -595,73 +592,66 @@ export function FulfillmentGoodsTab() {
expandedWholesalers.has(wholesaler.id);
return (
<React.Fragment key={wholesaler.id}>
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-green-500/10">
<td className="p-4 pl-20">
<tr
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-green-500/10 cursor-pointer"
onClick={() =>
toggleWholesalerExpansion(wholesaler.id)
}
>
<td className="p-2 relative">
<div className="flex items-center space-x-2">
<Button
variant="ghost"
size="sm"
onClick={() =>
toggleWholesalerExpansion(
wholesaler.id
)
}
className="h-6 w-6 p-0 text-white/60 hover:text-white hover:bg-white/10"
>
{isWholesalerExpanded ? (
<ChevronDown className="h-4 w-4" />
) : (
<ChevronRight className="h-4 w-4" />
)}
</Button>
<Building2 className="h-4 w-4 text-green-400" />
<span className="text-white font-medium">
<div className="w-1 h-1 rounded-full bg-green-400 mr-1"></div>
<div className="w-1 h-1 rounded-full bg-green-400 mr-1"></div>
<Building2 className="h-3 w-3 text-green-400" />
<span className="text-white font-medium text-sm">
Оптовик
</span>
</div>
<div className="absolute left-0 top-0 w-0.5 h-full bg-green-400/30"></div>
</td>
<td className="p-4" colSpan={2}>
<td className="p-2" colSpan={1}>
<div className="text-white">
<div className="font-medium mb-1">
<div className="font-medium mb-1 text-sm">
{wholesaler.name}
</div>
<div className="text-xs text-white/60 mb-1">
<div className="text-xs text-white/60 mb-1 hidden sm:block">
ИНН: {wholesaler.inn}
</div>
<div className="text-xs text-white/60 mb-1">
<div className="text-xs text-white/60 mb-1 hidden lg:block">
{wholesaler.address}
</div>
<div className="text-xs text-white/60">
<div className="text-xs text-white/60 hidden sm:block">
{wholesaler.contact}
</div>
</div>
</td>
<td className="p-4">
<span className="text-white/80">
<td className="p-2 hidden lg:table-cell"></td>
<td className="p-2">
<span className="text-white/80 text-sm">
{wholesaler.products.reduce(
(sum, p) => sum + p.plannedQty,
0
)}
</span>
</td>
<td className="p-4">
<span className="text-white/80">
<td className="p-2">
<span className="text-white/80 text-sm">
{wholesaler.products.reduce(
(sum, p) => sum + p.actualQty,
0
)}
</span>
</td>
<td className="p-4">
<span className="text-white/80">
<td className="p-2">
<span className="text-white/80 text-sm">
{wholesaler.products.reduce(
(sum, p) => sum + p.defectQty,
0
)}
</span>
</td>
<td className="p-4">
<span className="text-green-400 font-medium">
<td className="p-2">
<span className="text-green-400 font-medium text-sm">
{formatCurrency(
wholesaler.products.reduce(
(sum, p) =>
@ -671,9 +661,12 @@ export function FulfillmentGoodsTab() {
)}
</span>
</td>
<td className="p-4" colSpan={2}></td>
<td className="p-4">
<span className="text-white font-semibold">
<td
className="p-2 hidden lg:table-cell"
colSpan={2}
></td>
<td className="p-2">
<span className="text-white font-semibold text-sm">
{formatCurrency(
wholesaler.totalAmount
)}
@ -689,57 +682,53 @@ export function FulfillmentGoodsTab() {
expandedProducts.has(product.id);
return (
<React.Fragment key={product.id}>
<tr className="border-b border-white/10 hover:bg-white/5 transition-colors bg-yellow-500/10">
<td className="p-4 pl-28">
<tr
className="border-b border-white/10 hover:bg-white/5 transition-colors bg-yellow-500/10 cursor-pointer"
onClick={() =>
toggleProductExpansion(
product.id
)
}
>
<td className="p-2 relative">
<div className="flex items-center space-x-2">
<Button
variant="ghost"
size="sm"
onClick={() =>
toggleProductExpansion(
product.id
)
}
className="h-6 w-6 p-0 text-white/60 hover:text-white hover:bg-white/10"
>
{isProductExpanded ? (
<ChevronDown className="h-4 w-4" />
) : (
<ChevronRight className="h-4 w-4" />
)}
</Button>
<Package className="h-4 w-4 text-yellow-400" />
<span className="text-white font-medium">
<div className="w-1 h-1 rounded-full bg-yellow-400 mr-1"></div>
<div className="w-1 h-1 rounded-full bg-yellow-400 mr-1"></div>
<div className="w-1 h-1 rounded-full bg-yellow-400 mr-1"></div>
<Package className="h-3 w-3 text-yellow-400" />
<span className="text-white font-medium text-sm">
Товар
</span>
</div>
<div className="absolute left-0 top-0 w-0.5 h-full bg-yellow-400/30"></div>
</td>
<td className="p-4" colSpan={2}>
<td className="p-2" colSpan={1}>
<div className="text-white">
<div className="font-medium mb-1">
<div className="font-medium mb-1 text-sm">
{product.name}
</div>
<div className="text-xs text-white/60 mb-1">
<div className="text-xs text-white/60 mb-1 hidden sm:block">
Артикул: {product.sku}
</div>
<Badge className="bg-gray-500/20 text-gray-300 border-gray-500/30 border text-xs">
<Badge className="bg-gray-500/20 text-gray-300 border-gray-500/30 border text-xs hidden sm:inline-flex">
{product.category}
</Badge>
</div>
</td>
<td className="p-4">
<span className="text-white font-semibold">
<td className="p-2 hidden lg:table-cell"></td>
<td className="p-2">
<span className="text-white font-semibold text-sm">
{product.plannedQty}
</span>
</td>
<td className="p-4">
<span className="text-white font-semibold">
<td className="p-2">
<span className="text-white font-semibold text-sm">
{product.actualQty}
</span>
</td>
<td className="p-4">
<td className="p-2">
<span
className={`font-semibold ${
className={`font-semibold text-sm ${
product.defectQty > 0
? "text-red-400"
: "text-white"
@ -748,16 +737,16 @@ export function FulfillmentGoodsTab() {
{product.defectQty}
</span>
</td>
<td className="p-4">
<td className="p-2">
<div className="text-white">
<div className="font-medium">
<div className="font-medium text-sm">
{formatCurrency(
calculateProductTotal(
product
)
)}
</div>
<div className="text-xs text-white/60">
<div className="text-xs text-white/60 hidden sm:block">
{formatCurrency(
product.productPrice
)}{" "}
@ -765,15 +754,18 @@ export function FulfillmentGoodsTab() {
</div>
</div>
</td>
<td className="p-4" colSpan={2}>
<td
className="p-2 hidden lg:table-cell"
colSpan={2}
>
{getEfficiencyBadge(
product.plannedQty,
product.actualQty,
product.defectQty
)}
</td>
<td className="p-4">
<span className="text-white font-semibold">
<td className="p-2">
<span className="text-white font-semibold text-sm">
{formatCurrency(
calculateProductTotal(
product
@ -781,7 +773,7 @@ export function FulfillmentGoodsTab() {
)}
</span>
</td>
<td className="p-4"></td>
<td className="p-2"></td>
</tr>
{/* Параметры товара */}
@ -792,7 +784,7 @@ export function FulfillmentGoodsTab() {
className="p-0"
>
<div className="bg-white/5 border-t border-white/10">
<div className="p-4 pl-36">
<div className="p-4">
<h4 className="text-white font-medium mb-3 flex items-center space-x-2">
<span className="text-xs text-white/60">
📋 Параметры товара: