|
@@ -0,0 +1,286 @@
|
|
|
|
|
+"use client"
|
|
|
|
|
+
|
|
|
|
|
+import {useState} from "react"
|
|
|
|
|
+import MainTitle from "@/components/MainTitle"
|
|
|
|
|
+import SubTitle from "@/components/subTitle"
|
|
|
|
|
+import Image from "next/image"
|
|
|
|
|
+
|
|
|
|
|
+export default function ProductShowcase() {
|
|
|
|
|
+ const [selectedKey, setSelectedKey] = useState("software")
|
|
|
|
|
+ const [expandedKeys, setExpandedKeys] = useState<string[]>([])
|
|
|
|
|
+
|
|
|
|
|
+ const findLabelByKey = (key: string): string => {
|
|
|
|
|
+ for (const item of menuItems) {
|
|
|
|
|
+ if (item.key === key) {
|
|
|
|
|
+ return item.label
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (item.children) {
|
|
|
|
|
+ const child = item.children.find((child) => child.key === key)
|
|
|
|
|
+ if (child) {
|
|
|
|
|
+ return child.label
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return key
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const products = [
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 1,
|
|
|
|
|
+ title: "可视化数字孪生平台",
|
|
|
|
|
+ bgColor: "bg-gradient-to-br from-blue-900 via-blue-800 to-slate-800",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 2,
|
|
|
|
|
+ title: "水库雨水情测报与大坝安全监测平台",
|
|
|
|
|
+ bgColor: "bg-gradient-to-br from-teal-900 via-emerald-800 to-cyan-800",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 3,
|
|
|
|
|
+ title: "物联网平台",
|
|
|
|
|
+ bgColor: "bg-gradient-to-br from-teal-900 via-emerald-800 to-cyan-800",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 4,
|
|
|
|
|
+ title: "智慧档案库可视化平台",
|
|
|
|
|
+ bgColor: "bg-gradient-to-br from-blue-900 via-indigo-800 to-slate-800",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 5,
|
|
|
|
|
+ title: "智慧环保监测管理平台",
|
|
|
|
|
+ bgColor: "bg-gradient-to-br from-slate-900 via-blue-900 to-indigo-900",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 6,
|
|
|
|
|
+ title: "自然灾害应急能力提升平台",
|
|
|
|
|
+ bgColor: "bg-gradient-to-br from-slate-900 via-gray-800 to-blue-900",
|
|
|
|
|
+ },
|
|
|
|
|
+ ]
|
|
|
|
|
+
|
|
|
|
|
+ const menuItems = [
|
|
|
|
|
+ {
|
|
|
|
|
+ key: "software",
|
|
|
|
|
+ label: "软件产品",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: "hardware",
|
|
|
|
|
+ label: "硬件产品",
|
|
|
|
|
+ children: [
|
|
|
|
|
+ {
|
|
|
|
|
+ key: "sensor",
|
|
|
|
|
+ label: "传感设备",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: "iot",
|
|
|
|
|
+ label: "物联设备",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: "terminal",
|
|
|
|
|
+ label: "智能交互终端",
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ ]
|
|
|
|
|
+
|
|
|
|
|
+ const handleMenuClick = (key: string) => {
|
|
|
|
|
+ setSelectedKey(key)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const toggleExpanded = (key: string) => {
|
|
|
|
|
+ setExpandedKeys((prev) => (prev.includes(key) ? prev.filter((k) => k !== key) : [...prev, key]))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const DesktopMenu = () => (
|
|
|
|
|
+ <div className="space-y-1">
|
|
|
|
|
+ {menuItems.map((item) => (
|
|
|
|
|
+ <div key={item.key}>
|
|
|
|
|
+ <div
|
|
|
|
|
+ className={`flex items-center justify-between px-4 py-6 text-sm font-medium cursor-pointer rounded-lg transition-all duration-300 ${
|
|
|
|
|
+ selectedKey === item.key
|
|
|
|
|
+ ? "bg-blue-500 text-white shadow-lg"
|
|
|
|
|
+ : "text-gray-700 bg-blue-100 hover:bg-gray-100 hover:text-gray-900"
|
|
|
|
|
+ }`}
|
|
|
|
|
+ onClick={() => {
|
|
|
|
|
+ if (item.children) {
|
|
|
|
|
+ toggleExpanded(item.key)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ handleMenuClick(item.key)
|
|
|
|
|
+ }
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <span className="transition-all duration-200">{item.label}</span>
|
|
|
|
|
+ {item.children && (
|
|
|
|
|
+ <svg
|
|
|
|
|
+ className={`w-4 h-4 transition-all duration-300 ease-in-out ${
|
|
|
|
|
+ expandedKeys.includes(item.key) ? "rotate-90" : ""
|
|
|
|
|
+ } ${selectedKey === item.key ? "text-white" : "text-gray-500 hover:text-blue-400"}`}
|
|
|
|
|
+ fill="none"
|
|
|
|
|
+ stroke="currentColor"
|
|
|
|
|
+ viewBox="0 0 24 24"
|
|
|
|
|
+ >
|
|
|
|
|
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ {item.children && (
|
|
|
|
|
+ <div
|
|
|
|
|
+ className={`ml-4 mt-1 space-y-1 overflow-hidden transition-all duration-300 ease-in-out ${
|
|
|
|
|
+ expandedKeys.includes(item.key) ? "max-h-96 opacity-100" : "max-h-0 opacity-0"
|
|
|
|
|
+ }`}
|
|
|
|
|
+ >
|
|
|
|
|
+ {item.children.map((child) => (
|
|
|
|
|
+ <div
|
|
|
|
|
+ key={child.key}
|
|
|
|
|
+ className={`px-4 py-4 text-sm cursor-pointer rounded-lg transition-all duration-200 ${
|
|
|
|
|
+ selectedKey === child.key
|
|
|
|
|
+ ? "bg-blue-500 text-white shadow-md"
|
|
|
|
|
+ : "text-gray-600 hover:bg-blue-50 hover:text-blue-700"
|
|
|
|
|
+ }`}
|
|
|
|
|
+ onClick={() => handleMenuClick(child.key)}
|
|
|
|
|
+ >
|
|
|
|
|
+ <span className="flex items-center">{child.label}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ const MobileMenu = () => (
|
|
|
|
|
+ <div className="bg-white shadow-sm">
|
|
|
|
|
+ <div className="px-4 py-3">
|
|
|
|
|
+ <div className="flex flex-wrap gap-2">
|
|
|
|
|
+ {menuItems.map((item) => (
|
|
|
|
|
+ <div key={item.key} className="relative">
|
|
|
|
|
+ <button
|
|
|
|
|
+ className={`px-4 py-2 rounded-lg text-sm font-medium transition-all duration-200 ${
|
|
|
|
|
+ selectedKey === item.key ||
|
|
|
|
|
+ (item.children && item.children.some((child) => selectedKey === child.key))
|
|
|
|
|
+ ? "bg-blue-500 text-white shadow-md"
|
|
|
|
|
+ : "bg-gray-100 text-gray-700 hover:bg-gray-200"
|
|
|
|
|
+ }`}
|
|
|
|
|
+ onClick={() => {
|
|
|
|
|
+ if (item.children) {
|
|
|
|
|
+ toggleExpanded(item.key)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ handleMenuClick(item.key)
|
|
|
|
|
+ }
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <span className="flex items-center gap-1">
|
|
|
|
|
+ {item.label}
|
|
|
|
|
+ {item.children && (
|
|
|
|
|
+ <svg
|
|
|
|
|
+ className={`w-3 h-3 transition-transform duration-200 ${
|
|
|
|
|
+ expandedKeys.includes(item.key) ? "rotate-180" : ""
|
|
|
|
|
+ }`}
|
|
|
|
|
+ fill="none"
|
|
|
|
|
+ stroke="currentColor"
|
|
|
|
|
+ viewBox="0 0 24 24"
|
|
|
|
|
+ >
|
|
|
|
|
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </button>
|
|
|
|
|
+
|
|
|
|
|
+ {item.children && expandedKeys.includes(item.key) && (
|
|
|
|
|
+ <div className="absolute top-full left-0 mt-1 bg-white border border-gray-200 rounded-lg shadow-lg z-10 min-w-[160px]">
|
|
|
|
|
+ {item.children.map((child) => (
|
|
|
|
|
+ <button
|
|
|
|
|
+ key={child.key}
|
|
|
|
|
+ className={`w-full text-left px-4 py-3 text-sm transition-colors duration-200 first:rounded-t-lg last:rounded-b-lg ${
|
|
|
|
|
+ selectedKey === child.key ? "bg-blue-500 text-white" : "text-gray-700 hover:bg-gray-50"
|
|
|
|
|
+ }`}
|
|
|
|
|
+ onClick={() => {
|
|
|
|
|
+ handleMenuClick(child.key)
|
|
|
|
|
+ setExpandedKeys([]) // Close dropdown after selection
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ {child.label}
|
|
|
|
|
+ </button>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <Image src={"/assets/productions/1.png"} alt={"产品中心"} width={1920} height={1080} />
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div className="py-6 sm:py-10">
|
|
|
|
|
+ <MainTitle title={"产品中心"} />
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div className="sm:hidden">
|
|
|
|
|
+ <MobileMenu />
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div className="flex mt-6 sm:mt-10 mb-12 sm:mb-16 w-full sm:w-4/5 mx-auto px-4 sm:px-0">
|
|
|
|
|
+ <div className="hidden sm:block w-56 lg:w-64 p-4">
|
|
|
|
|
+ <DesktopMenu />
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div className="flex-1 p-2 sm:p-4 lg:p-8 sm:pt-8">
|
|
|
|
|
+ <div className="sm:hidden mt-3 mb-10">
|
|
|
|
|
+ <SubTitle title={findLabelByKey(selectedKey)} customStyle={{ textAlign: "center" }} />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6">
|
|
|
|
|
+ {products.map((product) => (
|
|
|
|
|
+ <div
|
|
|
|
|
+ key={product.id}
|
|
|
|
|
+ className="bg-white rounded-lg overflow-hidden shadow-lg hover:shadow-xl transition-all duration-300 hover:scale-[1.02]"
|
|
|
|
|
+ >
|
|
|
|
|
+ <div className={`h-32 sm:h-40 lg:h-48 ${product.bgColor} relative overflow-hidden`}>
|
|
|
|
|
+ <div className="absolute inset-3 sm:inset-4 space-y-2">
|
|
|
|
|
+ <div className="flex space-x-2">
|
|
|
|
|
+ <div className="w-12 sm:w-16 h-1.5 sm:h-2 bg-white/20 rounded"></div>
|
|
|
|
|
+ <div className="w-8 sm:w-12 h-1.5 sm:h-2 bg-white/20 rounded"></div>
|
|
|
|
|
+ <div className="w-14 sm:w-20 h-1.5 sm:h-2 bg-white/20 rounded"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div className="grid grid-cols-2 gap-2 mt-3 sm:mt-4">
|
|
|
|
|
+ <div className="h-12 sm:h-16 bg-white/10 rounded border border-white/20"></div>
|
|
|
|
|
+ <div className="h-12 sm:h-16 bg-white/10 rounded border border-white/20"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div className="mt-3 sm:mt-4 space-y-1">
|
|
|
|
|
+ <div className="w-full h-0.5 sm:h-1 bg-white/20 rounded"></div>
|
|
|
|
|
+ <div className="w-3/4 h-0.5 sm:h-1 bg-white/20 rounded"></div>
|
|
|
|
|
+ <div className="w-1/2 h-0.5 sm:h-1 bg-white/20 rounded"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div className="absolute top-1 sm:top-2 right-1 sm:right-2 w-6 sm:w-8 h-6 sm:h-8 border border-white/30 rounded-full"></div>
|
|
|
|
|
+ <div className="absolute bottom-1 sm:bottom-2 left-1 sm:left-2 w-3 sm:w-4 h-3 sm:h-4 bg-cyan-400/60 rounded"></div>
|
|
|
|
|
+ <div className="absolute bottom-1 sm:bottom-2 right-1 sm:right-2 w-4 sm:w-6 h-4 sm:h-6 bg-blue-400/60 rounded"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div className="p-4 sm:p-6 text-center">
|
|
|
|
|
+ <h3 className="text-sm sm:text-base lg:text-lg font-medium text-gray-900 mb-3 sm:mb-4 leading-tight min-h-[2.5rem] sm:min-h-[3rem] flex items-center justify-center">
|
|
|
|
|
+ {product.title}
|
|
|
|
|
+ </h3>
|
|
|
|
|
+ <button className="bg-blue-500 hover:bg-blue-600 text-white px-4 sm:px-6 py-2 sm:py-2.5 rounded-lg font-medium transition-all duration-200 text-sm sm:text-base hover:scale-105 active:scale-95">
|
|
|
|
|
+ 了解详情
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </>
|
|
|
|
|
+ )
|
|
|
|
|
+}
|