diff --git a/src/components/BrandSelectionModal.tsx b/src/components/BrandSelectionModal.tsx index 6c754cd..aa45d9a 100644 --- a/src/components/BrandSelectionModal.tsx +++ b/src/components/BrandSelectionModal.tsx @@ -52,7 +52,7 @@ const BrandSelectionModal: React.FC = ({ return (
diff --git a/src/components/VehiclePartsSearchSection.tsx b/src/components/VehiclePartsSearchSection.tsx index 9d148a7..689adae 100644 --- a/src/components/VehiclePartsSearchSection.tsx +++ b/src/components/VehiclePartsSearchSection.tsx @@ -210,7 +210,7 @@ const VehiclePartsSearchSection: React.FC = ({
{searchType === 'quickgroups' && supportsQuickGroups && ( diff --git a/src/components/vin/KnotIn.tsx b/src/components/vin/KnotIn.tsx index c579cad..dcf5d31 100644 --- a/src/components/vin/KnotIn.tsx +++ b/src/components/vin/KnotIn.tsx @@ -1,4 +1,27 @@ -import React from "react"; +import React, { useRef, useState } from "react"; +import { useQuery } from '@apollo/client'; +import { useRouter } from 'next/router'; +import { GET_LAXIMO_UNIT_INFO, GET_LAXIMO_UNIT_IMAGE_MAP } from '@/lib/graphql'; +import BrandSelectionModal from '../BrandSelectionModal'; + +interface KnotInProps { + catalogCode: string; + vehicleId: string; + ssd?: string; + unitId: string; + unitName?: string; + parts?: Array<{ + detailid?: string; + codeonimage?: string | number; + oem?: string; + name?: string; + price?: string | number; + brand?: string; + availability?: string; + note?: string; + attributes?: Array<{ key: string; name?: string; value: string }>; + }>; +} // Функция для корректного формирования URL изображения const getImageUrl = (baseUrl: string, size: string) => { @@ -11,25 +34,138 @@ const getImageUrl = (baseUrl: string, size: string) => { .replace('%size%', size); }; -const KnotIn = ({ node }: { node: any }) => { - if (!node) return null; - let imageUrl = ''; - if (node.imageurl) { - imageUrl = getImageUrl(node.imageurl, '250'); - } else if (node.largeimageurl) { - imageUrl = node.largeimageurl; +const KnotIn: React.FC = ({ catalogCode, vehicleId, ssd, unitId, unitName, parts }) => { + const imgRef = useRef(null); + const [imageScale, setImageScale] = useState({ x: 1, y: 1 }); + const selectedImageSize = 'source'; + const [isBrandModalOpen, setIsBrandModalOpen] = useState(false); + const [selectedDetail, setSelectedDetail] = useState<{ oem: string; name: string } | null>(null); + const router = useRouter(); + + // Получаем инфо об узле (для картинки) + const { data: unitInfoData, loading: unitInfoLoading, error: unitInfoError } = useQuery( + GET_LAXIMO_UNIT_INFO, + { + variables: { catalogCode, vehicleId, unitId, ssd: ssd || '' }, + skip: !catalogCode || !vehicleId || !unitId, + errorPolicy: 'all', + } + ); + // Получаем карту координат + const { data: imageMapData, loading: imageMapLoading, error: imageMapError } = useQuery( + GET_LAXIMO_UNIT_IMAGE_MAP, + { + variables: { catalogCode, vehicleId, unitId, ssd: ssd || '' }, + skip: !catalogCode || !vehicleId || !unitId, + errorPolicy: 'all', + } + ); + + const unitInfo = unitInfoData?.laximoUnitInfo; + const coordinates = imageMapData?.laximoUnitImageMap?.coordinates || []; + const imageUrl = unitInfo?.imageurl ? getImageUrl(unitInfo.imageurl, selectedImageSize) : ''; + + // Масштабируем точки после загрузки картинки + const handleImageLoad = (e: React.SyntheticEvent) => { + const img = e.currentTarget; + if (!img.naturalWidth || !img.naturalHeight) return; + setImageScale({ + x: img.offsetWidth / img.naturalWidth, + y: img.offsetHeight / img.naturalHeight, + }); + }; + + // Клик по точке: найти part по codeonimage/detailid и открыть BrandSelectionModal + const handlePointClick = (codeonimage: string | number) => { + if (!parts) return; + console.log('Клик по точке:', codeonimage, 'Все детали:', parts); + const part = parts.find( + (p) => + (p.codeonimage && p.codeonimage.toString() === codeonimage.toString()) || + (p.detailid && p.detailid.toString() === codeonimage.toString()) + ); + console.log('Найдена деталь для точки:', part); + if (part?.oem) { + setSelectedDetail({ oem: part.oem, name: part.name || '' }); + setIsBrandModalOpen(true); + } else { + console.warn('Нет артикула (oem) для выбранной точки:', codeonimage, part); + } + }; + + // Для отладки: вывести детали и координаты + React.useEffect(() => { + console.log('KnotIn parts:', parts); + console.log('KnotIn coordinates:', coordinates); + }, [parts, coordinates]); + + if (unitInfoLoading || imageMapLoading) { + return
Загружаем схему узла...
; } + if (unitInfoError) { + return
Ошибка загрузки схемы: {unitInfoError.message}
; + } + if (!imageUrl) { + return
Нет изображения для этого узла
; + } + return ( -
- {imageUrl ? ( - {node.name - ) : ( -
- Нет изображения + <> +
+ {/* ВРЕМЕННО: выводим количество точек для быстрой проверки */} +
+ {coordinates.length} точек
- )} - {/*
{node.name}
*/} + {unitName + {/* Точки/области */} + {coordinates.map((coord: any, idx: number) => { + const scaledX = coord.x * imageScale.x; + const scaledY = coord.y * imageScale.y; + const scaledWidth = coord.width * imageScale.x; + const scaledHeight = coord.height * imageScale.y; + return ( +
{ + if (e.key === 'Enter' || e.key === ' ') handlePointClick(coord.codeonimage); + }} + className="absolute flex items-center justify-center border-2 border-red-600 bg-white rounded-full cursor-pointer" + style={{ + left: scaledX, + top: scaledY, + width: scaledWidth, + height: scaledHeight, + borderRadius: '50%', + pointerEvents: 'auto', + }} + title={coord.codeonimage} + onClick={() => handlePointClick(coord.codeonimage)} + > + + {coord.codeonimage} + +
+ ); + })}
+ {/* Модалка выбора бренда */} + setIsBrandModalOpen(false)} + articleNumber={selectedDetail?.oem || ''} + detailName={selectedDetail?.name || ''} + /> + ); }; diff --git a/src/components/vin/KnotParts.tsx b/src/components/vin/KnotParts.tsx index 1d0dffb..52b1f29 100644 --- a/src/components/vin/KnotParts.tsx +++ b/src/components/vin/KnotParts.tsx @@ -1,5 +1,6 @@ -import React from "react"; +import React, { useState } from "react"; import { useRouter } from "next/router"; +import BrandSelectionModal from '../BrandSelectionModal'; interface KnotPartsProps { parts: Array<{ @@ -13,39 +14,59 @@ interface KnotPartsProps { note?: string; attributes?: Array<{ key: string; name?: string; value: string }>; }>; + selectedCodeOnImage?: string | number; } -const KnotParts: React.FC = ({ parts }) => { - const router = useRouter(); +const KnotParts: React.FC = ({ parts, selectedCodeOnImage }) => { + const [isBrandModalOpen, setIsBrandModalOpen] = useState(false); + const [selectedDetail, setSelectedDetail] = useState<{ oem: string; name: string } | null>(null); + + const handlePriceClick = (part: any) => { + if (part.oem) { + setSelectedDetail({ oem: part.oem, name: part.name || '' }); + setIsBrandModalOpen(true); + } + }; + return ( -
- {parts.map((part, idx) => ( -
-
-
{part.codeonimage || idx + 1}
-
{part.oem}
-
-
{part.name}
-
- -
- - - +
+
{part.codeonimage || idx + 1}
+
{part.oem}
+
+
{part.name}
+
+ +
+ + + +
+
-
-
- ))} -
+ ); + })} +
+ setIsBrandModalOpen(false)} + articleNumber={selectedDetail?.oem || ''} + detailName={selectedDetail?.name || ''} + /> + ); }; diff --git a/src/pages/vehicle-search/[brand]/[vehicleId].tsx b/src/pages/vehicle-search/[brand]/[vehicleId].tsx index 2982c9f..f3c311b 100644 --- a/src/pages/vehicle-search/[brand]/[vehicleId].tsx +++ b/src/pages/vehicle-search/[brand]/[vehicleId].tsx @@ -303,7 +303,14 @@ const VehicleDetailsPage = () => {
- + {unitDetailsLoading ? (
Загружаем детали узла...
) : unitDetailsError ? ( diff --git a/src/styles/my.css b/src/styles/my.css index 4c2222d..2dce3d4 100644 --- a/src/styles/my.css +++ b/src/styles/my.css @@ -386,15 +386,17 @@ input.input-receiver:focus { color: var(--_fonts---color--light-blue-grey); } -.knotin { +/* .knotin { max-width: 100%; display: flex; align-items: stretch; } .knotin img { max-width: 100%; - object-fit: contain; /* или cover */ -} + object-fit: contain; +} */ + + .tabs-menu.w-tab-menu { scrollbar-width: none;