Обновлены модели и компоненты для управления поставками и расходниками. Добавлены новые поля в модели SupplyOrder и соответствующие резолверы для поддержки логистики. Реализованы компоненты уведомлений для отображения статуса логистических заявок и поставок. Оптимизирован интерфейс для улучшения пользовательского опыта, добавлены логи для диагностики запросов. Обновлены GraphQL схемы и мутации для поддержки новых функциональных возможностей.
This commit is contained in:
@ -7,6 +7,11 @@ import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Sidebar } from "@/components/dashboard/sidebar";
|
||||
import { useSidebar } from "@/hooks/useSidebar";
|
||||
import { useAuth } from "@/hooks/useAuth";
|
||||
@ -15,7 +20,8 @@ import {
|
||||
GET_MY_COUNTERPARTIES,
|
||||
GET_SUPPLY_ORDERS,
|
||||
GET_WAREHOUSE_PRODUCTS,
|
||||
GET_MY_SUPPLIES, // Расходники селлеров
|
||||
GET_MY_SUPPLIES, // Расходники селлеров (старые данные заказов)
|
||||
GET_SELLER_SUPPLIES_ON_WAREHOUSE, // Расходники селлеров на складе (новый API)
|
||||
GET_MY_FULFILLMENT_SUPPLIES, // Расходники фулфилмента
|
||||
GET_FULFILLMENT_WAREHOUSE_STATS, // Статистика склада с изменениями за сутки
|
||||
} from "@/graphql/queries";
|
||||
@ -55,6 +61,7 @@ interface ProductVariant {
|
||||
defectsQuantity: number;
|
||||
sellerSuppliesPlace?: string;
|
||||
sellerSuppliesQuantity: number;
|
||||
sellerSuppliesOwners?: string[]; // Владельцы расходников
|
||||
pvzReturnsPlace?: string;
|
||||
pvzReturnsQuantity: number;
|
||||
}
|
||||
@ -72,6 +79,7 @@ interface ProductItem {
|
||||
defectsQuantity: number;
|
||||
sellerSuppliesPlace?: string;
|
||||
sellerSuppliesQuantity: number;
|
||||
sellerSuppliesOwners?: string[]; // Владельцы расходников
|
||||
pvzReturnsPlace?: string;
|
||||
pvzReturnsQuantity: number;
|
||||
// Третий уровень - варианты товара
|
||||
@ -200,13 +208,13 @@ export function FulfillmentWarehouseDashboard() {
|
||||
fetchPolicy: "cache-and-network",
|
||||
});
|
||||
|
||||
// Загружаем расходники селлеров
|
||||
// Загружаем расходники селлеров на складе фулфилмента
|
||||
const {
|
||||
data: suppliesData,
|
||||
loading: suppliesLoading,
|
||||
error: suppliesError,
|
||||
refetch: refetchSupplies,
|
||||
} = useQuery(GET_MY_SUPPLIES, {
|
||||
data: sellerSuppliesData,
|
||||
loading: sellerSuppliesLoading,
|
||||
error: sellerSuppliesError,
|
||||
refetch: refetchSellerSupplies,
|
||||
} = useQuery(GET_SELLER_SUPPLIES_ON_WAREHOUSE, {
|
||||
fetchPolicy: "cache-and-network",
|
||||
});
|
||||
|
||||
@ -246,8 +254,10 @@ export function FulfillmentWarehouseDashboard() {
|
||||
goods: warehouseStatsData.fulfillmentWarehouseStats.goods,
|
||||
defects: warehouseStatsData.fulfillmentWarehouseStats.defects,
|
||||
pvzReturns: warehouseStatsData.fulfillmentWarehouseStats.pvzReturns,
|
||||
fulfillmentSupplies: warehouseStatsData.fulfillmentWarehouseStats.fulfillmentSupplies,
|
||||
sellerSupplies: warehouseStatsData.fulfillmentWarehouseStats.sellerSupplies,
|
||||
fulfillmentSupplies:
|
||||
warehouseStatsData.fulfillmentWarehouseStats.fulfillmentSupplies,
|
||||
sellerSupplies:
|
||||
warehouseStatsData.fulfillmentWarehouseStats.sellerSupplies,
|
||||
});
|
||||
}
|
||||
|
||||
@ -258,7 +268,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
);
|
||||
const supplyOrders: SupplyOrder[] = ordersData?.supplyOrders || [];
|
||||
const allProducts = productsData?.warehouseProducts || [];
|
||||
const mySupplies = suppliesData?.mySupplies || []; // Расходники селлеров
|
||||
const sellerSupplies = sellerSuppliesData?.sellerSuppliesOnWarehouse || []; // Расходники селлеров на складе
|
||||
const myFulfillmentSupplies =
|
||||
fulfillmentSuppliesData?.myFulfillmentSupplies || []; // Расходники фулфилмента
|
||||
|
||||
@ -276,8 +286,8 @@ export function FulfillmentWarehouseDashboard() {
|
||||
deliveredOrders: supplyOrders.filter((o) => o.status === "DELIVERED")
|
||||
.length,
|
||||
productsCount: allProducts.length,
|
||||
suppliesCount: mySupplies.length, // Добавляем логирование расходников
|
||||
supplies: mySupplies.map((s: any) => ({
|
||||
suppliesCount: sellerSupplies.length, // Добавляем логирование расходников
|
||||
supplies: sellerSupplies.map((s: any) => ({
|
||||
id: s.id,
|
||||
name: s.name,
|
||||
currentStock: s.currentStock,
|
||||
@ -293,7 +303,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
})),
|
||||
// Добавляем анализ соответствия товаров и расходников
|
||||
productSupplyMatching: allProducts.map((product: any) => {
|
||||
const matchingSupply = mySupplies.find((supply: any) => {
|
||||
const matchingSupply = sellerSupplies.find((supply: any) => {
|
||||
return (
|
||||
supply.name.toLowerCase() === product.name.toLowerCase() ||
|
||||
supply.name
|
||||
@ -311,11 +321,11 @@ export function FulfillmentWarehouseDashboard() {
|
||||
counterpartiesLoading,
|
||||
ordersLoading,
|
||||
productsLoading,
|
||||
suppliesLoading, // Добавляем статус загрузки расходников
|
||||
sellerSuppliesLoading, // Добавляем статус загрузки расходников селлеров
|
||||
counterpartiesError: counterpartiesError?.message,
|
||||
ordersError: ordersError?.message,
|
||||
productsError: productsError?.message,
|
||||
suppliesError: suppliesError?.message, // Добавляем ошибки загрузки расходников
|
||||
sellerSuppliesError: sellerSuppliesError?.message, // Добавляем ошибки загрузки расходников селлеров
|
||||
});
|
||||
|
||||
// Расчет поступлений расходников за сутки (выносим отдельно для использования в storeData)
|
||||
@ -408,7 +418,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
console.log("📊 Статистика расходников селлера:", {
|
||||
suppliesReceivedToday,
|
||||
suppliesUsedToday,
|
||||
totalSellerSupplies: mySupplies.reduce(
|
||||
totalSellerSupplies: sellerSupplies.reduce(
|
||||
(sum: number, supply: any) => sum + (supply.currentStock || 0),
|
||||
0
|
||||
),
|
||||
@ -418,7 +428,10 @@ export function FulfillmentWarehouseDashboard() {
|
||||
// Получаем статистику склада из GraphQL (с реальными изменениями за сутки)
|
||||
const warehouseStats: WarehouseStats = useMemo(() => {
|
||||
// Если данные еще загружаются, возвращаем нули
|
||||
if (warehouseStatsLoading || !warehouseStatsData?.fulfillmentWarehouseStats) {
|
||||
if (
|
||||
warehouseStatsLoading ||
|
||||
!warehouseStatsData?.fulfillmentWarehouseStats
|
||||
) {
|
||||
return {
|
||||
products: { current: 0, change: 0 },
|
||||
goods: { current: 0, change: 0 },
|
||||
@ -511,26 +524,64 @@ export function FulfillmentWarehouseDashboard() {
|
||||
}
|
||||
});
|
||||
|
||||
// Группируем расходники по названию
|
||||
const groupedSupplies = new Map<string, number>();
|
||||
mySupplies.forEach((supply: any) => {
|
||||
// ИСПРАВЛЕНО: Группируем расходники по СЕЛЛЕРУ-ВЛАДЕЛЬЦУ, а не по названию
|
||||
const suppliesByOwner = new Map<
|
||||
string,
|
||||
Map<string, { quantity: number; ownerName: string }>
|
||||
>();
|
||||
|
||||
sellerSupplies.forEach((supply: any) => {
|
||||
const ownerId = supply.sellerOwner?.id;
|
||||
const ownerName =
|
||||
supply.sellerOwner?.name ||
|
||||
supply.sellerOwner?.fullName ||
|
||||
"Неизвестный селлер";
|
||||
const supplyName = supply.name;
|
||||
const currentStock = supply.currentStock || 0;
|
||||
const supplyType = supply.type;
|
||||
|
||||
if (groupedSupplies.has(supplyName)) {
|
||||
groupedSupplies.set(
|
||||
supplyName,
|
||||
groupedSupplies.get(supplyName)! + currentStock
|
||||
// ИСПРАВЛЕНО: Строгая проверка согласно правилам
|
||||
if (!ownerId || supplyType !== "SELLER_CONSUMABLES") {
|
||||
console.warn(
|
||||
"⚠️ ОТФИЛЬТРОВАН расходник в компоненте (нарушение правил):",
|
||||
{
|
||||
id: supply.id,
|
||||
name: supplyName,
|
||||
type: supplyType,
|
||||
ownerId,
|
||||
ownerName,
|
||||
reason: !ownerId
|
||||
? "нет sellerOwner.id"
|
||||
: "тип не SELLER_CONSUMABLES",
|
||||
}
|
||||
);
|
||||
return; // Пропускаем согласно ПРАВИЛУ 6 из секции 11.6
|
||||
}
|
||||
|
||||
// Инициализируем группу для селлера, если её нет
|
||||
if (!suppliesByOwner.has(ownerId)) {
|
||||
suppliesByOwner.set(ownerId, new Map());
|
||||
}
|
||||
|
||||
const ownerSupplies = suppliesByOwner.get(ownerId)!;
|
||||
|
||||
if (ownerSupplies.has(supplyName)) {
|
||||
// Суммируем количество, если расходник уже есть у этого селлера
|
||||
const existing = ownerSupplies.get(supplyName)!;
|
||||
existing.quantity += currentStock;
|
||||
} else {
|
||||
groupedSupplies.set(supplyName, currentStock);
|
||||
// Добавляем новый расходник для этого селлера
|
||||
ownerSupplies.set(supplyName, {
|
||||
quantity: currentStock,
|
||||
ownerName: ownerName,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Логирование группировки
|
||||
console.log("📊 Группировка товаров и расходников:", {
|
||||
groupedProductsCount: groupedProducts.size,
|
||||
groupedSuppliesCount: groupedSupplies.size,
|
||||
suppliesByOwnerCount: suppliesByOwner.size,
|
||||
groupedProducts: Array.from(groupedProducts.entries()).map(
|
||||
([name, data]) => ({
|
||||
name,
|
||||
@ -539,10 +590,20 @@ export function FulfillmentWarehouseDashboard() {
|
||||
uniqueSuppliers: [...new Set(data.suppliers)],
|
||||
})
|
||||
),
|
||||
groupedSupplies: Array.from(groupedSupplies.entries()).map(
|
||||
([name, quantity]) => ({
|
||||
name,
|
||||
totalQuantity: quantity,
|
||||
suppliesByOwner: Array.from(suppliesByOwner.entries()).map(
|
||||
([ownerId, ownerSupplies]) => ({
|
||||
ownerId,
|
||||
suppliesCount: ownerSupplies.size,
|
||||
totalQuantity: Array.from(ownerSupplies.values()).reduce(
|
||||
(sum, s) => sum + s.quantity,
|
||||
0
|
||||
),
|
||||
ownerName:
|
||||
Array.from(ownerSupplies.values())[0]?.ownerName || "Unknown",
|
||||
supplies: Array.from(ownerSupplies.entries()).map(([name, data]) => ({
|
||||
name,
|
||||
quantity: data.quantity,
|
||||
})),
|
||||
})
|
||||
),
|
||||
});
|
||||
@ -567,37 +628,56 @@ export function FulfillmentWarehouseDashboard() {
|
||||
const productData = groupedProducts.get(productName)!;
|
||||
const itemProducts = productData.totalQuantity;
|
||||
|
||||
// Ищем соответствующий расходник по названию
|
||||
const matchingSupplyQuantity = groupedSupplies.get(productName) || 0;
|
||||
// ИСПРАВЛЕНО: Ищем расходники конкретного селлера-владельца
|
||||
let itemSuppliesQuantity = 0;
|
||||
let suppliesOwners: string[] = [];
|
||||
|
||||
// Если нет точного совпадения, ищем частичное совпадение
|
||||
let itemSuppliesQuantity = matchingSupplyQuantity;
|
||||
if (itemSuppliesQuantity === 0) {
|
||||
for (const [supplyName, quantity] of groupedSupplies.entries()) {
|
||||
if (
|
||||
supplyName.toLowerCase().includes(productName.toLowerCase()) ||
|
||||
productName.toLowerCase().includes(supplyName.toLowerCase())
|
||||
) {
|
||||
itemSuppliesQuantity = quantity;
|
||||
break;
|
||||
// Получаем реального селлера для этого виртуального партнера
|
||||
const realSeller = sellerPartners[index];
|
||||
|
||||
if (realSeller?.id && suppliesByOwner.has(realSeller.id)) {
|
||||
const sellerSupplies = suppliesByOwner.get(realSeller.id)!;
|
||||
|
||||
// Ищем расходники этого селлера по названию товара
|
||||
const matchingSupply = sellerSupplies.get(productName);
|
||||
|
||||
if (matchingSupply) {
|
||||
itemSuppliesQuantity = matchingSupply.quantity;
|
||||
suppliesOwners = [matchingSupply.ownerName];
|
||||
} else {
|
||||
// Если нет точного совпадения, ищем частичное среди расходников ЭТОГО селлера
|
||||
for (const [supplyName, supplyData] of sellerSupplies.entries()) {
|
||||
if (
|
||||
supplyName
|
||||
.toLowerCase()
|
||||
.includes(productName.toLowerCase()) ||
|
||||
productName.toLowerCase().includes(supplyName.toLowerCase())
|
||||
) {
|
||||
itemSuppliesQuantity = supplyData.quantity;
|
||||
suppliesOwners = [supplyData.ownerName];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback к процентному соотношению
|
||||
if (itemSuppliesQuantity === 0) {
|
||||
itemSuppliesQuantity = Math.floor(itemProducts * 0.1);
|
||||
}
|
||||
// Если у этого селлера нет расходников для данного товара - оставляем 0
|
||||
// НЕ используем fallback, так как должны показывать только реальные данные
|
||||
|
||||
console.log(`📦 Товар "${productName}":`, {
|
||||
totalQuantity: itemProducts,
|
||||
suppliersCount: productData.suppliers.length,
|
||||
uniqueSuppliers: [...new Set(productData.suppliers)],
|
||||
matchingSupplyQuantity: matchingSupplyQuantity,
|
||||
finalSuppliesQuantity: itemSuppliesQuantity,
|
||||
usedFallback:
|
||||
matchingSupplyQuantity === 0 && itemSuppliesQuantity > 0,
|
||||
});
|
||||
console.log(
|
||||
`📦 Товар "${productName}" (партнер: ${
|
||||
realSeller?.name || "Unknown"
|
||||
}):`,
|
||||
{
|
||||
totalQuantity: itemProducts,
|
||||
suppliersCount: productData.suppliers.length,
|
||||
uniqueSuppliers: [...new Set(productData.suppliers)],
|
||||
sellerSuppliesQuantity: itemSuppliesQuantity,
|
||||
suppliesOwners: suppliesOwners,
|
||||
sellerId: realSeller?.id,
|
||||
hasSellerSupplies: itemSuppliesQuantity > 0,
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
id: `grouped-${productName}-${itemIndex}`, // Уникальный ID для группированного товара
|
||||
@ -615,6 +695,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
defectsQuantity: 0, // Нет реальных данных о браке
|
||||
sellerSuppliesPlace: `D${index + 1}-${itemIndex + 1}`,
|
||||
sellerSuppliesQuantity: itemSuppliesQuantity, // Суммированное количество расходников (реальные данные)
|
||||
sellerSuppliesOwners: suppliesOwners, // Владельцы расходников (ИСПРАВЛЕНО)
|
||||
pvzReturnsPlace: `E${index + 1}-${itemIndex + 1}`,
|
||||
pvzReturnsQuantity: 0, // Нет реальных данных о возвратах с ПВЗ
|
||||
// Создаем варианты товара
|
||||
@ -634,6 +715,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
sellerSuppliesQuantity: Math.floor(
|
||||
itemSuppliesQuantity * 0.4
|
||||
), // Часть от расходников
|
||||
sellerSuppliesOwners: suppliesOwners, // Владельцы расходников (ИСПРАВЛЕНО)
|
||||
pvzReturnsPlace: `E${index + 1}-${itemIndex + 1}-1`,
|
||||
pvzReturnsQuantity: 0, // Нет реальных данных о возвратах
|
||||
},
|
||||
@ -650,6 +732,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
sellerSuppliesQuantity: Math.floor(
|
||||
itemSuppliesQuantity * 0.4
|
||||
), // Часть от расходников
|
||||
sellerSuppliesOwners: suppliesOwners, // Владельцы расходников (ИСПРАВЛЕНО)
|
||||
pvzReturnsPlace: `E${index + 1}-${itemIndex + 1}-2`,
|
||||
pvzReturnsQuantity: 0, // Нет реальных данных о возвратах
|
||||
},
|
||||
@ -666,6 +749,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
sellerSuppliesQuantity: Math.floor(
|
||||
itemSuppliesQuantity * 0.2
|
||||
), // Оставшаяся часть расходников
|
||||
sellerSuppliesOwners: suppliesOwners, // Владельцы расходников (ИСПРАВЛЕНО)
|
||||
pvzReturnsPlace: `E${index + 1}-${itemIndex + 1}-3`,
|
||||
pvzReturnsQuantity: 0, // Нет реальных данных о возвратах
|
||||
},
|
||||
@ -738,7 +822,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
totalSellerSupplies > 0
|
||||
? Math.floor(
|
||||
(totalSellerSupplies /
|
||||
(mySupplies.reduce(
|
||||
(sellerSupplies.reduce(
|
||||
(sum: number, supply: any) =>
|
||||
sum + (supply.currentStock || 0),
|
||||
0
|
||||
@ -774,7 +858,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
items,
|
||||
};
|
||||
});
|
||||
}, [sellerPartners, allProducts, mySupplies, suppliesReceivedToday]);
|
||||
}, [sellerPartners, allProducts, sellerSupplies, suppliesReceivedToday]);
|
||||
|
||||
// Функции для аватаров магазинов
|
||||
const getInitials = (name: string): string => {
|
||||
@ -1007,9 +1091,14 @@ export function FulfillmentWarehouseDashboard() {
|
||||
onClick?: () => void;
|
||||
}) => {
|
||||
// Используем percentChange из GraphQL, если доступно, иначе вычисляем локально
|
||||
const displayPercentChange = percentChange !== undefined && percentChange !== null && !isNaN(percentChange)
|
||||
? percentChange
|
||||
: (current > 0 ? (change / current) * 100 : 0);
|
||||
const displayPercentChange =
|
||||
percentChange !== undefined &&
|
||||
percentChange !== null &&
|
||||
!isNaN(percentChange)
|
||||
? percentChange
|
||||
: current > 0
|
||||
? (change / current) * 100
|
||||
: 0;
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -1125,7 +1214,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
counterpartiesLoading ||
|
||||
ordersLoading ||
|
||||
productsLoading ||
|
||||
suppliesLoading
|
||||
sellerSuppliesLoading
|
||||
) {
|
||||
return (
|
||||
<div className="h-screen flex overflow-hidden">
|
||||
@ -1210,7 +1299,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
counterpartiesLoading ||
|
||||
ordersLoading ||
|
||||
productsLoading ||
|
||||
suppliesLoading
|
||||
sellerSuppliesLoading
|
||||
}
|
||||
>
|
||||
<RotateCcw className="h-3 w-3 mr-1" />
|
||||
@ -1224,7 +1313,10 @@ export function FulfillmentWarehouseDashboard() {
|
||||
icon={Box}
|
||||
current={warehouseStats.products.current}
|
||||
change={warehouseStats.products.change}
|
||||
percentChange={warehouseStatsData?.fulfillmentWarehouseStats?.products?.percentChange}
|
||||
percentChange={
|
||||
warehouseStatsData?.fulfillmentWarehouseStats?.products
|
||||
?.percentChange
|
||||
}
|
||||
description="Готовые к отправке"
|
||||
/>
|
||||
<StatCard
|
||||
@ -1232,7 +1324,10 @@ export function FulfillmentWarehouseDashboard() {
|
||||
icon={Package}
|
||||
current={warehouseStats.goods.current}
|
||||
change={warehouseStats.goods.change}
|
||||
percentChange={warehouseStatsData?.fulfillmentWarehouseStats?.goods?.percentChange}
|
||||
percentChange={
|
||||
warehouseStatsData?.fulfillmentWarehouseStats?.goods
|
||||
?.percentChange
|
||||
}
|
||||
description="В обработке"
|
||||
/>
|
||||
<StatCard
|
||||
@ -1240,7 +1335,10 @@ export function FulfillmentWarehouseDashboard() {
|
||||
icon={AlertTriangle}
|
||||
current={warehouseStats.defects.current}
|
||||
change={warehouseStats.defects.change}
|
||||
percentChange={warehouseStatsData?.fulfillmentWarehouseStats?.defects?.percentChange}
|
||||
percentChange={
|
||||
warehouseStatsData?.fulfillmentWarehouseStats?.defects
|
||||
?.percentChange
|
||||
}
|
||||
description="Требует утилизации"
|
||||
/>
|
||||
<StatCard
|
||||
@ -1248,7 +1346,10 @@ export function FulfillmentWarehouseDashboard() {
|
||||
icon={RotateCcw}
|
||||
current={warehouseStats.pvzReturns.current}
|
||||
change={warehouseStats.pvzReturns.change}
|
||||
percentChange={warehouseStatsData?.fulfillmentWarehouseStats?.pvzReturns?.percentChange}
|
||||
percentChange={
|
||||
warehouseStatsData?.fulfillmentWarehouseStats?.pvzReturns
|
||||
?.percentChange
|
||||
}
|
||||
description="К обработке"
|
||||
/>
|
||||
<StatCard
|
||||
@ -1256,7 +1357,10 @@ export function FulfillmentWarehouseDashboard() {
|
||||
icon={Wrench}
|
||||
current={warehouseStats.fulfillmentSupplies.current}
|
||||
change={warehouseStats.fulfillmentSupplies.change}
|
||||
percentChange={warehouseStatsData?.fulfillmentWarehouseStats?.fulfillmentSupplies?.percentChange}
|
||||
percentChange={
|
||||
warehouseStatsData?.fulfillmentWarehouseStats
|
||||
?.fulfillmentSupplies?.percentChange
|
||||
}
|
||||
description="Расходники, этикетки"
|
||||
onClick={() => router.push("/fulfillment-warehouse/supplies")}
|
||||
/>
|
||||
@ -1265,7 +1369,10 @@ export function FulfillmentWarehouseDashboard() {
|
||||
icon={Users}
|
||||
current={warehouseStats.sellerSupplies.current}
|
||||
change={warehouseStats.sellerSupplies.change}
|
||||
percentChange={warehouseStatsData?.fulfillmentWarehouseStats?.sellerSupplies?.percentChange}
|
||||
percentChange={
|
||||
warehouseStatsData?.fulfillmentWarehouseStats?.sellerSupplies
|
||||
?.percentChange
|
||||
}
|
||||
description="Материалы клиентов"
|
||||
/>
|
||||
</div>
|
||||
@ -1935,11 +2042,43 @@ export function FulfillmentWarehouseDashboard() {
|
||||
|
||||
{/* Расходники селлера */}
|
||||
<div className="grid grid-cols-2 gap-0">
|
||||
<div className="px-1 py-2 text-center text-xs text-white font-medium">
|
||||
{formatNumber(
|
||||
item.sellerSuppliesQuantity
|
||||
)}
|
||||
</div>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<div className="px-1 py-2 text-center text-xs text-white font-medium cursor-help hover:bg-white/10 rounded">
|
||||
{formatNumber(
|
||||
item.sellerSuppliesQuantity
|
||||
)}
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-64 glass-card">
|
||||
<div className="text-xs">
|
||||
<div className="font-medium mb-2 text-white">
|
||||
Расходники селлеров:
|
||||
</div>
|
||||
{item.sellerSuppliesOwners &&
|
||||
item.sellerSuppliesOwners.length >
|
||||
0 ? (
|
||||
<div className="space-y-1">
|
||||
{item.sellerSuppliesOwners.map(
|
||||
(owner, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="text-white/80 flex items-center"
|
||||
>
|
||||
<div className="w-2 h-2 bg-purple-500 rounded-full mr-2 flex-shrink-0"></div>
|
||||
{owner}
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-white/60">
|
||||
Нет данных о владельцах
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<div className="px-1 py-2 text-center text-xs text-white/60">
|
||||
{item.sellerSuppliesPlace || "-"}
|
||||
</div>
|
||||
@ -2065,11 +2204,45 @@ export function FulfillmentWarehouseDashboard() {
|
||||
|
||||
{/* Расходники селлера */}
|
||||
<div className="grid grid-cols-2 gap-0">
|
||||
<div className="px-1 py-1.5 text-center text-[10px] text-white font-medium">
|
||||
{formatNumber(
|
||||
variant.sellerSuppliesQuantity
|
||||
)}
|
||||
</div>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<div className="px-1 py-1.5 text-center text-[10px] text-white font-medium cursor-help hover:bg-white/10 rounded">
|
||||
{formatNumber(
|
||||
variant.sellerSuppliesQuantity
|
||||
)}
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-64 glass-card">
|
||||
<div className="text-xs">
|
||||
<div className="font-medium mb-2 text-white">
|
||||
Расходники селлеров:
|
||||
</div>
|
||||
{variant.sellerSuppliesOwners &&
|
||||
variant
|
||||
.sellerSuppliesOwners
|
||||
.length > 0 ? (
|
||||
<div className="space-y-1">
|
||||
{variant.sellerSuppliesOwners.map(
|
||||
(owner, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="text-white/80 flex items-center"
|
||||
>
|
||||
<div className="w-2 h-2 bg-purple-500 rounded-full mr-2 flex-shrink-0"></div>
|
||||
{owner}
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-white/60">
|
||||
Нет данных о
|
||||
владельцах
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<div className="px-1 py-1.5 text-center text-[10px] text-white/60">
|
||||
{variant.sellerSuppliesPlace ||
|
||||
"-"}
|
||||
|
Reference in New Issue
Block a user