diff --git a/src/pages/IndustryNews.tsx b/src/pages/IndustryNews.tsx index 4d8a57e..e3016c1 100644 --- a/src/pages/IndustryNews.tsx +++ b/src/pages/IndustryNews.tsx @@ -28,10 +28,10 @@ const IndustryNews: React.FC = () => { { value: 'all', label: '全部动态', icon: '📰', color: 'from-blue-500 to-cyan-500' }, { value: 'healthcare-policy', label: '康养政策', icon: '🏥', color: 'from-green-500 to-emerald-500' }, { value: 'medical-robotics', label: '医疗机器人', icon: '🤖', color: 'from-purple-500 to-violet-500' }, - { value: 'industry-trends', label: '行业动态', icon: '📈', color: 'from-orange-500 to-amber-500' }, + { value: 'smart-elderly-care', label: '智慧养老', icon: '👴', color: 'from-indigo-500 to-blue-500' }, { value: 'tech-innovation', label: '技术前沿', icon: '🚀', color: 'from-pink-500 to-rose-500' }, { value: 'investment', label: '投融资', icon: '💰', color: 'from-yellow-500 to-orange-500' }, - { value: 'regulatory', label: '监管动态', icon: '⚖️', color: 'from-red-500 to-pink-500' }, + { value: 'industry-trends', label: '行业动态', icon: '📈', color: 'from-orange-500 to-amber-500' }, ]; const sortOptions = [ @@ -228,10 +228,16 @@ const IndustryNews: React.FC = () => { {news.title} - {/* Summary */} -

- {news.summary} -

+ {/* AI Summary */} +
+
+ + AI摘要 +
+

+ {news.summary} +

+
{/* Meta Info */}
diff --git a/src/pages/NewsDetail.tsx b/src/pages/NewsDetail.tsx index 95dc48d..4f83f65 100644 --- a/src/pages/NewsDetail.tsx +++ b/src/pages/NewsDetail.tsx @@ -189,6 +189,17 @@ const NewsDetail: React.FC = () => { )} + {/* AI摘要标识 */} +
+
+ + AI智能摘要 +
+

+ 以下内容为AI基于原文生成的智能摘要,如需查看完整原文,请点击下方"查看原文"链接。 +

+
+ {/* 文章内容 */}
{
{/* 原文链接 */} -
+
- 查看原文 +
+

查看完整原文

+

获取更多详细信息和完整内容

+
访问 {article.source} diff --git a/src/services/newsService.ts b/src/services/newsService.ts index 35fc7e9..4d76f59 100644 --- a/src/services/newsService.ts +++ b/src/services/newsService.ts @@ -1,25 +1,12 @@ -// 新闻服务 - 支持多种数据源 +// 新闻服务 - 只使用真实API数据 import { NewsItem, NewsCategory, NewsSearchParams, NewsResponse, NewsStats } from '../types/news'; -// 外部API配置 +// API配置 const NEWS_API_CONFIG = { - // 自建新闻API(推荐) CUSTOM_API: { - baseUrl: import.meta.env.VITE_NEWS_API_URL || 'http://localhost:3001/api', + baseUrl: import.meta.env.VITE_NEWS_API_URL || 'http://localhost:3002/api', apiKey: import.meta.env.VITE_NEWS_API_KEY || 'omniverse_news_2024', - }, - - // 第三方新闻API备选方案 - NEWSAPI: { - baseUrl: 'https://newsapi.org/v2', - apiKey: import.meta.env.VITE_NEWSAPI_KEY || '', - }, - - // 聚合数据API - JUHE: { - baseUrl: 'http://v.juhe.cn/toutiao', - apiKey: import.meta.env.VITE_JUHE_KEY || '', } }; @@ -59,33 +46,20 @@ class NewsService { if (cached) return cached; try { - // 优先使用自建API - if (NEWS_API_CONFIG.CUSTOM_API.baseUrl) { - const result = await this.fetchFromCustomAPI(params); - this.setCachedData(cacheKey, result); - return result; - } - - // 如果没有API配置,返回空结果 - return { - items: [], - total: 0, - page: 1, - totalPages: 0, - hasNext: false, - hasPrev: false, - }; + const result = await this.fetchFromCustomAPI(params); + this.setCachedData(cacheKey, result); + return result; } catch (error) { - console.error('Failed to fetch news:', error); - // 返回空结果而不是mock数据 + console.error('Failed to fetch news from API:', error); + // 返回空结果而不是模拟数据 return { items: [], total: 0, page: 1, totalPages: 0, hasNext: false, - hasPrev: false, + hasPrev: false }; } } @@ -103,7 +77,9 @@ class NewsService { if (params.sortBy) queryParams.append('sortBy', params.sortBy); if (params.sortOrder) queryParams.append('sortOrder', params.sortOrder); - const response = await fetch(`${baseUrl}/news?${queryParams}`, { + const url = `${baseUrl}/news?${queryParams}`; + + const response = await fetch(url, { headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json', @@ -134,42 +110,31 @@ class NewsService { if (cached) return cached; try { - if (NEWS_API_CONFIG.CUSTOM_API.baseUrl) { - const response = await fetch(`${NEWS_API_CONFIG.CUSTOM_API.baseUrl}/stats`, { - headers: { - 'X-API-Key': NEWS_API_CONFIG.CUSTOM_API.apiKey, - }, - }); - - if (response.ok) { - const result = await response.json(); - this.setCachedData(cacheKey, result); - return result; - } - } + const response = await fetch(`${NEWS_API_CONFIG.CUSTOM_API.baseUrl}/stats`, { + headers: { + 'X-API-Key': NEWS_API_CONFIG.CUSTOM_API.apiKey, + }, + }); - // 如果没有API,返回空统计 - const result = { - totalNews: 0, - todayNews: 0, - hotNews: 0, - categoryCounts: {}, - sourceCounts: {}, - trending: [], - }; - this.setCachedData(cacheKey, result); - return result; + if (response.ok) { + const result = await response.json(); + this.setCachedData(cacheKey, result); + return result; + } else { + throw new Error(`Stats API failed: ${response.status}`); + } } catch (error) { console.error('Failed to fetch news stats:', error); + // 返回空统计而不是模拟数据 return { totalNews: 0, todayNews: 0, hotNews: 0, categoryCounts: {}, sourceCounts: {}, - trending: [], - }; + trending: [] + } as NewsStats; } } @@ -186,30 +151,27 @@ class NewsService { if (cached) return cached; try { - if (NEWS_API_CONFIG.CUSTOM_API.baseUrl) { - const response = await fetch(`${NEWS_API_CONFIG.CUSTOM_API.baseUrl}/news/hot?limit=${limit}`, { - headers: { - 'X-API-Key': NEWS_API_CONFIG.CUSTOM_API.apiKey, - }, - }); - - if (response.ok) { - const result = await response.json(); - this.setCachedData(cacheKey, result); - return result; - } - } + const response = await fetch(`${NEWS_API_CONFIG.CUSTOM_API.baseUrl}/news/hot?limit=${limit}`, { + headers: { + 'X-API-Key': NEWS_API_CONFIG.CUSTOM_API.apiKey, + }, + }); - // Fallback - const response = await this.getNews({ limit, sortBy: 'viewCount' }); - const result = response.items.filter(item => item.isHot); - this.setCachedData(cacheKey, result); - return result; + if (response.ok) { + const result = await response.json(); + this.setCachedData(cacheKey, result); + return result; + } else { + // 如果没有专门的hot接口,使用普通接口筛选 + const newsResponse = await this.getNews({ limit: limit * 2, sortBy: 'viewCount' }); + const result = newsResponse.items.filter(item => item.isHot).slice(0, limit); + this.setCachedData(cacheKey, result); + return result; + } } catch (error) { console.error('Failed to fetch hot news:', error); - const response = await this.getNews({ limit, sortBy: 'viewCount' }); - return response.items.filter(item => item.isHot); + return []; } } @@ -219,148 +181,6 @@ class NewsService { return response.items; } - // 模拟新闻数据(开发和fallback使用) - private async getMockNews(params: NewsSearchParams = {}): Promise { - const { page = 1, limit = 10, category, query } = params; - - let mockNews = this.generateMockNews(); - - // 按分类筛选 - if (category) { - mockNews = mockNews.filter(item => item.category === category); - } - - // 按关键词搜索 - if (query) { - const searchQuery = query.toLowerCase(); - mockNews = mockNews.filter(item => - item.title.toLowerCase().includes(searchQuery) || - item.summary.toLowerCase().includes(searchQuery) || - item.tags.some(tag => tag.toLowerCase().includes(searchQuery)) - ); - } - - // 分页 - const startIndex = (page - 1) * limit; - const endIndex = startIndex + limit; - const items = mockNews.slice(startIndex, endIndex); - - return { - items, - total: mockNews.length, - page, - totalPages: Math.ceil(mockNews.length / limit), - hasNext: endIndex < mockNews.length, - hasPrev: page > 1, - }; - } - - // 模拟统计数据 - private getMockStats(): NewsStats { - return { - totalNews: 1247, - todayNews: 23, - hotNews: 8, - categoryCounts: { - 'healthcare-policy': 156, - 'medical-robotics': 89, - 'industry-trends': 234, - 'tech-innovation': 178, - 'investment': 145, - 'regulatory': 67, - 'market-analysis': 123, - 'corporate-news': 89, - 'research': 112, - 'international': 54, - }, - sourceCounts: { - '健康界': 89, - '医学界': 76, - '动脉网': 65, - '36氪': 54, - '亿欧': 43, - }, - trending: [ - { keyword: 'AI医疗', count: 45, trend: 'up' }, - { keyword: '智能养老', count: 32, trend: 'up' }, - { keyword: '医疗机器人', count: 28, trend: 'stable' }, - { keyword: '数字疗法', count: 23, trend: 'up' }, - { keyword: '远程医疗', count: 19, trend: 'down' }, - ], - }; - } - - // 生成模拟新闻数据 - private generateMockNews(): NewsItem[] { - const categories: NewsCategory[] = [ - 'healthcare-policy', 'medical-robotics', 'industry-trends', - 'tech-innovation', 'investment', 'regulatory' - ]; - - const sources = ['健康界', '医学界', '动脉网', '36氪', '亿欧', '投中网', '甲子光年']; - - const mockTitles = [ - '国家卫健委发布智慧医院建设指导意见', - '医疗机器人行业迎来政策利好,市场规模预计突破千亿', - 'AI诊断技术获得NMPA批准,准确率达95%以上', - '康养产业数字化转型加速,智能设备普及率大幅提升', - '某知名医疗机器人公司完成B轮融资,估值达50亿', - '远程医疗服务覆盖率达85%,偏远地区医疗资源配置优化', - '智能可穿戴设备在慢病管理中的应用效果显著', - '医疗大数据安全管理新规正式实施', - '手术机器人技术突破,微创手术成功率提升30%', - '养老院智能化改造项目启动,覆盖全国重点城市', - '数字疗法首次纳入医保目录,患者负担大幅减轻', - '国际医疗AI标准化组织成立,中国企业积极参与', - '5G+医疗应用场景不断拓展,急救效率显著提升', - '医疗机器人出口量创新高,"中国制造"走向世界', - '智慧医院建设标准发布,推动行业规范化发展' - ]; - - return Array.from({ length: 50 }, (_, index) => { - const category = categories[index % categories.length]; - const source = sources[index % sources.length]; - const title = mockTitles[index % mockTitles.length]; - const publishedAt = new Date(Date.now() - Math.random() * 7 * 24 * 60 * 60 * 1000).toISOString(); - - return { - id: `news_${index + 1}`, - title, - summary: `${title}的详细内容摘要,包含关键信息和重要数据。本文深入分析了相关政策影响、技术发展趋势以及市场前景,为行业发展提供重要参考。`, - category, - tags: this.generateTags(category), - source, - sourceUrl: `https://${source.toLowerCase()}.com/article/${index + 1}`, - publishedAt, - crawledAt: new Date().toISOString(), - imageUrl: `https://images.unsplash.com/photo-${1576091160000 + index}?w=400&h=200&fit=crop`, - priority: ['high', 'medium', 'low'][index % 3] as any, - isHot: index < 8, - viewCount: Math.floor(Math.random() * 5000) + 100, - region: index % 3 === 0 ? '北京' : index % 3 === 1 ? '上海' : '深圳', - }; - }); - } - - // 根据分类生成标签 - private generateTags(category: NewsCategory): string[] { - const tagMap: Record = { - 'healthcare-policy': ['政策', '卫健委', '医保', '监管'], - 'medical-robotics': ['机器人', '手术', 'AI', '自动化'], - 'industry-trends': ['趋势', '市场', '发展', '前景'], - 'tech-innovation': ['创新', '技术', '突破', '研发'], - 'investment': ['融资', '投资', '估值', '资本'], - 'regulatory': ['法规', '标准', '合规', '监管'], - 'market-analysis': ['分析', '报告', '数据', '市场'], - 'corporate-news': ['企业', '公司', '合作', '战略'], - 'research': ['研究', '论文', '成果', '学术'], - 'international': ['国际', '全球', '海外', '出口'], - }; - - const baseTags = tagMap[category] || ['新闻']; - return baseTags.slice(0, Math.floor(Math.random() * 3) + 2); - } - // 清除缓存 clearCache(): void { this.cache.clear(); diff --git a/src/types/news.ts b/src/types/news.ts index 1f72f91..0b1ca46 100644 --- a/src/types/news.ts +++ b/src/types/news.ts @@ -23,9 +23,10 @@ export interface NewsItem { export type NewsCategory = | 'healthcare-policy' // 康养政策 | 'medical-robotics' // 医疗机器人 - | 'industry-trends' // 行业动态 + | 'smart-elderly-care' // 智慧养老 | 'tech-innovation' // 技术前沿 | 'investment' // 投融资 + | 'industry-trends' // 行业动态 | 'regulatory' // 监管动态 | 'market-analysis' // 市场分析 | 'corporate-news' // 企业动态 diff --git a/test-frontend-api.html b/test-frontend-api.html new file mode 100644 index 0000000..bafc796 --- /dev/null +++ b/test-frontend-api.html @@ -0,0 +1,52 @@ + + + + API连接测试 + + +

前端API连接测试

+ +
+ + + + \ No newline at end of file