109 lines
4.1 KiB
JavaScript
109 lines
4.1 KiB
JavaScript
'use client';
|
||
|
||
import { useState, useEffect } from 'react';
|
||
|
||
const ProductImageGallery = ({ data }) => {
|
||
const [currentImageIndex, setCurrentImageIndex] = useState(0);
|
||
|
||
// 如果没有attachments,不显示组件
|
||
if (!data?.attachments || data.attachments.length === 0) {
|
||
return null;
|
||
}
|
||
|
||
// 找到主图在attachments中的索引
|
||
const getMainImageIndex = () => {
|
||
if (!data.image) return 0;
|
||
|
||
const mainImageIndex = data.attachments.findIndex(
|
||
attachment => attachment.file_url === data.image
|
||
);
|
||
|
||
return mainImageIndex >= 0 ? mainImageIndex : 0;
|
||
};
|
||
|
||
const mainImageIndex = getMainImageIndex();
|
||
const currentImage = data.attachments[currentImageIndex]?.file_url || data.attachments[0]?.file_url;
|
||
|
||
// 初始化当前索引为主图索引
|
||
useEffect(() => {
|
||
setCurrentImageIndex(mainImageIndex);
|
||
}, [mainImageIndex]);
|
||
|
||
const changeMainImage = (direction) => {
|
||
if (data.attachments.length <= 1) return;
|
||
|
||
if (direction === 'next') {
|
||
setCurrentImageIndex((prev) => (prev + 1) % data.attachments.length);
|
||
} else {
|
||
setCurrentImageIndex((prev) => (prev - 1 + data.attachments.length) % data.attachments.length);
|
||
}
|
||
};
|
||
|
||
const changeMainImageByIndex = (index) => {
|
||
setCurrentImageIndex(index);
|
||
};
|
||
|
||
return (
|
||
<div className="flex-shrink-0 w-full md:w-120 flex justify-center md:justify-start mb-4 md:mb-0 max-w-full">
|
||
<div className="relative w-full max-w-[320px] md:max-w-full">
|
||
{/* 主图显示区域 */}
|
||
<div className="relative overflow-hidden rounded-xl shadow-lg mb-4">
|
||
<img
|
||
src={currentImage}
|
||
alt={data?.title || 'Product Image'}
|
||
className="w-full max-w-[320px] md:max-w-full object-contain"
|
||
/>
|
||
{/* 导航箭头 */}
|
||
{data.attachments.length > 1 && (
|
||
<>
|
||
<button
|
||
className="absolute left-2 top-1/2 transform -translate-y-1/2 w-8 h-8 bg-white rounded-full border border-gray-300 flex items-center justify-center shadow-md hover:bg-gray-50 transition-colors z-10"
|
||
onClick={() => changeMainImage('prev')}
|
||
aria-label="Previous image"
|
||
>
|
||
<svg className="w-4 h-4 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||
</svg>
|
||
</button>
|
||
<button
|
||
className="absolute right-2 top-1/2 transform -translate-y-1/2 w-8 h-8 bg-white rounded-full border border-gray-300 flex items-center justify-center shadow-md hover:bg-gray-50 transition-colors z-10"
|
||
onClick={() => changeMainImage('next')}
|
||
aria-label="Next image"
|
||
>
|
||
<svg className="w-4 h-4 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||
</svg>
|
||
</button>
|
||
</>
|
||
)}
|
||
</div>
|
||
|
||
{/* 缩略图列表 - 直接显示attachments */}
|
||
<div className="flex flex-wrap gap-1 justify-center md:justify-start">
|
||
{data.attachments.map((attachment, index) => (
|
||
<div
|
||
key={index}
|
||
className={`w-16 h-16 border-1 rounded-lg overflow-hidden cursor-pointer transition-all hover:border-blue-500 ${
|
||
index === currentImageIndex ? 'border-blue-500' : 'border-gray-200'
|
||
}`}
|
||
onClick={() => changeMainImageByIndex(index)}
|
||
>
|
||
<img
|
||
src={attachment.file_url}
|
||
alt={`${data?.title || 'Product'} - ${index + 1}`}
|
||
className="w-full h-full object-cover"
|
||
onError={(e) => {
|
||
console.error('Image load error:', attachment.file_url);
|
||
e.target.style.display = 'none';
|
||
}}
|
||
/>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default ProductImageGallery;
|