|
@@ -1,31 +1,75 @@
|
|
|
-import React, { useState } from 'react';
|
|
|
|
|
|
|
+import React, { useState, useEffect } from 'react';
|
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { useNavigate } from 'react-router-dom';
|
|
|
import { useAuth } from '../hooks/AuthProvider';
|
|
import { useAuth } from '../hooks/AuthProvider';
|
|
|
|
|
|
|
|
|
|
+// 图片加载组件
|
|
|
|
|
+const LazyImage: React.FC<{
|
|
|
|
|
+ src: string;
|
|
|
|
|
+ alt: string;
|
|
|
|
|
+ className?: string;
|
|
|
|
|
+ fallback?: string;
|
|
|
|
|
+ onClick?: () => void;
|
|
|
|
|
+}> = ({ src, alt, className, fallback, onClick }) => {
|
|
|
|
|
+ const [imageSrc, setImageSrc] = useState(fallback || '/images/placeholder.jpg');
|
|
|
|
|
+ const [isLoading, setIsLoading] = useState(true);
|
|
|
|
|
+
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ const img = new Image();
|
|
|
|
|
+ img.src = src;
|
|
|
|
|
+ img.onload = () => {
|
|
|
|
|
+ setImageSrc(src);
|
|
|
|
|
+ setIsLoading(false);
|
|
|
|
|
+ };
|
|
|
|
|
+ img.onerror = () => {
|
|
|
|
|
+ setIsLoading(false);
|
|
|
|
|
+ };
|
|
|
|
|
+ }, [src]);
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <img
|
|
|
|
|
+ src={imageSrc}
|
|
|
|
|
+ alt={alt}
|
|
|
|
|
+ className={`${className} ${isLoading ? 'animate-pulse bg-gray-200' : ''} ${onClick ? 'cursor-pointer' : ''}`}
|
|
|
|
|
+ onClick={onClick}
|
|
|
|
|
+ />
|
|
|
|
|
+ );
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
// 首页组件 - 银龄智慧平台主入口
|
|
// 首页组件 - 银龄智慧平台主入口
|
|
|
const HomePage: React.FC = () => {
|
|
const HomePage: React.FC = () => {
|
|
|
const navigate = useNavigate();
|
|
const navigate = useNavigate();
|
|
|
const { user } = useAuth();
|
|
const { user } = useAuth();
|
|
|
const [searchQuery, setSearchQuery] = useState('');
|
|
const [searchQuery, setSearchQuery] = useState('');
|
|
|
|
|
+ const [currentSlide, setCurrentSlide] = useState(0);
|
|
|
|
|
|
|
|
- // 轮播图数据
|
|
|
|
|
|
|
+ // 轮播图数据 - 使用更稳定的图片源
|
|
|
const carouselItems = [
|
|
const carouselItems = [
|
|
|
{
|
|
{
|
|
|
id: 1,
|
|
id: 1,
|
|
|
title: '银龄智慧平台上线啦',
|
|
title: '银龄智慧平台上线啦',
|
|
|
description: '为银龄群体打造的专业服务平台',
|
|
description: '为银龄群体打造的专业服务平台',
|
|
|
- image: 'https://picsum.photos/id/1/800/400',
|
|
|
|
|
- link: '/silver-jobs'
|
|
|
|
|
|
|
+ image: '/images/banner1.jpg',
|
|
|
|
|
+ fallbackImage: '/images/placeholder-banner.jpg',
|
|
|
|
|
+ link: '/home'
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
id: 2,
|
|
id: 2,
|
|
|
title: '时间银行互助养老',
|
|
title: '时间银行互助养老',
|
|
|
description: '存储时间,收获温暖',
|
|
description: '存储时间,收获温暖',
|
|
|
- image: 'https://picsum.photos/id/2/800/400',
|
|
|
|
|
|
|
+ image: '/images/banner2.jpg',
|
|
|
|
|
+ fallbackImage: '/images/placeholder-banner.jpg',
|
|
|
link: '/time-bank'
|
|
link: '/time-bank'
|
|
|
}
|
|
}
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
|
|
+ // 自动轮播功能
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ const interval = setInterval(() => {
|
|
|
|
|
+ setCurrentSlide((prev) => (prev + 1) % carouselItems.length);
|
|
|
|
|
+ }, 5000);
|
|
|
|
|
+ return () => clearInterval(interval);
|
|
|
|
|
+ }, [carouselItems.length]);
|
|
|
|
|
+
|
|
|
// 服务分类数据
|
|
// 服务分类数据
|
|
|
const serviceCategories = [
|
|
const serviceCategories = [
|
|
|
{ name: '银龄岗', icon: '💼', path: '/silver-jobs', color: 'bg-blue-500' },
|
|
{ name: '银龄岗', icon: '💼', path: '/silver-jobs', color: 'bg-blue-500' },
|
|
@@ -103,15 +147,23 @@ const HomePage: React.FC = () => {
|
|
|
|
|
|
|
|
{/* 滚动轮播图 */}
|
|
{/* 滚动轮播图 */}
|
|
|
<div className="relative bg-white overflow-hidden">
|
|
<div className="relative bg-white overflow-hidden">
|
|
|
- <div className="aspect-w-16 aspect-h-9">
|
|
|
|
|
- <div className="flex overflow-x-auto snap-x">
|
|
|
|
|
|
|
+ <div className="relative h-48">
|
|
|
|
|
+ <div
|
|
|
|
|
+ className="flex transition-transform duration-300 ease-in-out"
|
|
|
|
|
+ style={{ transform: `translateX(-${currentSlide * 100}%)` }}
|
|
|
|
|
+ >
|
|
|
{carouselItems.map((item) => (
|
|
{carouselItems.map((item) => (
|
|
|
<div
|
|
<div
|
|
|
key={item.id}
|
|
key={item.id}
|
|
|
- className="snap-center w-full flex-shrink-0 relative cursor-pointer"
|
|
|
|
|
|
|
+ className="w-full flex-shrink-0 relative cursor-pointer"
|
|
|
onClick={() => navigate(item.link)}
|
|
onClick={() => navigate(item.link)}
|
|
|
>
|
|
>
|
|
|
- <img src={item.image} alt={item.title} className="w-full h-48 object-cover" />
|
|
|
|
|
|
|
+ <LazyImage
|
|
|
|
|
+ src={item.image}
|
|
|
|
|
+ fallback={item.fallbackImage}
|
|
|
|
|
+ alt={item.title}
|
|
|
|
|
+ className="w-full h-48 object-cover"
|
|
|
|
|
+ />
|
|
|
<div className="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent">
|
|
<div className="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent">
|
|
|
<div className="absolute bottom-4 left-4 text-white">
|
|
<div className="absolute bottom-4 left-4 text-white">
|
|
|
<h3 className="text-lg font-bold">{item.title}</h3>
|
|
<h3 className="text-lg font-bold">{item.title}</h3>
|
|
@@ -121,6 +173,16 @@ const HomePage: React.FC = () => {
|
|
|
</div>
|
|
</div>
|
|
|
))}
|
|
))}
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
|
|
+ {/* 轮播指示器 */}
|
|
|
|
|
+ <div className="absolute bottom-2 left-1/2 transform -translate-x-1/2 flex space-x-2">
|
|
|
|
|
+ {carouselItems.map((_, index) => (
|
|
|
|
|
+ <div
|
|
|
|
|
+ key={index}
|
|
|
|
|
+ className={`w-2 h-2 rounded-full ${index === currentSlide ? 'bg-white' : 'bg-white/50'}`}
|
|
|
|
|
+ />
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
@@ -156,14 +218,14 @@ const HomePage: React.FC = () => {
|
|
|
|
|
|
|
|
<div className="space-y-3">
|
|
<div className="space-y-3">
|
|
|
{recommendedItems.map((item) => (
|
|
{recommendedItems.map((item) => (
|
|
|
- <div
|
|
|
|
|
- key={item.id}
|
|
|
|
|
- className="flex items-center p-3 bg-gray-50 rounded-lg cursor-pointer hover:bg-gray-100"
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ key={item.id}
|
|
|
|
|
+ className="flex items-center p-3 bg-gray-50 rounded-lg cursor-pointer hover:bg-gray-100 transition-colors"
|
|
|
onClick={() => navigate(`/silver-jobs/${item.id}`)}
|
|
onClick={() => navigate(`/silver-jobs/${item.id}`)}
|
|
|
>
|
|
>
|
|
|
- <img
|
|
|
|
|
- src={item.image}
|
|
|
|
|
- alt={item.title}
|
|
|
|
|
|
|
+ <LazyImage
|
|
|
|
|
+ src={item.image}
|
|
|
|
|
+ alt={item.title}
|
|
|
className="w-12 h-12 rounded-full object-cover mr-3"
|
|
className="w-12 h-12 rounded-full object-cover mr-3"
|
|
|
/>
|
|
/>
|
|
|
<div className="flex-1">
|
|
<div className="flex-1">
|