|
@@ -1,32 +1,87 @@
|
|
|
'use client'
|
|
'use client'
|
|
|
-import React from 'react';
|
|
|
|
|
|
|
+import React, {useEffect, useState} from 'react';
|
|
|
import {Carousel, Tabs, TabsProps} from "antd";
|
|
import {Carousel, Tabs, TabsProps} from "antd";
|
|
|
import Image from "next/image";
|
|
import Image from "next/image";
|
|
|
|
|
|
|
|
-function Honor({honorList}: {honorList: HonorInfo[]}) {
|
|
|
|
|
|
|
+function Honor({ honorList }: { honorList: HonorInfo[] }) {
|
|
|
const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL;
|
|
const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL;
|
|
|
- function CategoryCarousel({ images }: { images: Array<{ id: string; url: string;}> }) {
|
|
|
|
|
- // 将图片按每页3个分组
|
|
|
|
|
- const imageGroups = []
|
|
|
|
|
- for (let i = 0; i < images.length; i += 3) {
|
|
|
|
|
- imageGroups.push(images.slice(i, i + 3))
|
|
|
|
|
|
|
+ const [previewUrl, setPreviewUrl] = useState<string | null>(null);
|
|
|
|
|
+ const [isMobile, setIsMobile] = useState(false);
|
|
|
|
|
+
|
|
|
|
|
+ // 判断是否是小屏
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ const checkMobile = () => setIsMobile(window.innerWidth < 640);
|
|
|
|
|
+ checkMobile();
|
|
|
|
|
+ window.addEventListener("resize", checkMobile);
|
|
|
|
|
+ return () => window.removeEventListener("resize", checkMobile);
|
|
|
|
|
+ }, []);
|
|
|
|
|
+
|
|
|
|
|
+ // 预览层
|
|
|
|
|
+ function PreviewModal({ url, onClose }: { url: string, onClose: () => void }) {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div
|
|
|
|
|
+ className="fixed inset-0 bg-black/80 flex items-center justify-center z-50"
|
|
|
|
|
+ onClick={onClose}
|
|
|
|
|
+ >
|
|
|
|
|
+ <div
|
|
|
|
|
+ className="relative max-w-5xl w-full flex justify-center border border-white/20 rounded-lg"
|
|
|
|
|
+ onClick={(e) => e.stopPropagation()}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Image
|
|
|
|
|
+ src={url}
|
|
|
|
|
+ alt="预览"
|
|
|
|
|
+ width={1000}
|
|
|
|
|
+ height={800}
|
|
|
|
|
+ className="max-h-[90vh] object-contain rounded-lg"
|
|
|
|
|
+ />
|
|
|
|
|
+ <button
|
|
|
|
|
+ onClick={onClose}
|
|
|
|
|
+ className="absolute top-4 right-4 bg-white text-black rounded-full px-3 py-1 shadow hover:bg-gray-200"
|
|
|
|
|
+ >
|
|
|
|
|
+ ✕
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Carousel
|
|
|
|
|
+ function CategoryCarousel({ images }: { images: Array<{ id: string; url: string }> }) {
|
|
|
|
|
+ let imageGroups: Array<typeof images> = [];
|
|
|
|
|
+
|
|
|
|
|
+ if (isMobile) {
|
|
|
|
|
+ // 移动端:每页一个
|
|
|
|
|
+ imageGroups = images.map((img) => [img]);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 桌面端:每页三个
|
|
|
|
|
+ for (let i = 0; i < images.length; i += 3) {
|
|
|
|
|
+ imageGroups.push(images.slice(i, i + 3));
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
<div className="relative">
|
|
<div className="relative">
|
|
|
- <Carousel arrows dots={true} infinite={false}>
|
|
|
|
|
|
|
+ <Carousel arrows draggable dots infinite={false} autoplay autoplaySpeed={2500}>
|
|
|
{imageGroups.map((group, groupIndex) => (
|
|
{imageGroups.map((group, groupIndex) => (
|
|
|
<div key={groupIndex}>
|
|
<div key={groupIndex}>
|
|
|
- <div className="grid grid-cols-1 sm:grid-cols-3 gap-6 p-4">
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ className={`grid ${
|
|
|
|
|
+ isMobile ? "grid-cols-1" : "grid-cols-3"
|
|
|
|
|
+ } gap-6 p-4`}
|
|
|
|
|
+ >
|
|
|
{group.map((image) => (
|
|
{group.map((image) => (
|
|
|
- <div key={image.id} className="relative group">
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ key={image.id}
|
|
|
|
|
+ className="relative group cursor-pointer"
|
|
|
|
|
+ onClick={() => setPreviewUrl(BASE_URL + image.url)}
|
|
|
|
|
+ >
|
|
|
<div className="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300">
|
|
<div className="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300">
|
|
|
<Image
|
|
<Image
|
|
|
- src={ BASE_URL + image.url || "/placeholder.svg"}
|
|
|
|
|
- alt={"证书"}
|
|
|
|
|
|
|
+ src={BASE_URL + image.url || "/placeholder.svg"}
|
|
|
|
|
+ alt="证书"
|
|
|
width={400}
|
|
width={400}
|
|
|
height={300}
|
|
height={300}
|
|
|
- className="w-full h-48 object-cover group-hover:scale-105 transition-transform duration-300"
|
|
|
|
|
|
|
+ className="w-full h-auto max-h-100 min-h-100 object-contain group-hover:scale-105 transition-transform duration-300"
|
|
|
/>
|
|
/>
|
|
|
<div className="p-4">
|
|
<div className="p-4">
|
|
|
<p className="text-sm text-gray-600 text-center">证书</p>
|
|
<p className="text-sm text-gray-600 text-center">证书</p>
|
|
@@ -39,19 +94,21 @@ function Honor({honorList}: {honorList: HonorInfo[]}) {
|
|
|
))}
|
|
))}
|
|
|
</Carousel>
|
|
</Carousel>
|
|
|
</div>
|
|
</div>
|
|
|
- )
|
|
|
|
|
|
|
+ );
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const tabItems: TabsProps["items"] = honorList.map((honor,index) => ({
|
|
|
|
|
|
|
+ const tabItems: TabsProps["items"] = honorList.map((honor, index) => ({
|
|
|
key: honor.id || index.toString(),
|
|
key: honor.id || index.toString(),
|
|
|
label: honor.certificateType || "未知",
|
|
label: honor.certificateType || "未知",
|
|
|
children: <CategoryCarousel images={honor.fileList || []} />,
|
|
children: <CategoryCarousel images={honor.fileList || []} />,
|
|
|
- }))
|
|
|
|
|
|
|
+ }));
|
|
|
|
|
+
|
|
|
return (
|
|
return (
|
|
|
<>
|
|
<>
|
|
|
- <Tabs defaultActiveKey="honor" items={tabItems} className="w-full" centered/>
|
|
|
|
|
|
|
+ <Tabs defaultActiveKey={honorList[0]?.id || "0"} items={tabItems} className="w-full" centered />
|
|
|
|
|
+ {previewUrl && <PreviewModal url={previewUrl} onClose={() => setPreviewUrl(null)} />}
|
|
|
</>
|
|
</>
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export default Honor;
|
|
|
|
|
|
|
+export default Honor;
|