1 Commits

Author SHA1 Message Date
47844749eb fix1407 2025-07-14 10:45:27 +03:00
7 changed files with 95 additions and 30 deletions

View File

@ -273,6 +273,10 @@ const CoreProductCard: React.FC<CoreProductCardProps> = ({
<> <>
<div className="w-layout-hflex core-product-search-s1"> <div className="w-layout-hflex core-product-search-s1">
<div className="w-layout-vflex flex-block-48-copy"> <div className="w-layout-vflex flex-block-48-copy">
<div className="w-layout-vflex product-list-search-s1">
<div className="w-layout-vflex flex-block-48-copy">
<div className="w-layout-vflex product-list-search-s1"> <div className="w-layout-vflex product-list-search-s1">
<div className="w-layout-vflex core-product-s1"> <div className="w-layout-vflex core-product-s1">
<div className="w-layout-vflex flex-block-47"> <div className="w-layout-vflex flex-block-47">
@ -310,8 +314,6 @@ const CoreProductCard: React.FC<CoreProductCardProps> = ({
</div> </div>
)} )}
</div> </div>
<div className="w-layout-vflex flex-block-48-copy">
<div className="w-layout-vflex product-list-search-s1">
<div className="w-layout-hflex sort-list-s1"> <div className="w-layout-hflex sort-list-s1">
<div className="w-layout-hflex flex-block-49"> <div className="w-layout-hflex flex-block-49">
<div className="sort-item first">Наличие</div> <div className="sort-item first">Наличие</div>

View File

