Объединены файлы правил системы в единую базу знаний v3.0 с устранением противоречий и дублирования. Создан rules-unified.md на основе rules.md, rules1.md и rules2.md с добавлением всех уникальных разделов. Обновлена терминология системы с соответствием реальной схеме БД (ТОВАР→PRODUCT, РАСХОДНИКИ→CONSUMABLE). Архивированы старые файлы правил в папку archive. Обновлены ссылки в CLAUDE.md и development-checklist.md на новый единый источник истины.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Veronika Smirnova
2025-08-05 00:19:17 +03:00
parent 17ffd6c9ed
commit ee72a9488b
21 changed files with 9147 additions and 174 deletions

View File

@ -0,0 +1,735 @@
"use client";
import React, { useState } from "react";
import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import {
Package,
Building2,
Calendar,
DollarSign,
Search,
Filter,
ChevronDown,
ChevronRight,
Smartphone,
Eye,
MoreHorizontal,
MapPin,
TrendingUp,
AlertTriangle,
Warehouse,
} from "lucide-react";
import { formatCurrency } from "@/lib/utils";
// Простые компоненты таблицы
const Table = ({ children, ...props }: any) => (
<div className="w-full overflow-auto" {...props}>
<table className="w-full">{children}</table>
</div>
);
const TableHeader = ({ children, ...props }: any) => <thead {...props}>{children}</thead>;
const TableBody = ({ children, ...props }: any) => <tbody {...props}>{children}</tbody>;
const TableRow = ({ children, className, ...props }: any) => (
<tr className={className} {...props}>{children}</tr>
);
const TableHead = ({ children, className, ...props }: any) => (
<th className={`px-4 py-3 text-left font-medium ${className}`} {...props}>{children}</th>
);
const TableCell = ({ children, className, ...props }: any) => (
<td className={`px-4 py-3 ${className}`} {...props}>{children}</td>
);
// Расширенные типы данных для детальной структуры поставок
interface ProductParameter {
id: string;
name: string;
value: string;
unit?: string;
}
interface GoodsSupplyProduct {
id: string;
name: string;
sku: string;
category: string;
plannedQty: number;
actualQty: number;
defectQty: number;
productPrice: number;
parameters: ProductParameter[];
}
interface GoodsSupplyWholesaler {
id: string;
name: string;
inn: string;
contact: string;
address: string;
products: GoodsSupplyProduct[];
totalAmount: number;
}
interface GoodsSupplyRoute {
id: string;
from: string;
fromAddress: string;
to: string;
toAddress: string;
wholesalers: GoodsSupplyWholesaler[];
totalProductPrice: number;
fulfillmentServicePrice: number;
logisticsPrice: number;
totalAmount: number;
}
// Основной интерфейс поставки товаров согласно rules2.md 9.5.4
interface GoodsSupply {
id: string;
number: string;
creationMethod: 'cards' | 'suppliers'; // 📱 карточки / 🏢 поставщик
deliveryDate: string;
createdAt: string;
status: string;
// Агрегированные данные
plannedTotal: number;
actualTotal: number;
defectTotal: number;
totalProductPrice: number;
totalFulfillmentPrice: number;
totalLogisticsPrice: number;
grandTotal: number;
// Детальная структура
routes: GoodsSupplyRoute[];
// Для обратной совместимости
goodsCount?: number;
totalAmount?: number;
supplier?: string;
items?: GoodsSupplyItem[];
}
// Простой интерфейс товара для базовой детализации
interface GoodsSupplyItem {
id: string;
name: string;
quantity: number;
price: number;
category?: string;
}
interface GoodsSuppliesTableProps {
supplies?: GoodsSupply[];
loading?: boolean;
}
// Компонент для иконки способа создания
function CreationMethodIcon({ method }: { method: 'cards' | 'suppliers' }) {
if (method === 'cards') {
return (
<div className="flex items-center gap-1 text-blue-400">
<Smartphone className="h-3 w-3" />
<span className="text-xs hidden sm:inline">Карточки</span>
</div>
);
}
return (
<div className="flex items-center gap-1 text-green-400">
<Building2 className="h-3 w-3" />
<span className="text-xs hidden sm:inline">Поставщик</span>
</div>
);
}
// Компонент для статуса поставки
function StatusBadge({ status }: { status: string }) {
const getStatusColor = (status: string) => {
switch (status.toLowerCase()) {
case 'pending': return 'bg-yellow-500/20 text-yellow-300 border-yellow-500/30';
case 'supplier_approved': return 'bg-blue-500/20 text-blue-300 border-blue-500/30';
case 'confirmed': return 'bg-purple-500/20 text-purple-300 border-purple-500/30';
case 'shipped': return 'bg-orange-500/20 text-orange-300 border-orange-500/30';
case 'in_transit': return 'bg-indigo-500/20 text-indigo-300 border-indigo-500/30';
case 'delivered': return 'bg-green-500/20 text-green-300 border-green-500/30';
default: return 'bg-gray-500/20 text-gray-300 border-gray-500/30';
}
};
const getStatusText = (status: string) => {
switch (status.toLowerCase()) {
case 'pending': return 'Ожидает';
case 'supplier_approved': return 'Одобрена';
case 'confirmed': return 'Подтверждена';
case 'shipped': return 'Отгружена';
case 'in_transit': return 'В пути';
case 'delivered': return 'Доставлена';
default: return status;
}
};
return (
<Badge className={`${getStatusColor(status)} border text-xs`}>
{getStatusText(status)}
</Badge>
);
}
export function GoodsSuppliesTable({ supplies = [], loading = false }: GoodsSuppliesTableProps) {
const [searchQuery, setSearchQuery] = useState("");
const [selectedMethod, setSelectedMethod] = useState<string>("all");
const [selectedStatus, setSelectedStatus] = useState<string>("all");
const [expandedSupplies, setExpandedSupplies] = useState<Set<string>>(new Set());
const [expandedRoutes, setExpandedRoutes] = useState<Set<string>>(new Set());
const [expandedWholesalers, setExpandedWholesalers] = useState<Set<string>>(new Set());
const [expandedProducts, setExpandedProducts] = useState<Set<string>>(new Set());
// Фильтрация согласно rules2.md 9.5.4 с поддержкой расширенной структуры
const filteredSupplies = supplies.filter(supply => {
const matchesSearch = supply.number.toLowerCase().includes(searchQuery.toLowerCase()) ||
(supply.supplier && supply.supplier.toLowerCase().includes(searchQuery.toLowerCase())) ||
(supply.routes && supply.routes.some(route =>
route.wholesalers.some(wholesaler =>
wholesaler.name.toLowerCase().includes(searchQuery.toLowerCase())
)
));
const matchesMethod = selectedMethod === "all" || supply.creationMethod === selectedMethod;
const matchesStatus = selectedStatus === "all" || supply.status === selectedStatus;
return matchesSearch && matchesMethod && matchesStatus;
});
const toggleSupplyExpansion = (supplyId: string) => {
const newExpanded = new Set(expandedSupplies);
if (newExpanded.has(supplyId)) {
newExpanded.delete(supplyId);
} else {
newExpanded.add(supplyId);
}
setExpandedSupplies(newExpanded);
};
const toggleRouteExpansion = (routeId: string) => {
const newExpanded = new Set(expandedRoutes);
if (newExpanded.has(routeId)) {
newExpanded.delete(routeId);
} else {
newExpanded.add(routeId);
}
setExpandedRoutes(newExpanded);
};
const toggleWholesalerExpansion = (wholesalerId: string) => {
const newExpanded = new Set(expandedWholesalers);
if (newExpanded.has(wholesalerId)) {
newExpanded.delete(wholesalerId);
} else {
newExpanded.add(wholesalerId);
}
setExpandedWholesalers(newExpanded);
};
const toggleProductExpansion = (productId: string) => {
const newExpanded = new Set(expandedProducts);
if (newExpanded.has(productId)) {
newExpanded.delete(productId);
} else {
newExpanded.add(productId);
}
setExpandedProducts(newExpanded);
};
// Вспомогательные функции
const getStatusBadge = (status: string) => {
const statusMap = {
pending: { label: "Ожидает", color: "bg-yellow-500/20 text-yellow-300 border-yellow-500/30" },
supplier_approved: { label: "Одобрена", color: "bg-blue-500/20 text-blue-300 border-blue-500/30" },
confirmed: { label: "Подтверждена", color: "bg-purple-500/20 text-purple-300 border-purple-500/30" },
shipped: { label: "Отгружена", color: "bg-orange-500/20 text-orange-300 border-orange-500/30" },
in_transit: { label: "В пути", color: "bg-indigo-500/20 text-indigo-300 border-indigo-500/30" },
delivered: { label: "Доставлена", color: "bg-green-500/20 text-green-300 border-green-500/30" },
planned: { label: "Запланирована", color: "bg-blue-500/20 text-blue-300 border-blue-500/30" },
completed: { label: "Завершена", color: "bg-purple-500/20 text-purple-300 border-purple-500/30" },
};
const statusInfo = statusMap[status as keyof typeof statusMap] || { label: status, color: "bg-gray-500/20 text-gray-300 border-gray-500/30" };
return <Badge className={`${statusInfo.color} border`}>{statusInfo.label}</Badge>;
};
const getEfficiencyBadge = (planned: number, actual: number, defect: number) => {
const efficiency = ((actual - defect) / planned) * 100;
if (efficiency >= 95) {
return <Badge className="bg-green-500/20 text-green-300 border-green-500/30 border">Отлично</Badge>;
} else if (efficiency >= 90) {
return <Badge className="bg-yellow-500/20 text-yellow-300 border-yellow-500/30 border">Хорошо</Badge>;
} else {
return <Badge className="bg-red-500/20 text-red-300 border-red-500/30 border">Проблемы</Badge>;
}
};
const calculateProductTotal = (product: GoodsSupplyProduct) => {
return product.actualQty * product.productPrice;
};
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString("ru-RU", {
day: "2-digit",
month: "2-digit",
year: "numeric",
});
};
if (loading) {
return (
<Card className="bg-white/10 backdrop-blur border-white/20 p-6">
<div className="animate-pulse space-y-4">
<div className="h-4 bg-white/10 rounded w-1/4"></div>
<div className="space-y-2">
{[...Array(5)].map((_, i) => (
<div key={i} className="h-12 bg-white/5 rounded"></div>
))}
</div>
</div>
</Card>
);
}
return (
<div className="space-y-4">
{/* Фильтры */}
<Card className="bg-white/5 backdrop-blur border-white/10 p-4">
<div className="flex flex-col sm:flex-row gap-4">
{/* Поиск */}
<div className="relative flex-1">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-white/40 h-4 w-4" />
<Input
placeholder="Поиск по номеру или поставщику..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="bg-white/10 border-white/20 text-white placeholder-white/50 pl-10"
/>
</div>
{/* Фильтр по способу создания */}
<select
value={selectedMethod}
onChange={(e) => setSelectedMethod(e.target.value)}
className="bg-white/10 border border-white/20 text-white rounded-md px-3 py-2 text-sm"
>
<option value="all">Все способы</option>
<option value="cards">Карточки</option>
<option value="suppliers">Поставщики</option>
</select>
{/* Фильтр по статусу */}
<select
value={selectedStatus}
onChange={(e) => setSelectedStatus(e.target.value)}
className="bg-white/10 border border-white/20 text-white rounded-md px-3 py-2 text-sm"
>
<option value="all">Все статусы</option>
<option value="pending">Ожидает</option>
<option value="supplier_approved">Одобрена</option>
<option value="confirmed">Подтверждена</option>
<option value="shipped">Отгружена</option>
<option value="in_transit">В пути</option>
<option value="delivered">Доставлена</option>
</select>
</div>
</Card>
{/* Таблица поставок согласно rules2.md 9.5.4 */}
<Card className="bg-white/10 backdrop-blur border-white/20 overflow-hidden">
<Table>
<TableHeader>
<TableRow className="border-white/10 hover:bg-white/5">
<TableHead className="text-white/70"></TableHead>
<TableHead className="text-white/70">
<span className="hidden sm:inline">Дата поставки</span>
<span className="sm:hidden">Поставка</span>
</TableHead>
<TableHead className="text-white/70 hidden lg:table-cell">Создана</TableHead>
<TableHead className="text-white/70">План</TableHead>
<TableHead className="text-white/70">Факт</TableHead>
<TableHead className="text-white/70">Брак</TableHead>
<TableHead className="text-white/70">
<span className="hidden md:inline">Цена товаров</span>
<span className="md:hidden">Цена</span>
</TableHead>
<TableHead className="text-white/70 hidden lg:table-cell">ФФ</TableHead>
<TableHead className="text-white/70 hidden lg:table-cell">Логистика</TableHead>
<TableHead className="text-white/70">Итого</TableHead>
<TableHead className="text-white/70">Статус</TableHead>
<TableHead className="text-white/70">Способ</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{filteredSupplies.length === 0 ? (
<TableRow>
<TableCell colSpan={12} className="text-center py-8 text-white/60">
{searchQuery || selectedMethod !== "all" || selectedStatus !== "all"
? "Поставки не найдены по заданным фильтрам"
: "Поставки товаров отсутствуют"
}
</TableCell>
</TableRow>
) : (
filteredSupplies.map((supply) => {
const isSupplyExpanded = expandedSupplies.has(supply.id);
return (
<React.Fragment key={supply.id}>
{/* Основная строка поставки */}
<TableRow
className="border-white/10 hover:bg-white/5 cursor-pointer transition-colors bg-purple-500/10"
onClick={() => toggleSupplyExpansion(supply.id)}
>
<TableCell className="text-white font-mono text-sm">
<div className="flex items-center gap-2">
{isSupplyExpanded ? (
<ChevronDown className="h-4 w-4 text-white/40" />
) : (
<ChevronRight className="h-4 w-4 text-white/40" />
)}
{supply.number}
</div>
</TableCell>
<TableCell>
<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>
</TableCell>
<TableCell className="hidden lg:table-cell">
<span className="text-white/80 text-sm">
{formatDate(supply.createdAt)}
</span>
</TableCell>
<TableCell>
<span className="text-white font-semibold text-sm">
{supply.plannedTotal || supply.goodsCount || 0}
</span>
</TableCell>
<TableCell>
<span className="text-white font-semibold text-sm">
{supply.actualTotal || supply.goodsCount || 0}
</span>
</TableCell>
<TableCell>
<span className={`font-semibold text-sm ${
(supply.defectTotal || 0) > 0 ? "text-red-400" : "text-white"
}`}>
{supply.defectTotal || 0}
</span>
</TableCell>
<TableCell>
<span className="text-green-400 font-semibold text-sm">
{formatCurrency(supply.totalProductPrice || supply.totalAmount || 0)}
</span>
</TableCell>
<TableCell className="hidden lg:table-cell">
<span className="text-blue-400 font-semibold text-sm">
{formatCurrency(supply.totalFulfillmentPrice || 0)}
</span>
</TableCell>
<TableCell className="hidden lg:table-cell">
<span className="text-purple-400 font-semibold text-sm">
{formatCurrency(supply.totalLogisticsPrice || 0)}
</span>
</TableCell>
<TableCell>
<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 || supply.totalAmount || 0)}
</span>
</div>
</TableCell>
<TableCell>
{getStatusBadge(supply.status)}
</TableCell>
<TableCell>
<CreationMethodIcon method={supply.creationMethod} />
</TableCell>
</TableRow>
{/* Развернутые уровни - маршруты, поставщики, товары */}
{isSupplyExpanded && supply.routes && supply.routes.map((route) => {
const isRouteExpanded = expandedRoutes.has(route.id);
return (
<React.Fragment key={route.id}>
<TableRow
className="border-white/10 hover:bg-white/5 cursor-pointer transition-colors bg-blue-500/10"
onClick={() => toggleRouteExpansion(route.id)}
>
<TableCell className="relative">
<div className="flex items-center space-x-2">
<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>
</TableCell>
<TableCell colSpan={1}>
<div className="text-white">
<div className="flex items-center space-x-2 mb-1">
<span className="font-medium text-sm">{route.from}</span>
<span className="text-white/60"></span>
<span className="font-medium text-sm">{route.to}</span>
</div>
<div className="text-xs text-white/60 hidden sm:block">
{route.fromAddress} {route.toAddress}
</div>
</div>
</TableCell>
<TableCell className="hidden lg:table-cell"></TableCell>
<TableCell>
<span className="text-white/80 text-sm">
{route.wholesalers.reduce((sum, w) =>
sum + w.products.reduce((pSum, p) => pSum + p.plannedQty, 0), 0
)}
</span>
</TableCell>
<TableCell>
<span className="text-white/80 text-sm">
{route.wholesalers.reduce((sum, w) =>
sum + w.products.reduce((pSum, p) => pSum + p.actualQty, 0), 0
)}
</span>
</TableCell>
<TableCell>
<span className="text-white/80 text-sm">
{route.wholesalers.reduce((sum, w) =>
sum + w.products.reduce((pSum, p) => pSum + p.defectQty, 0), 0
)}
</span>
</TableCell>
<TableCell>
<span className="text-green-400 font-medium text-sm">
{formatCurrency(route.totalProductPrice)}
</span>
</TableCell>
<TableCell className="hidden lg:table-cell">
<span className="text-blue-400 font-medium text-sm">
{formatCurrency(route.fulfillmentServicePrice)}
</span>
</TableCell>
<TableCell className="hidden lg:table-cell">
<span className="text-purple-400 font-medium text-sm">
{formatCurrency(route.logisticsPrice)}
</span>
</TableCell>
<TableCell>
<span className="text-white font-semibold text-sm">
{formatCurrency(route.totalAmount)}
</span>
</TableCell>
<TableCell colSpan={2}></TableCell>
</TableRow>
{/* Поставщики в маршруте */}
{isRouteExpanded && route.wholesalers.map((wholesaler) => {
const isWholesalerExpanded = expandedWholesalers.has(wholesaler.id);
return (
<React.Fragment key={wholesaler.id}>
<TableRow
className="border-white/10 hover:bg-white/5 cursor-pointer transition-colors bg-green-500/10"
onClick={() => toggleWholesalerExpansion(wholesaler.id)}
>
<TableCell className="relative">
<div className="flex items-center space-x-2">
<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>
</TableCell>
<TableCell colSpan={1}>
<div className="text-white">
<div className="font-medium mb-1 text-sm">{wholesaler.name}</div>
<div className="text-xs text-white/60 mb-1 hidden sm:block">
ИНН: {wholesaler.inn}
</div>
<div className="text-xs text-white/60 mb-1 hidden lg:block">
{wholesaler.address}
</div>
<div className="text-xs text-white/60 hidden sm:block">
{wholesaler.contact}
</div>
</div>
</TableCell>
<TableCell className="hidden lg:table-cell"></TableCell>
<TableCell>
<span className="text-white/80 text-sm">
{wholesaler.products.reduce((sum, p) => sum + p.plannedQty, 0)}
</span>
</TableCell>
<TableCell>
<span className="text-white/80 text-sm">
{wholesaler.products.reduce((sum, p) => sum + p.actualQty, 0)}
</span>
</TableCell>
<TableCell>
<span className="text-white/80 text-sm">
{wholesaler.products.reduce((sum, p) => sum + p.defectQty, 0)}
</span>
</TableCell>
<TableCell>
<span className="text-green-400 font-medium text-sm">
{formatCurrency(wholesaler.products.reduce((sum, p) => sum + calculateProductTotal(p), 0))}
</span>
</TableCell>
<TableCell className="hidden lg:table-cell" colSpan={2}></TableCell>
<TableCell>
<span className="text-white font-semibold text-sm">
{formatCurrency(wholesaler.totalAmount)}
</span>
</TableCell>
<TableCell colSpan={2}></TableCell>
</TableRow>
{/* Товары поставщика */}
{isWholesalerExpanded && wholesaler.products.map((product) => {
const isProductExpanded = expandedProducts.has(product.id);
return (
<React.Fragment key={product.id}>
<TableRow
className="border-white/10 hover:bg-white/5 cursor-pointer transition-colors bg-yellow-500/10"
onClick={() => toggleProductExpansion(product.id)}
>
<TableCell className="relative">
<div className="flex items-center space-x-2">
<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>
</TableCell>
<TableCell colSpan={1}>
<div className="text-white">
<div className="font-medium mb-1 text-sm">{product.name}</div>
<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 hidden sm:inline-flex">
{product.category}
</Badge>
</div>
</TableCell>
<TableCell className="hidden lg:table-cell"></TableCell>
<TableCell>
<span className="text-white font-semibold text-sm">{product.plannedQty}</span>
</TableCell>
<TableCell>
<span className="text-white font-semibold text-sm">{product.actualQty}</span>
</TableCell>
<TableCell>
<span className={`font-semibold text-sm ${
product.defectQty > 0 ? "text-red-400" : "text-white"
}`}>
{product.defectQty}
</span>
</TableCell>
<TableCell>
<div className="text-white">
<div className="font-medium text-sm">
{formatCurrency(calculateProductTotal(product))}
</div>
<div className="text-xs text-white/60 hidden sm:block">
{formatCurrency(product.productPrice)} за шт.
</div>
</div>
</TableCell>
<TableCell className="hidden lg:table-cell" colSpan={2}>
{getEfficiencyBadge(product.plannedQty, product.actualQty, product.defectQty)}
</TableCell>
<TableCell>
<span className="text-white font-semibold text-sm">
{formatCurrency(calculateProductTotal(product))}
</span>
</TableCell>
<TableCell colSpan={2}></TableCell>
</TableRow>
{/* Параметры товара */}
{isProductExpanded && (
<TableRow>
<TableCell colSpan={12} className="p-0">
<div className="bg-white/5 border-t border-white/10">
<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">📋 Параметры товара:</span>
</h4>
<div className="grid grid-cols-3 gap-4">
{product.parameters.map((param) => (
<div key={param.id} className="bg-white/5 rounded-lg p-3">
<div className="text-white/80 text-xs font-medium mb-1">
{param.name}
</div>
<div className="text-white text-sm">
{param.value} {param.unit || ""}
</div>
</div>
))}
</div>
</div>
</div>
</TableCell>
</TableRow>
)}
</React.Fragment>
);
})}
</React.Fragment>
);
})}
</React.Fragment>
);
})}
{/* Базовая детализация для поставок без маршрутов */}
{isSupplyExpanded && supply.items && !supply.routes && (
<TableRow>
<TableCell colSpan={12} className="bg-white/5 border-white/5">
<div className="p-4 space-y-4">
<h4 className="text-white font-medium">Детализация товаров:</h4>
<div className="grid gap-2">
{supply.items.map((item) => (
<div key={item.id} className="flex justify-between items-center py-2 px-3 bg-white/5 rounded-lg">
<div className="flex-1">
<span className="text-white text-sm">{item.name}</span>
{item.category && (
<span className="text-white/60 text-xs ml-2">({item.category})</span>
)}
</div>
<div className="flex items-center gap-4 text-sm">
<span className="text-white/80">{item.quantity} шт</span>
<span className="text-white/80">{formatCurrency(item.price)}</span>
<span className="text-white font-medium">{formatCurrency(item.price * item.quantity)}</span>
</div>
</div>
))}
</div>
</div>
</TableCell>
</TableRow>
)}
</React.Fragment>
);
})
)}
</TableBody>
</Table>
</Card>
</div>
);
}