Kaynağa Gözat

1.新增主页视频后端维护

chenhg 1 gün önce
ebeveyn
işleme
fdb43d025b

+ 31 - 7
src/contexts/ThemeContext.tsx

@@ -113,6 +113,35 @@ export const ThemeProvider: React.FC<{ children: ReactNode }> = ({ children }) =
     loadHeroImagesFromApi();
   }, []); // Empty dependency array means this runs on every component mount (page refresh)
 
+  // Fetch video content from API on every page refresh
+  useEffect(() => {
+    const loadVideoContentFromApi = async () => {
+      try {
+        // Import the functions dynamically to avoid circular dependencies
+        const { fetchVideoContent, extractVideoContentFromArticles } = 
+            await import('../services/articleService.ts');
+
+        // Fetch video content from the API (lang=1 for Chinese)
+        const videoData = await fetchVideoContent(1);
+        
+        // Extract video content from the articles data
+        const videoContent = extractVideoContentFromArticles(videoData);
+        
+        // If we got video content from the API, use it
+        if (videoContent) {
+          setVideoSection(videoContent);
+        }
+        // Otherwise, keep the default video content
+      } catch (error) {
+        console.error('Failed to fetch video content from API:', error);
+        // Fallback to default video content if API fails
+        setVideoSection(DEFAULT_VIDEO);
+      }
+    };
+
+    loadVideoContentFromApi();
+  }, []); // Empty dependency array means this runs on every component mount (page refresh)
+
   // --- Content Sections ---
   const [itineraries, setItineraries] = useState<Itinerary[]>(() => {
     const saved = localStorage.getItem('vista_itineraries');
@@ -129,10 +158,7 @@ export const ThemeProvider: React.FC<{ children: ReactNode }> = ({ children }) =
     return saved ? JSON.parse(saved) : DEFAULT_DINING;
   });
 
-  const [videoSection, setVideoSection] = useState<VideoSectionContent>(() => {
-    const saved = localStorage.getItem('vista_video');
-    return saved ? JSON.parse(saved) : DEFAULT_VIDEO;
-  });
+  const [videoSection, setVideoSection] = useState<VideoSectionContent>(DEFAULT_VIDEO);
 
   const [shipsPageImages, setShipsPageImages] = useState<ShipsPageImages>(() => {
     const saved = localStorage.getItem('vista_ships_page_images');
@@ -164,9 +190,7 @@ export const ThemeProvider: React.FC<{ children: ReactNode }> = ({ children }) =
     localStorage.setItem('vista_dining', JSON.stringify(dining));
   }, [dining]);
 
-  useEffect(() => {
-    localStorage.setItem('vista_video', JSON.stringify(videoSection));
-  }, [videoSection]);
+
 
   useEffect(() => {
     localStorage.setItem('vista_ships_page_images', JSON.stringify(shipsPageImages));

+ 18 - 7
src/pages/Home.tsx

@@ -214,14 +214,25 @@ const Home: React.FC = () => {
                   </div>
               </div>
               <div className="md:w-1/2 w-full relative group cursor-pointer">
-                  {/* Video Thumbnail Placeholder */}
+                  {/* Video Section */}
                   <div className="aspect-video w-full bg-black relative overflow-hidden shadow-2xl">
-                      <img src={videoSection.thumbnail} className="w-full h-full object-cover opacity-60 group-hover:opacity-40 transition-opacity" alt="Video Thumbnail" />
-                      <div className="absolute inset-0 flex items-center justify-center">
-                          <div className="w-20 h-20 rounded-full border border-white flex items-center justify-center group-hover:bg-white group-hover:text-vista-darkblue transition-all duration-300">
-                              <Play size={32} fill="currentColor" />
-                          </div>
-                      </div>
+                      {videoSection.video ? (
+                          <video 
+                              src={videoSection.video} 
+                              className="w-full h-full object-cover" 
+                              controls 
+                              poster={videoSection.thumbnail}
+                          />
+                      ) : (
+                          <>  
+                              <img src={videoSection.thumbnail} className="w-full h-full object-cover opacity-60 group-hover:opacity-40 transition-opacity" alt="Video Thumbnail" />
+                              <div className="absolute inset-0 flex items-center justify-center">
+                                  <div className="w-20 h-20 rounded-full border border-white flex items-center justify-center group-hover:bg-white group-hover:text-vista-darkblue transition-all duration-300">
+                                      <Play size={32} fill="currentColor" />
+                                  </div>
+                              </div>
+                          </>
+                      )}
                   </div>
               </div>
           </div>

+ 45 - 0
src/services/articleService.ts

@@ -61,3 +61,48 @@ export const extractHeroImagesFromArticles = (articlesData: ApiResponse): string
     .filter(article => article.coverUrl) // 确保coverUrl存在
     .map(article => article.coverUrl);
 };
+
+// 获取视频内容
+export const fetchVideoContent = async (lang: number): Promise<ApiResponse> => {
+  try {
+    const response = await axios.get<ApiResponse>(
+      'http://localhost:48080/ship-api/cms/article/portal/page-list',
+      {
+        params: {
+          lang,
+          'type.id': '2001571782243946498'
+        }
+      }
+    );
+    return response.data;
+  } catch (error) {
+    console.error('Failed to fetch video content:', error);
+    throw error;
+  }
+};
+
+// 从文章数据中提取视频内容
+export const extractVideoContentFromArticles = (articlesData: ApiResponse): {
+  title: string;
+  titleItalic: string;
+  description: string;
+  thumbnail: string;
+  video?: string;
+} | null => {
+  // 检查API响应是否成功
+  if (articlesData.code !== 0 || !articlesData.data || !articlesData.data.list || articlesData.data.list.length === 0) {
+    return null;
+  }
+
+  // 获取第一篇文章作为视频内容
+  const videoArticle = articlesData.data.list[0];
+  
+  // 提取视频内容
+  return {
+    title: videoArticle.title || '',
+    titleItalic: '', // API中没有直接的titleItalic字段,可能需要从title中提取或使用默认值
+    description: videoArticle.summary || '',
+    thumbnail: videoArticle.coverUrl || '',
+    video: videoArticle.video || undefined
+  };
+};

+ 1 - 0
src/types.ts

@@ -54,6 +54,7 @@ export interface VideoSectionContent {
   titleItalic: string;
   description: string;
   thumbnail: string;
+  video?: string;
 }
 
 // New Interface for Ships Page Images