@ -88,7 +88,7 @@ const Filters: React.FC<FiltersProps> = ({
if (filter.type === "range") { if (filter.type === "range") {
return ( return (
<FilterRange <FilterRange
key={filter.title + idx} key={filter.title + idx + JSON.stringify((filterValues && filterValues[filter.title]) || null)}
title={filter.title} title={filter.title}
min={filter.min} min={filter.min}
max={filter.max} max={filter.max}

View File

@ -134,7 +134,7 @@ const FiltersPanelMobile: React.FC<FiltersPanelMobileProps> = ({
if (filter.type === "range") { if (filter.type === "range") {
return ( return (
<FilterRange <FilterRange
key={filter.title + idx} key={filter.title + idx + JSON.stringify(localFilterValues[filter.title] || null)}
title={filter.title} title={filter.title}
min={filter.min} min={filter.min}
max={filter.max} max={filter.max}

View File

@ -24,20 +24,24 @@ const FilterRange: React.FC<FilterRangeProps> = ({ title, min = DEFAULT_MIN, max
const [open, setOpen] = useState(true); const [open, setOpen] = useState(true);
const trackRef = useRef<HTMLDivElement>(null); const trackRef = useRef<HTMLDivElement>(null);
// Обновляем локальное состояние при изменении внешнего значения // Обновляем локальное состояние при изменении внешнего значения или границ
useEffect(() => { useEffect(() => {
if (value) { let nextFrom = value ? value[0] : min;
setFrom(String(value[0])); let nextTo = value ? value[1] : max;
setTo(String(value[1])); let changed = false;
setConfirmedFrom(value[0]); // Корректируем значения, если они вне новых границ
setConfirmedTo(value[1]); if (nextFrom < min) { nextFrom = min; changed = true; }
} else { if (nextTo > max) { nextTo = max; changed = true; }
setFrom(String(min)); if (nextFrom > nextTo) { nextFrom = nextTo; changed = true; }
setTo(String(max)); setFrom(String(nextFrom));
setConfirmedFrom(min); setTo(String(nextTo));
setConfirmedTo(max); setConfirmedFrom(nextFrom);
setConfirmedTo(nextTo);
// Если значения были скорректированы, уведомляем родителя
if (changed && onChange) {
onChange([nextFrom, nextTo]);
} }
}, [value, min, max]); }, [value, min, max, onChange]);
// Обновляем ширину полосы при монтировании и ресайзе // Обновляем ширину полосы при монтировании и ресайзе
useLayoutEffect(() => { useLayoutEffect(() => {

View File

@ -49,6 +49,16 @@ const ProductOfDaySection: React.FC = () => {
.sort((a, b) => a.sortOrder - b.sortOrder); .sort((a, b) => a.sortOrder - b.sortOrder);
}, [data]); }, [data]);
// Корректный сброс currentSlide только если индекс вне диапазона
useEffect(() => {
if (currentSlide > activeProducts.length - 1) {
setCurrentSlide(activeProducts.length > 0 ? activeProducts.length - 1 : 0);
}
// Если товаров стало больше и текущий слайд = 0, ничего не делаем
// Если товаров стало меньше и текущий слайд в диапазоне, ничего не делаем
// Если товаров стало меньше и текущий слайд вне диапазона, сбрасываем на последний
}, [activeProducts.length]);
// Получаем данные из PartsIndex для текущего товара // Получаем данные из PartsIndex для текущего товара
const currentProduct = activeProducts[currentSlide]; const currentProduct = activeProducts[currentSlide];
const { data: partsIndexData } = useQuery( const { data: partsIndexData } = useQuery(
@ -132,11 +142,6 @@ const ProductOfDaySection: React.FC = () => {
setCurrentSlide(index); setCurrentSlide(index);
}; };
// Сброс слайда при изменении товаров
useEffect(() => {
setCurrentSlide(0);
}, [activeProducts]);
// Если нет активных товаров дня, не показываем секцию // Если нет активных товаров дня, не показываем секцию
if (loading || error || activeProducts.length === 0) { if (loading || error || activeProducts.length === 0) {
return null; return null;
@ -244,7 +249,7 @@ const ProductOfDaySection: React.FC = () => {
</div> </div>
{productImage && ( {productImage && (
<div className="relative"> <div className="">
<img <img
width="Auto" width="Auto"
height="Auto" height="Auto"

View File

@ -55,6 +55,7 @@ const KnotIn: React.FC<KnotInProps> = ({
const [selectedDetail, setSelectedDetail] = useState<{ oem: string; name: string } | null>(null); const [selectedDetail, setSelectedDetail] = useState<{ oem: string; name: string } | null>(null);
const [hoveredCodeOnImage, setHoveredCodeOnImage] = useState<string | number | null>(null); const [hoveredCodeOnImage, setHoveredCodeOnImage] = useState<string | number | null>(null);
const router = useRouter(); const router = useRouter();
const [isImageModalOpen, setIsImageModalOpen] = useState(false);
// Получаем инфо об узле (для картинки) // Получаем инфо об узле (для картинки)
console.log('🔍 KnotIn - GET_LAXIMO_UNIT_INFO запрос:', { console.log('🔍 KnotIn - GET_LAXIMO_UNIT_INFO запрос:', {
@ -164,6 +165,12 @@ const KnotIn: React.FC<KnotInProps> = ({
}); });
}; };
// Обработчик клика по картинке (zoom)
const handleImageClick = (e: React.MouseEvent<HTMLImageElement>) => {
// Если клик был по точке, не открываем модалку (точки выше по z-index)
setIsImageModalOpen(true);
};
// Обработчик наведения на точку // Обработчик наведения на точку
const handlePointHover = (coord: any) => { const handlePointHover = (coord: any) => {
// Попробуем использовать разные поля для связи // Попробуем использовать разные поля для связи
@ -318,8 +325,9 @@ const KnotIn: React.FC<KnotInProps> = ({
loading="lazy" loading="lazy"
alt={unitName || unitInfo?.name || "Изображение узла"} alt={unitName || unitInfo?.name || "Изображение узла"}
onLoad={handleImageLoad} onLoad={handleImageLoad}
className="max-w-full h-auto mx-auto rounded" className="max-w-full h-auto mx-auto rounded cursor-zoom-in"
style={{ maxWidth: 400, display: 'block' }} style={{ maxWidth: 400, display: 'block' }}
onClick={handleImageClick}
/> />
{/* Точки/области */} {/* Точки/области */}
{coordinates.map((coord: any, idx: number) => { {coordinates.map((coord: any, idx: number) => {
@ -369,8 +377,8 @@ const KnotIn: React.FC<KnotInProps> = ({
pointerEvents: 'auto', pointerEvents: 'auto',
}} }}
title={`${codeValue} (Клик - выделить в списке, двойной клик - перейти к выбору бренда)`} title={`${codeValue} (Клик - выделить в списке, двойной клик - перейти к выбору бренда)`}
onClick={() => handlePointClick(coord)} onClick={e => { e.stopPropagation(); handlePointClick(coord); }}
onDoubleClick={() => handlePointDoubleClick(coord)} onDoubleClick={e => { e.stopPropagation(); handlePointDoubleClick(coord); }}
onMouseEnter={() => handlePointHover(coord)} onMouseEnter={() => handlePointHover(coord)}
onMouseLeave={() => { onMouseLeave={() => {
setHoveredCodeOnImage(null); setHoveredCodeOnImage(null);
@ -389,6 +397,30 @@ const KnotIn: React.FC<KnotInProps> = ({
); );
})} })}
</div> </div>
{/* Модалка увеличенного изображения */}
{isImageModalOpen && (
<div
className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/20 bg-opacity-70"
onClick={() => setIsImageModalOpen(false)}
style={{ cursor: 'zoom-out' }}
>
<img
src={imageUrl}
alt={unitName || unitInfo?.name || "Изображение узла"}
className="max-h-[90vh] max-w-[90vw] rounded shadow-lg"
onClick={e => e.stopPropagation()}
style={{ background: '#fff' }}
/>
<button
onClick={() => setIsImageModalOpen(false)}
className="absolute top-4 right-4 text-white text-3xl font-bold bg-black bg-opacity-40 rounded-full w-10 h-10 flex items-center justify-center"
aria-label="Закрыть"
style={{ zIndex: 10000 }}
>
×
</button>
</div>
)}
{/* Модалка выбора бренда */} {/* Модалка выбора бренда */}
<BrandSelectionModal <BrandSelectionModal
isOpen={isBrandModalOpen} isOpen={isBrandModalOpen}

View File

@ -53,6 +53,7 @@
.flex-block-40 { .flex-block-40 {
background-color: #fff; background-color: #fff;
padding-top: 10px;
} }
input.text-block-31 { input.text-block-31 {
@ -364,6 +365,15 @@ input.input-receiver:focus {
display: block; display: block;
} }
.image-5-copy {
width: 97px !important;
height: 97px !important;
}
.flex-block-111 {
width: 172px !important;
}
.show-more-btn { .show-more-btn {
background-color: #ec1c24; background-color: #ec1c24;
color: #fff; color: #fff;
@ -516,6 +526,9 @@ input#VinSearchInput {
} }
} }
.div-block-19{
padding-left: 20px !important;
}
.dropdown-toggle-card { .dropdown-toggle-card {
align-self: stretch; align-self: stretch;
@ -913,8 +926,8 @@ a.link-block-2.w-inline-block {
.flex-block-15-copy { .flex-block-15-copy {
width: 235px!important; width: 232px!important;
min-width: 235px!important; min-width: 232px!important;
} }
.nameitembp { .nameitembp {
@ -966,7 +979,16 @@ a.link-block-2.w-inline-block {
@media (max-width: 767px) {
.flex-block-110 {
flex-direction: row !important;
align-items: flex-start !important;
}
.image-5-copy {
width: 75px !important;
height: 75px !important;
}
}
@media (max-width: 767px) { @media (max-width: 767px) {
.topmenub { .topmenub {
display: none !important; display: none !important;