|
@@ -1,7 +1,8 @@
|
|
|
"use client";
|
|
"use client";
|
|
|
-import React, {useEffect, useMemo, useState} from 'react';
|
|
|
|
|
|
|
+import React, {useMemo} from 'react';
|
|
|
import Link from "next/link";
|
|
import Link from "next/link";
|
|
|
import Image from 'next/image';
|
|
import Image from 'next/image';
|
|
|
|
|
+import { useRouter, useSearchParams } from 'next/navigation';
|
|
|
|
|
|
|
|
// 1. 抽离类型定义,提升可维护性
|
|
// 1. 抽离类型定义,提升可维护性
|
|
|
interface Article {
|
|
interface Article {
|
|
@@ -19,10 +20,6 @@ interface NewsItemProps {
|
|
|
news: Article,
|
|
news: Article,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-interface NewsListProps {
|
|
|
|
|
- newsList: Article[];
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
interface NewsPageProps {
|
|
interface NewsPageProps {
|
|
|
newsList: Article[];
|
|
newsList: Article[];
|
|
|
}
|
|
}
|
|
@@ -37,7 +34,7 @@ const CATEGORY_MAP = Object.freeze({
|
|
|
const NewsItem: React.FC<NewsItemProps> = ({news: article}) => {
|
|
const NewsItem: React.FC<NewsItemProps> = ({news: article}) => {
|
|
|
// 环境变量默认值兜底,避免undefined
|
|
// 环境变量默认值兜底,避免undefined
|
|
|
const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL || '';
|
|
const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL || '';
|
|
|
- const REMOTE_BASE_URL = process.env.NEXT_PUBLIC_REMOTE_BASE_URL || '';
|
|
|
|
|
|
|
+ const REMOTE_BASE_URL = process.env.NEXT_PUBLIC_REMOTE_BASE_URL || 'http://47.107.107.47:8040';
|
|
|
|
|
|
|
|
// 图片地址处理抽离,提升可读性,并且修复可能出现的本地绝对路径和重复拼接问题
|
|
// 图片地址处理抽离,提升可读性,并且修复可能出现的本地绝对路径和重复拼接问题
|
|
|
let coverImageUrl = article.newsUrl || '';
|
|
let coverImageUrl = article.newsUrl || '';
|
|
@@ -103,57 +100,23 @@ const NewsItem: React.FC<NewsItemProps> = ({news: article}) => {
|
|
|
);
|
|
);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-// 5. 新闻列表组件(添加空状态优化)
|
|
|
|
|
-const NewsList: React.FC<NewsListProps> = ({newsList}) => {
|
|
|
|
|
- // 空数组判断优化,避免length判断出错
|
|
|
|
|
- if (!Array.isArray(newsList) || newsList.length === 0) {
|
|
|
|
|
- return <div className="text-center text-lg text-gray-400 py-10">暂无相关新闻</div>;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return (
|
|
|
|
|
- <div className="flex flex-col gap-5 mt-5 mb-10">
|
|
|
|
|
- {newsList.map((news) => (
|
|
|
|
|
- <NewsItem
|
|
|
|
|
- key={news.id}
|
|
|
|
|
- news={news}
|
|
|
|
|
- />
|
|
|
|
|
- ))}
|
|
|
|
|
- </div>
|
|
|
|
|
- );
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
// 6. 主新闻页面组件
|
|
// 6. 主新闻页面组件
|
|
|
const NewsPage: React.FC<NewsPageProps> = ({newsList = []}) => {
|
|
const NewsPage: React.FC<NewsPageProps> = ({newsList = []}) => {
|
|
|
|
|
+ const router = useRouter();
|
|
|
|
|
+ const searchParams = useSearchParams();
|
|
|
|
|
+ const activeTab = searchParams.get('category') || 'company';
|
|
|
|
|
+
|
|
|
// 类型守卫,确保newsList是数组类型
|
|
// 类型守卫,确保newsList是数组类型
|
|
|
const safeNewsList = useMemo(() =>
|
|
const safeNewsList = useMemo(() =>
|
|
|
Array.isArray(newsList) ? newsList : [],
|
|
Array.isArray(newsList) ? newsList : [],
|
|
|
[newsList]);
|
|
[newsList]);
|
|
|
|
|
|
|
|
- const [activeTab, setActiveTab] = useState<keyof typeof CATEGORY_MAP>('company'); // 严格类型约束
|
|
|
|
|
- const [filteredNews, setFilteredNews] = useState<Article[]>([]);
|
|
|
|
|
- const [isLoading, setIsLoading] = useState(true);
|
|
|
|
|
-
|
|
|
|
|
- // 7. 优化筛选逻辑:使用useMemo减少重复计算
|
|
|
|
|
- useEffect(() => {
|
|
|
|
|
- setIsLoading(true);
|
|
|
|
|
-
|
|
|
|
|
- const timer = setTimeout(() => {
|
|
|
|
|
- const targetCategory = CATEGORY_MAP[activeTab];
|
|
|
|
|
- const filtered = safeNewsList.filter(
|
|
|
|
|
- (news) => news.newsCategory === targetCategory
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- setFilteredNews(filtered);
|
|
|
|
|
- setIsLoading(false);
|
|
|
|
|
- }, 300);
|
|
|
|
|
-
|
|
|
|
|
- return () => clearTimeout(timer);
|
|
|
|
|
- }, [safeNewsList, activeTab]);
|
|
|
|
|
-
|
|
|
|
|
- // 8. 抽离标签切换逻辑,简化代码
|
|
|
|
|
|
|
+ // 8. 抽离标签切换逻辑,改为路由跳转
|
|
|
const handleTabChange = (tab: keyof typeof CATEGORY_MAP) => {
|
|
const handleTabChange = (tab: keyof typeof CATEGORY_MAP) => {
|
|
|
- setIsLoading(true);
|
|
|
|
|
- setActiveTab(tab);
|
|
|
|
|
|
|
+ const url = new URL(window.location.href);
|
|
|
|
|
+ url.searchParams.set('category', tab);
|
|
|
|
|
+ url.searchParams.set('page', '1'); // 切换分类时,页码重置为第一页
|
|
|
|
|
+ router.push(url.pathname + url.search);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
@@ -188,8 +151,18 @@ const NewsPage: React.FC<NewsPageProps> = ({newsList = []}) => {
|
|
|
</button>
|
|
</button>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- {isLoading && <div className="text-center text-lg text-gray-500 py-10">加载中...</div>}
|
|
|
|
|
- {!isLoading && <NewsList newsList={filteredNews}/>}
|
|
|
|
|
|
|
+ {(!safeNewsList || safeNewsList.length === 0) ? (
|
|
|
|
|
+ <div className="text-center text-lg text-gray-400 py-10">暂无相关新闻</div>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <div className="flex flex-col gap-5 mt-5 mb-10">
|
|
|
|
|
+ {safeNewsList.map((news) => (
|
|
|
|
|
+ <NewsItem
|
|
|
|
|
+ key={news.id}
|
|
|
|
|
+ news={news}
|
|
|
|
|
+ />
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )}
|
|
|
</div>
|
|
</div>
|
|
|
);
|
|
);
|
|
|
};
|
|
};
|