返回 AiToEarn
index.tsx
1 import React, { useState, useEffect } from 'react';
2 import {
3 platformApi,
4 Platform,
5 PlatformRanking,
6 RankingContent,
7 PaginationMeta,
8 } from '@/api/platform';
9 import { Pagination, Modal, Popover, DatePicker } from 'antd';
10 import {
11 InfoCircleOutlined,
12 DownOutlined,
13 RightOutlined,
14 UserOutlined,
15 } from '@ant-design/icons';
16 import { getImageUrl } from '@/config';
17 import dayjs from 'dayjs';
18 import 'dayjs/locale/zh-cn';
19 import locale from 'antd/es/date-picker/locale/zh_CN';
20
21 // 声明全局 electron 对象
22 declare global {
23 interface Window {
24 electron: {
25 openExternal: (url: string) => Promise<void>;
26 };
27 }
28 }
29
30 // 定义榜单内容项的接口
31 interface RankingItem {
32 id: string;
33 title: string;
34 author: {
35 name: string;
36 avatar: string;
37 followers: string;
38 };
39 category: {
40 name: string;
41 subCategory: string;
42 };
43 duration: string;
44 views: string;
45 likes: string;
46 comments: string;
47 engagement: string;
48 thumbnail: string;
49 createTime: string;
50 }
51
52 // 在文件顶部添加或更新接口定义
53 interface TopicContent {
54 id: string;
55 title: string;
56 type: string;
57 description: string | null;
58 msgType: string;
59 category: string;
60 subCategory: string | null;
61 author: string;
62 avatar: string;
63 cover: string;
64 authorId: string;
65 fans: number;
66 topics: string[];
67 rank: number;
68 shareCount: number;
69 likeCount: number;
70 watchingCount: number | null;
71 readCount: number;
72 publishTime: string;
73 url: string;
74 platformId: {
75 id: string;
76 name: string;
77 icon: string;
78 };
79 hotValue?: number;
80
81 commentCount: number;
82 collectCount: number;
83 // ... 其他属性
84 }
85
86 interface TopicResponse {
87 items: TopicContent[];
88 meta: {
89 currentPage: number;
90 itemCount: number;
91 itemsPerPage: number;
92 totalItems: number;
93 totalPages: number;
94 };
95 }
96
97 // 在文件顶部添加热点事件相关的接口
98 interface HotTopic {
99 id: string;
100 title: string;
101 hotValue: number;
102 url: string;
103 rank: number;
104 rankChange: number;
105 isRising: boolean;
106 platformId: {
107 id: string;
108 name: string;
109 icon: string;
110 };
111 hotValueHistory: HotValueHistory[]; // 热度趋势数据
112 }
113
114 interface PlatformHotTopics {
115 platform: {
116 id: string;
117 name: string;
118 icon: string;
119 type: string;
120 };
121 topics: HotTopic[];
122 }
123
124 // 在文件顶部添加爆款标题相关的接口
125 interface ViralTitle {
126 id: string;
127 title: string;
128 platformId: string | Platform | any; // 使用 any 处理不确定的类型
129 category: string;
130 publishTime: string | null | Date | undefined; // 添加 Date 和 undefined 类型
131 engagement: number;
132 url: string;
133 rank: number;
134 createTime: string | Date; // 添加 Date 类型
135 updateTime: string | Date; // 添加 Date 类型
136 }
137
138 interface ViralTitleCategory {
139 category: string;
140 titles: ViralTitle[];
141 }
142
143 // 在热度趋势图部分修改代码
144 interface HotValueHistory {
145 hotValue: number;
146 timestamp: string;
147 }
148
149 interface Topic extends HotTopic {
150 // 继承 HotTopic 的所有属性
151 }
152
153 // 修改主题色常量
154 const THEME = {
155 primary: '#a66ae4',
156 primaryHover: '#9559d1',
157 primaryLight: '#f4ebff',
158 primaryBorder: '#e6d3f7',
159 };
160
161 // 修改按钮相关的样式类
162 const buttonStyles = {
163 base: 'px-4 py-2 rounded-md text-sm transition-all duration-200 border-none outline-none',
164 primary: `bg-[#a66ae4] text-white hover:bg-[#9559d1]`,
165 secondary: `bg-gray-50 text-gray-600 hover:bg-[#f4ebff] hover:text-[#a66ae4]`,
166 };
167
168 // 数据说明内容组件
169 const DataInfoContent: React.FC<{ ranking: PlatformRanking }> = ({
170 ranking,
171 }) => (
172 <div className="text-sm text-gray-600">
173 <div className="mb-1">
174 <span className="font-medium">更新时间:</span>
175 {ranking.updateFrequency}
176 </div>
177 <div className="mb-1">
178 <span className="font-medium">统计数据截止:</span>
179 {new Date(ranking.updateTime).toLocaleString('zh-CN', {
180 year: 'numeric',
181 month: '2-digit',
182 day: '2-digit',
183 hour: '2-digit',
184 minute: '2-digit',
185 })}
186 </div>
187 <div className="mb-1">
188 <span className="font-medium">时间查看:</span>
189 按日
190 </div>
191 <div>
192 <span className="font-medium">排序规则:</span>
193 统计当日点赞量前500名的作品推荐
194 </div>
195 </div>
196 );
197
198 // 格式化数字,超过10000显示为w单位
199 const formatNumber = (num: number) => {
200 if (!num && num !== 0) return '0';
201
202 if (num >= 10000) {
203 return (num / 10000).toFixed(1) + 'w';
204 }
205
206 return num.toString();
207 };
208
209 const Trending: React.FC = () => {
210 const [selectedPlatform, setSelectedPlatform] = useState<Platform | null>(
211 null,
212 );
213 const [selectedRanking, setSelectedRanking] =
214 useState<PlatformRanking | null>(null);
215 const [rankingList, setRankingList] = useState<PlatformRanking[]>([]);
216 const [rankingDatesList, setRankingDatesList] = useState<[]>([]); // 榜单日期列表
217 const [selectedDate, setSelectedDate] = useState<string>(
218 dayjs().subtract(2, 'day').format('YYYY-MM-DD'),
219 );
220 const [rankingMinDate, setRankingMinDate] = useState<string>(
221 dayjs().subtract(2, 'day').format('YYYY-MM-DD'),
222 );
223 const [rankingMaxDate, setRankingMaxDate] = useState<string>(
224 dayjs().subtract(2, 'day').format('YYYY-MM-DD'),
225 );
226 const [rankingDateLoading, setRankingDateLoading] = useState(false);
227 const [platforms, setPlatforms] = useState<Platform[]>([]);
228 const [rankingItems, setRankingItems] = useState<RankingItem[]>([]);
229 const [loading, setLoading] = useState(false);
230 const [rankingLoading, setRankingLoading] = useState(false);
231 const [rankingContents, setRankingContents] = useState<RankingContent[]>([]);
232 const [pagination, setPagination] = useState<PaginationMeta | null>(null);
233 const [currentPage, setCurrentPage] = useState(1);
234 const [isModalVisible, setIsModalVisible] = useState(false);
235 const [currentUrl, setCurrentUrl] = useState('');
236 const [categories, setCategories] = useState<string[]>(['全部']);
237 const [selectedCategory, setSelectedCategory] = useState<string>('全部');
238 const [categoryLoading, setCategoryLoading] = useState(false);
239 const [isExpanded, setIsExpanded] = useState(false);
240 const [currentTitle, setCurrentTitle] = useState('');
241 const [topicCategories, setTopicCategories] = useState<string[]>([]);
242 const [contentExpanded, setContentExpanded] = useState(true);
243 const [topicExpanded, setTopicExpanded] = useState(false);
244
245 // 热门专题的独立状态
246 const [selectedMsgType, setSelectedMsgType] = useState<string>('');
247 const [msgTypeList, setMsgTypeList] = useState<string[]>([]);
248 const [topicList, setTopicList] = useState<string[]>([]); // 专题标签列表
249 const [topicSubCategories, setTopicSubCategories] = useState<string[]>([]);
250 const [selectedTopicCategory, setSelectedTopicCategory] =
251 useState<string>('');
252 const [selectedTopicSubCategory, setSelectedTopicSubCategory] =
253 useState<string>('');
254 const [topicContents, setTopicContents] = useState<TopicContent[]>([]);
255 const [topicLoading, setTopicLoading] = useState(false);
256 const [topicPagination, setTopicPagination] = useState<PaginationMeta | null>(
257 null,
258 );
259
260 // 话题相关状态
261 const [talkExpanded, setTalkExpanded] = useState(false);
262 const [talkLoading, setTalkLoading] = useState(false);
263 const [talkPagination, setTalkPagination] = useState<PaginationMeta | null>(
264 null,
265 );
266 const [talkPlatforms, setTalkPlatforms] = useState<Platform[]>([]);
267 const [selectedTalkPlatform, setSelectedTalkPlatform] =
268 useState<Platform | null>(null);
269 const [selectedTalkColumn, setSelectedTalkColumn] = useState<string>('');
270 const [selectedTalkCategory, setSelectedTalkCategory] = useState<string>('');
271 const [selectedTalkXhsTimeRange, setSelectedTalkXhsTimeRange] =
272 useState<string>('24小时'); // 小红书话题时间筛选 默认选中24小时
273
274 // 在右侧内容区 - 热门专题界面部分添加筛选区
275 const [selectedPlatformId, setSelectedPlatformId] = useState<string>('');
276 const [selectedTopicType, setSelectedTopicType] = useState<string>('');
277 const [topicTypes, setTopicTypes] = useState<string[]>([]);
278
279 // 添加图片错误处理的状态
280 const [imgErrors, setImgErrors] = useState<{ [key: string]: boolean }>({});
281
282 // 在组件内添加状态
283 const [hotEventExpanded, setHotEventExpanded] = useState(false);
284 const [hotPlatformExpanded, setHotPlatformExpanded] = useState(false);
285 const [hotTopics, setHotTopics] = useState<PlatformHotTopics[]>([]);
286 const [hotTopicLoading, setHotTopicLoading] = useState(false);
287
288 // 添加爆款标题相关的状态
289 const [viralTitleExpanded, setViralTitleExpanded] = useState(false);
290 const [viralTitlePlatforms, setViralTitlePlatforms] = useState<Platform[]>(
291 [],
292 );
293 const [selectedViralPlatform, setSelectedViralPlatform] =
294 useState<Platform | null>(null);
295 const [viralTitleCategories, setViralTitleCategories] = useState<string[]>(
296 [],
297 );
298 const [selectedViralCategory, setSelectedViralCategory] =
299 useState<string>('');
300 const [viralTitleData, setViralTitleData] = useState<ViralTitleCategory[]>(
301 [],
302 );
303 const [viralTitleLoading, setViralTitleLoading] = useState(false);
304
305 // 在 Trending 组件中添加新的状态
306 const [isCategoryExpanded, setIsCategoryExpanded] = useState(false);
307
308 // 添加新的状态
309 const [showSingleCategory, setShowSingleCategory] = useState(false);
310 const [singleCategoryData, setSingleCategoryData] = useState<ViralTitle[]>(
311 [],
312 );
313 const [singleCategoryName, setSingleCategoryName] = useState('');
314 const [singleCategoryLoading, setSingleCategoryLoading] = useState(false);
315 const [singleCategoryPagination, setSingleCategoryPagination] =
316 useState<PaginationMeta | null>(null);
317
318 // 在 Trending 组件中添加时间筛选状态
319 const [selectedTimeRange, setSelectedTimeRange] = useState<string>('近7天'); // 默认选中近7天
320 const timeRangeOptions = [];
321 const [selectedViralTimeRange, setViralSelectedTimeRange] =
322 useState<string>('近7天'); // 爆款标题时间筛选 默认选中近7天
323
324 // 在 Trending 组件中添加时间类型状态
325 const [timeTypes, setTimeTypes] = useState<string[]>([]);
326 const [selectedTimeType, setSelectedTimeType] = useState<string>('');
327 const [selectedViralTimeType, setViralSelectedTimeType] =
328 useState<string>('近7天');
329
330 // 通用的一些固定值
331 const platformIdParams = {
332 xhsPlatformId: '6789d6a69b3e38d8da09ba47',
333 dyPlatformId: '6789d6a69b3e38d8da09ba48',
334 ksPlatformId: '678a3c1b18789840c02c806f',
335 biliPlatformId: '678a3c6218789840c02c8070',
336 gzhPlatformId: '679095d7df03a9e7d4b30ec9',
337 sphPlatformId: '678a3bdb18789840c02c806e',
338 };
339 // const xhsPlatformId = '6789d6a69b3e38d8da09ba47';
340 // const dyPlatformId = '6789d6a69b3e38d8da09ba48';
341 // const ksPlatformId = '678a3c1b18789840c02c806f';
342 // const biliPlatformId = '678a3c6218789840c02c8070';
343 // const gzhPlatformId = '679095d7df03a9e7d4b30ec9';
344 // const sphPlatformId = '678a3bdb18789840c02c806e';
345
346 // 添加处理图片加载错误的函数
347 const handleImageError = (imageId: string) => {
348 setImgErrors((prev) => ({
349 ...prev,
350 [imageId]: true,
351 }));
352 };
353
354 // 获取平台数据和专题分类
355 useEffect(() => {
356 const fetchData = async () => {
357 setLoading(true);
358 try {
359 // 获取平台列表
360 const platformData = await platformApi.getPlatformList();
361 console.log('platformData:', platformData);
362 setPlatforms(platformData);
363 if (platformData.length > 0) {
364 const firstPlatform = platformData[0];
365 setSelectedPlatform(firstPlatform);
366 fetchPlatformRanking(firstPlatform.id);
367 }
368
369 // // 获取专题分类
370 // const topicData = await platformApi.getMsgType();
371 // setMsgTypeList(topicData);
372 } catch (error) {
373 console.error('获取数据失败:', error);
374 } finally {
375 setLoading(false);
376 }
377 };
378
379 fetchData();
380 }, []);
381
382 // 获取平台榜单数据
383 const fetchPlatformRanking = async (platformId: string) => {
384 console.log('fetchPlatformRanking:', platformId);
385 setRankingLoading(true);
386 try {
387 const rankingData = await platformApi.getPlatformRanking(platformId);
388 console.log('rankingData:', rankingData);
389 setRankingList(rankingData);
390
391 // 自动选择第一个榜单并获取其内容
392 if (rankingData.length > 0) {
393 const firstRanking = rankingData[0];
394 // 获取榜单日期
395 await fetchRankingDates(firstRanking.id);
396
397 setSelectedRanking(firstRanking);
398
399 // // 获取榜单分类
400 await fetchRankingCategories(firstRanking.id);
401
402 // // 获取榜单内容
403 // await fetchRankingContents(firstRanking.id, 1);
404
405 // 重置页码到第一页
406 setCurrentPage(1);
407 } else {
408 // 如果没有榜单数据,清空相关状态
409 setSelectedRanking(null);
410 setCategories(['全部']);
411 setSelectedCategory('全部');
412 setRankingContents([]);
413 setCurrentPage(1);
414 // ... 可能还需要清空 datesList, min/max date 等 ...
415 setRankingDatesList([]);
416 setRankingMaxDate('');
417 setRankingMinDate('');
418 }
419 } catch (error) {
420 console.error('获取平台榜单失败:', error);
421 setRankingList([]);
422 setSelectedRanking(null);
423 setCategories(['全部']);
424 setSelectedCategory('全部');
425 setRankingContents([]);
426 setCurrentPage(1);
427 setRankingDatesList([]);
428 setRankingMaxDate('');
429 setRankingMinDate('');
430 } finally {
431 setRankingLoading(false);
432 }
433 };
434
435 // 获取榜单分类
436 const fetchRankingCategories = async (rankingId: string) => {
437 setCategoryLoading(true);
438 try {
439 const data = await platformApi.getRankingLabel(rankingId);
440
441 // 检查数据中是否已经包含"全部"选项
442 if (data.includes('全部')) {
443 // 如果已经包含"全部",则将其移到数组第一位
444 const filteredData = data.filter((item) => item !== '全部');
445 setCategories(['全部', ...filteredData]);
446 } else {
447 // 如果不包含"全部",则添加到列表开头
448 setCategories(['全部', ...data]);
449 }
450
451 // 默认选中"全部"
452 setSelectedCategory('全部');
453 } catch (error) {
454 console.error('获取榜单分类失败:', error);
455 setCategories(['全部']); // 出错时至少保留"全部"选项
456 } finally {
457 setCategoryLoading(false);
458 }
459 };
460
461 // 获取榜单日期列表
462 const fetchRankingDates = async (rankingId: string) => {
463 setRankingDateLoading(true);
464 let fetchedMaxDate = ''; // 用于临时存储获取到的日期
465 try {
466 const rankingDatesData = await platformApi.getRankingDates(rankingId);
467 console.log('fetchRankingDates:--', rankingId, rankingDatesData);
468 if (rankingDatesData && rankingDatesData.length > 0) {
469 const maxDate = (rankingDatesData[0] as any).queryDate;
470 const minDate = (rankingDatesData[rankingDatesData.length - 1] as any)
471 .queryDate;
472 setRankingMaxDate(maxDate);
473 setRankingMinDate(minDate);
474 fetchedMaxDate = maxDate; // 保存获取到的日期
475 setRankingDatesList(rankingDatesData as any);
476 } else {
477 // 没有日期数据,清空相关状态
478 setRankingMaxDate('');
479 setRankingMinDate('');
480 setRankingDatesList([]);
481 fetchedMaxDate = ''; // 没有日期,设为空
482 }
483 } catch (error) {
484 console.error('获取榜单日期列表失败:', error);
485 setRankingMaxDate('');
486 setRankingMinDate('');
487 setRankingDatesList([]);
488 fetchedMaxDate = ''; // 出错也设为空
489 } finally {
490 // 这将触发上面定义的 useEffect (如果 selectedDate 确实改变了)
491 setSelectedDate(fetchedMaxDate);
492 console.log('检查日期:', fetchedMaxDate, selectedDate);
493 setRankingDateLoading(false);
494 }
495 };
496
497 // 这个 useEffect 负责在依赖变化时获取榜单内容
498 useEffect(() => {
499 // 从 selectedRanking 中获取 rankingId
500 const currentRankingId = selectedRanking?.id; // 使用可选链 ?. 安全访问 id
501
502 // 检查依赖项是否有效,防止在初始状态或无效状态下发起请求
503 // 重要:这里的检查条件要根据你的逻辑调整:
504 // - currentRankingId 必须存在
505 // - selectedDate 必须存在且不为空字符串 (或者你用来表示“未选择”的其他值)
506 if (currentRankingId && selectedDate && selectedDate !== '') {
507 // 调用 fetchRankingContents,传入当前有效的依赖值
508 fetchRankingContents(
509 currentRankingId,
510 currentPage,
511 selectedCategory,
512 selectedDate,
513 );
514 } else {
515 // 如果依赖项无效(例如,刚加载还没有选择榜单,或者日期被清空),
516 // 你可能想清空内容列表
517 console.log(
518 'useEffect for content: 依赖项 (rankingId 或 selectedDate) 无效,清空内容',
519 );
520 setRankingContents([]);
521 } // 依赖项数组: 当数组中的任何一个值发生变化时,useEffect 内部的函数会重新执行
522 }, [selectedRanking, selectedCategory, selectedDate, currentPage]); // 依赖 selectedRanking, selectedDate 和 currentPage
523
524 // 获取榜单内容
525 const fetchRankingContents = async (
526 rankingId: string,
527 page = 1,
528 category?: string,
529 formattedDate?: string,
530 ) => {
531 setRankingLoading(true);
532 const dates = formattedDate ? formattedDate : selectedDate;
533 try {
534 const response = await platformApi.getRankingContents(
535 rankingId,
536 page,
537 20,
538 category,
539 dates,
540 );
541 setRankingContents(response.items);
542 setPagination(response.meta);
543 } catch (error) {
544 console.error('获取榜单内容失败:', error);
545 setRankingContents([]);
546 setPagination(null);
547 } finally {
548 setRankingLoading(false);
549 }
550 };
551
552 // 处理平台选择
553 const handlePlatformSelect = (platform: Platform) => {
554 // 设置选中的平台
555 setSelectedPlatform(platform);
556
557 // 清空原有数据并显示加载动画
558 setRankingList([]);
559 setSelectedRanking(null);
560 setCategories(['全部']);
561 setSelectedCategory('全部');
562 setRankingContents([]);
563 setRankingLoading(true);
564
565 // 关闭热门专题展开
566 setTopicExpanded(false);
567
568 // 获取新平台的榜单数据
569 fetchPlatformRanking(platform.id);
570 };
571
572 // 修改榜单选择处理函数
573 const handleRankingSelect = async (ranking: PlatformRanking) => {
574 // 如果点击的是当前已选中的榜单,不做任何操作
575 if (selectedRanking?.id === ranking.id) return;
576
577 // 设置选中的榜单
578 setSelectedRanking(ranking);
579
580 // 重置分页到第一页
581 setCurrentPage(1);
582
583 // 获取榜单内容
584 await fetchRankingContents(
585 ranking.id,
586 1,
587 selectedCategory !== '全部' ? selectedCategory : undefined,
588 );
589 };
590
591 // 处理页码变化
592 const handlePageChange = (page: number) => {
593 if (selectedRanking && page !== pagination?.currentPage) {
594 setCurrentPage(page);
595 fetchRankingContents(selectedRanking.id, page, selectedCategory);
596 // 滚动到顶部
597 window.scrollTo({
598 top: 0,
599 behavior: 'smooth',
600 });
601 }
602 };
603
604 // 处理内容点击
605 const handleContentClick = (url: string, title: string) => {
606 setCurrentUrl(url);
607 setCurrentTitle(title);
608 setIsModalVisible(true);
609 };
610
611 // 处理模态框关闭
612 const handleModalClose = () => {
613 setIsModalVisible(false);
614 setCurrentUrl('');
615 setCurrentTitle('');
616 };
617
618 // 处理分类选择
619 const handleCategorySelect = (category: string) => {
620 setSelectedCategory(category);
621 if (selectedRanking) {
622 // 当选择"全部"时,不传递 category 参数
623 const categoryParam = category === '全部' ? undefined : category;
624 fetchRankingContents(selectedRanking.id, 1, categoryParam);
625 }
626 };
627
628 // 处理日期变化
629 const handleDateChange = (date: dayjs.Dayjs | null) => {
630 const formattedDate = date
631 ? date.format('YYYY-MM-DD')
632 : dayjs().format('YYYY-MM-DD');
633 setSelectedDate(formattedDate);
634 if (selectedRanking) {
635 fetchRankingContents(
636 selectedRanking.id,
637 1,
638 selectedCategory === '全部' ? undefined : selectedCategory,
639 formattedDate,
640 );
641 }
642 };
643
644 // 获取爆款标题平台列表
645 const fetchViralTitlePlatforms = async () => {
646 setViralTitleLoading(true);
647 try {
648 const platforms = await platformApi.findPlatformsWithData();
649 const timeTypeData = await platformApi.getViralTitleTimeTypes();
650 setViralTitlePlatforms(platforms);
651 if (platforms.length > 0) {
652 setSelectedViralPlatform(platforms[0]);
653 fetchViralTitleCategories(platforms[0].id);
654 fetchViralTitleContents(platforms[0].id, timeTypeData[0]);
655 }
656 } catch (error) {
657 console.error('获取爆款标题平台失败:', error);
658 setViralTitlePlatforms([]);
659 } finally {
660 setViralTitleLoading(false);
661 }
662 };
663
664 // 获取爆款标题时间类型
665 const fetchViralTitleTimeTypes = async () => {
666 try {
667 const timeTypeData = await platformApi.getViralTitleTimeTypes();
668 setTimeTypes(timeTypeData);
669
670 // 如果有时间类型,自动选择第一个
671 if (timeTypeData.length > 0) {
672 setViralSelectedTimeRange(timeTypeData[0]);
673 }
674 } catch (error) {
675 console.error('获取爆款标题时间类型失败:', error);
676 setTimeTypes([]);
677 }
678 };
679
680 // 获取爆款标题分类和时间类型
681 const fetchViralTitleCategories = async (platformId: string) => {
682 try {
683 const categories = await platformApi.findCategoriesByPlatform(platformId);
684 setViralTitleCategories(categories);
685 fetchViralTitleTimeTypes();
686 if (categories.length > 0) {
687 setSelectedViralCategory('');
688 }
689 } catch (error) {
690 console.error('获取爆款标题分类失败:', error);
691 setViralTitleCategories([]);
692 }
693 };
694
695 // 获取爆款标题数据
696 const fetchViralTitleContents = async (
697 platformId: string,
698 timeType: string,
699 ) => {
700 setViralTitleLoading(true);
701 try {
702 const data = await platformApi.findTopByPlatformAndCategories(
703 platformId,
704 timeType,
705 );
706 // 使用 as any 绕过类型检查
707 const formattedData = data.map((item) => ({
708 category: item.category,
709 titles: item.titles.map((title) => ({
710 ...title,
711 platformId:
712 typeof title.platformId === 'object'
713 ? title.platformId.id
714 : title.platformId,
715 // 确保 publishTime 是 string 或 null
716 publishTime: title.publishTime ? title.publishTime.toString() : null,
717 // 确保 createTime 和 updateTime 是 string
718 // createTime: title.createTime.toString(),
719 updateTime: title.updateTime,
720 })),
721 })) as any;
722
723 setViralTitleData(formattedData);
724 } catch (error) {
725 console.error('获取爆款标题数据失败:', error);
726 setViralTitleData([]);
727 } finally {
728 setViralTitleLoading(false);
729 }
730 };
731
732 // 处理爆款标题平台选择
733 const handleViralPlatformSelect = (platform: Platform, timeType: string) => {
734 setSelectedViralPlatform(platform);
735 // 清空原有数据并显示加载动画
736 setSelectedViralCategory('全部');
737 setShowSingleCategory(false);
738 setViralTitleData([]);
739 fetchViralTitleCategories(platform.id);
740 fetchViralTitleTimeTypes(); // 获取时间类型
741 fetchViralTitleContents(platform.id, timeType);
742 };
743
744 // 修改处理爆款标题分类选择的函数
745 const handleViralCategorySelect = async (category: string) => {
746 setSelectedViralCategory(category);
747
748 if (category && selectedViralPlatform && selectedViralTimeRange) {
749 // 如果选择了特定分类,调用API获取该分类数据
750 console.log(
751 'handleViralCategorySelect:',
752 category,
753 selectedViralTimeRange,
754 selectedViralTimeType,
755 );
756 setSingleCategoryName(category);
757 setShowSingleCategory(true);
758 fetchSingleCategoryData(
759 selectedViralPlatform.id,
760 category,
761 1,
762 selectedViralTimeType,
763 );
764 } else {
765 // 如果选择"全部",返回到分类概览
766 setShowSingleCategory(false);
767 setSingleCategoryData([]);
768 setSingleCategoryName('');
769 }
770 };
771
772 // 处理爆款标题时间类型选择 全部分类
773 const handleViralTimeTypeSelect = (category: string, timeType: string) => {
774 setViralSelectedTimeType(timeType);
775 console.log(
776 'handleViralTimeTypeSelect:',
777 selectedViralCategory,
778 category,
779 timeType,
780 selectedViralTimeType,
781 selectedViralTimeRange,
782 );
783 if (category) {
784 // 获取单独分类
785 fetchSingleCategoryData(selectedViralPlatform!.id, category, 1, timeType);
786 } else {
787 // 获取爆款标题内容 全部分类
788 fetchViralTitleContents(selectedViralPlatform!.id, timeType);
789 }
790 };
791
792 // 添加获取热门专题二级分类的函数
793 const fetchTopicTypes = async (msgType: string) => {
794 try {
795 const types = await platformApi.getTopicLabels(msgType);
796 setTopicTypes(types);
797 } catch (error) {
798 console.error('获取专题分类失败:', error);
799 setTopicTypes([]);
800 }
801 };
802
803 // 修改热门专题点击处理函数
804 const handleTopicExpandClick = async () => {
805 const newTopicExpanded = !topicExpanded;
806 console.log('切换热门专题展开状态:', newTopicExpanded);
807
808 // 更新展开状态
809 setTopicExpanded(newTopicExpanded);
810
811 // 关闭其他展开的内容
812 setContentExpanded(false);
813 setHotPlatformExpanded(false);
814 setHotEventExpanded(false);
815 setViralTitleExpanded(false);
816
817 // 如果是展开热门专题,并且有消息类型,则加载数据
818 if (newTopicExpanded && msgTypeList.length > 0) {
819 console.log('准备加载热门专题数据');
820 fetchTopicTimeTypes(msgTypeList[0]);
821 // 如果没有选择消息类型,则自动选择第一个
822 if (!selectedMsgType && msgTypeList.length > 0) {
823 setSelectedMsgType(msgTypeList[0]);
824 }
825
826 // 使用当前选择的消息类型或第一个消息类型
827 const msgType = selectedMsgType || msgTypeList[0];
828
829 // 如果没有选择平台,则使用第一个平台
830 if (!selectedPlatformId && platforms.length > 0) {
831 setSelectedPlatformId(platforms[0].id);
832 }
833
834 // 调用处理函数获取数据
835 setTopicLoading(true);
836 try {
837 // 获取二级分类
838 await fetchTopicTypes(msgType);
839
840 // 获取专题数据 - 使用时间类型参数和当前选择的平台
841 const hotTopicsData = await platformApi.getAllTopics({
842 msgType: msgType,
843 platformId:
844 selectedPlatformId ||
845 (platforms.length > 0 ? platforms[0].id : undefined),
846 timeType: selectedTimeType || selectedTimeRange,
847 });
848
849 if (hotTopicsData && hotTopicsData.items) {
850 // 类型转换,确保类型兼容
851 setTopicContents(hotTopicsData.items as unknown as TopicContent[]);
852 if (hotTopicsData.meta) {
853 setTopicPagination({
854 currentPage: hotTopicsData.meta.currentPage || 1,
855 totalPages: hotTopicsData.meta.totalPages || 1,
856 totalItems: hotTopicsData.meta.totalItems || 0,
857 itemCount: hotTopicsData.meta.itemCount || 0,
858 itemsPerPage: hotTopicsData.meta.itemsPerPage || 20,
859 });
860 }
861 } else {
862 setTopicContents([]);
863 }
864 } catch (error) {
865 console.error('获取专题数据失败:', error);
866 setTopicContents([]);
867 } finally {
868 setTopicLoading(false);
869 }
870 }
871 };
872
873 // 修改 handleMsgTypeClick 函数
874 const handleMsgTypeClick = async (type: string) => {
875 setSelectedMsgType(type);
876 setTopicLoading(true);
877 setContentExpanded(false);
878 // setSelectedPlatformId(''); // 重置平台选择
879 setSelectedTopicType(''); // 重置分类选择
880
881 try {
882 // 获取二级分类
883 await fetchTopicTypes(type);
884
885 // 获取时间范围参数
886
887 // 获取专题数据 - 使用时间范围参数
888 const hotTopicsData = await platformApi.getAllTopics({
889 msgType: type,
890 platformId: selectedPlatformId,
891 timeType: selectedTimeRange,
892 });
893
894 if (hotTopicsData && hotTopicsData.items) {
895 // 类型转换,确保类型兼容
896 setTopicContents(hotTopicsData.items as unknown as TopicContent[]);
897 if (hotTopicsData.meta) {
898 setTopicPagination({
899 currentPage: hotTopicsData.meta.currentPage || 1,
900 totalPages: hotTopicsData.meta.totalPages || 1,
901 totalItems: hotTopicsData.meta.totalItems || 0,
902 itemCount: hotTopicsData.meta.itemCount || 0,
903 itemsPerPage: hotTopicsData.meta.itemsPerPage || 20,
904 });
905 }
906 } else {
907 setTopicContents([]);
908 }
909 } catch (error) {
910 console.error('获取专题数据失败:', error);
911 setTopicContents([]);
912 } finally {
913 setTopicLoading(false);
914 }
915 };
916
917 // 修改筛选变化处理函数
918 const handleFilterChange = async (platformId?: string) => {
919 setTopicLoading(true);
920 try {
921 // 使用传入的 platformId 或当前状态
922 const currentPlatformId = platformId || selectedPlatformId;
923
924 // 准备请求参数,只包含非空值
925 const params: any = {
926 msgType: selectedMsgType,
927 timeType: selectedTimeRange,
928 };
929
930 // 只有当 platformId 有值时才添加
931 if (currentPlatformId) {
932 params.platformId = currentPlatformId;
933 }
934
935 // 只有当 type 有值时才添加
936 if (selectedTopicType && selectedTopicType.trim() !== '') {
937 params.type = selectedTopicType;
938 }
939
940 console.log('查询参数:', params); // 添加日志,方便调试
941
942 const hotTopicsData = await platformApi.getAllTopics(params);
943
944 if (hotTopicsData && hotTopicsData.items) {
945 // 类型转换,确保类型兼容
946 setTopicContents(hotTopicsData.items as unknown as TopicContent[]);
947 if (hotTopicsData.meta) {
948 setTopicPagination({
949 currentPage: hotTopicsData.meta.currentPage || 1,
950 totalPages: hotTopicsData.meta.totalPages || 1,
951 totalItems: hotTopicsData.meta.totalItems || 0,
952 itemCount: hotTopicsData.meta.itemCount || 0,
953 itemsPerPage: hotTopicsData.meta.itemsPerPage || 20,
954 });
955 }
956 } else {
957 setTopicContents([]);
958 }
959 } catch (error) {
960 console.error('筛选专题数据失败:', error);
961 setTopicContents([]);
962 } finally {
963 setTopicLoading(false);
964 }
965 };
966
967 // 修改时间筛选处理函数
968 const handleTimeRangeChange = async (timeRange: string) => {
969 setSelectedTimeRange(timeRange);
970 setTopicLoading(true);
971 try {
972 // 获取时间范围参数
973
974 const hotTopicsData = await platformApi.getAllTopics({
975 msgType: selectedMsgType,
976 platformId: selectedPlatformId,
977 type: selectedTopicType,
978 timeType: timeRange,
979 });
980
981 if (hotTopicsData && hotTopicsData.items) {
982 // 类型转换,确保类型兼容
983 setTopicContents(hotTopicsData.items as unknown as TopicContent[]);
984 if (hotTopicsData.meta) {
985 setTopicPagination({
986 currentPage: hotTopicsData.meta.currentPage || 1,
987 totalPages: hotTopicsData.meta.totalPages || 1,
988 totalItems: hotTopicsData.meta.totalItems || 0,
989 itemCount: hotTopicsData.meta.itemCount || 0,
990 itemsPerPage: hotTopicsData.meta.itemsPerPage || 20,
991 });
992 }
993 } else {
994 setTopicContents([]);
995 }
996 } catch (error) {
997 console.error('筛选专题数据失败:', error);
998 setTopicContents([]);
999 } finally {
1000 setTopicLoading(false);
1001 }
1002 };
1003
1004 // 修改获取热点事件数据的函数,修复类型错误
1005 const fetchHotTopics = async () => {
1006 setHotTopicLoading(true);
1007 try {
1008 const response = await platformApi.getAllHotTopics();
1009 console.log('getAllHotTopics:', JSON.stringify(response));
1010 // 确保 response 和 items 存在
1011 if (response && Array.isArray(response)) {
1012 // 类型转换,确保类型兼容
1013 setHotTopics(response as unknown as PlatformHotTopics[]);
1014 } else {
1015 setHotTopics([]);
1016 }
1017 } catch (error) {
1018 console.error('获取热点事件失败:', error);
1019 setHotTopics([]);
1020 } finally {
1021 setHotTopicLoading(false);
1022 }
1023 };
1024
1025 // 修改专题分页处理函数
1026 const handleTopicPageChange = async (page: number) => {
1027 if (page !== topicPagination?.currentPage) {
1028 setTopicLoading(true);
1029 try {
1030 // 准备请求参数,只包含非空值
1031 const params: any = {
1032 msgType: selectedMsgType,
1033 timeType: selectedTimeRange,
1034 page, // 添加页码
1035 };
1036
1037 // 只有当 platformId 有值时才添加
1038 if (selectedPlatformId) {
1039 params.platformId = selectedPlatformId;
1040 }
1041
1042 // 只有当 type 有值时才添加
1043 if (selectedTopicType && selectedTopicType.trim() !== '') {
1044 params.type = selectedTopicType;
1045 }
1046
1047 const hotTopicsData = await platformApi.getAllTopics(params);
1048
1049 if (hotTopicsData && hotTopicsData.items) {
1050 // 类型转换,确保类型兼容
1051 setTopicContents(hotTopicsData.items as unknown as TopicContent[]);
1052 if (hotTopicsData.meta) {
1053 setTopicPagination({
1054 currentPage: hotTopicsData.meta.currentPage || 1,
1055 totalPages: hotTopicsData.meta.totalPages || 1,
1056 totalItems: hotTopicsData.meta.totalItems || 0,
1057 itemCount: hotTopicsData.meta.itemCount || 0,
1058 itemsPerPage: hotTopicsData.meta.itemsPerPage || 20,
1059 });
1060 }
1061 } else {
1062 setTopicContents([]);
1063 }
1064
1065 // 滚动到顶部
1066 window.scrollTo({
1067 top: 0,
1068 behavior: 'smooth',
1069 });
1070 } catch (error) {
1071 console.error('获取专题数据失败:', error);
1072 setTopicContents([]);
1073 } finally {
1074 setTopicLoading(false);
1075 }
1076 }
1077 };
1078
1079 // 修改获取单个分类数据的函数
1080 const fetchSingleCategoryData = async (
1081 platformId: string,
1082 category: string,
1083 page: number = 1,
1084 timeType: string = '近7天',
1085 ) => {
1086 setSingleCategoryLoading(true);
1087 try {
1088 // 修改 API 调用,使用正确的参数格式
1089 const response = await platformApi.findByPlatformAndCategory(platformId, {
1090 category: category,
1091 page: page,
1092 pageSize: 20, // 每页显示数量
1093 timeType: timeType, // 时间类型 近7天 近30天 近90天
1094 // 可以添加其他参数,如时间范围
1095 // startTime: new Date(Date.now() - 90 * 24 * 60 * 60 * 1000), // 90天前
1096 // endTime: new Date(),
1097 });
1098
1099 // 获取响应数据
1100 const items = response.items || [];
1101
1102 // 转换数据类型
1103 const formattedItems = items.map((item) => ({
1104 ...item,
1105 platformId:
1106 typeof item.platformId === 'object'
1107 ? item.platformId.id
1108 : item.platformId,
1109 // 确保 publishTime 是 string 或 null
1110 publishTime: item.publishTime ? item.publishTime.toString() : null,
1111 // 确保 createTime 和 updateTime 是 string
1112 // createTime: item.createTime.toString(),
1113 // updateTime: item.updateTime.toString(),
1114 })) as any;
1115
1116 setSingleCategoryData(formattedItems);
1117
1118 // 使用 API 返回的分页元数据
1119 const paginationMeta = response.meta || {
1120 currentPage: page,
1121 itemsPerPage: 20,
1122 totalItems: items.length,
1123 totalPages: Math.ceil(items.length / 20),
1124 itemCount: items.length,
1125 };
1126
1127 setSingleCategoryPagination(paginationMeta as PaginationMeta);
1128 } catch (error) {
1129 console.error('获取分类数据失败:', error);
1130 setSingleCategoryData([]);
1131 setSingleCategoryPagination(null);
1132 } finally {
1133 setSingleCategoryLoading(false);
1134 }
1135 };
1136
1137 // 处理查看更多点击
1138 const handleViewMoreClick = (category: string, timeType: string) => {
1139 if (selectedViralPlatform) {
1140 setSingleCategoryName(category);
1141 setShowSingleCategory(true);
1142 fetchSingleCategoryData(selectedViralPlatform.id, category, 1, timeType);
1143 }
1144 };
1145
1146 // 处理返回全部点击
1147 const handleBackToAllCategories = () => {
1148 setShowSingleCategory(false);
1149 setSingleCategoryData([]);
1150 setSingleCategoryName('');
1151 };
1152
1153 // 处理爆款标题单个分类分页
1154 const handleSingleCategoryPageChange = (page: number) => {
1155 if (selectedViralPlatform && singleCategoryName && selectedViralTimeType) {
1156 fetchSingleCategoryData(
1157 selectedViralPlatform.id,
1158 singleCategoryName,
1159 page,
1160 selectedViralTimeType,
1161 );
1162 // 滚动到顶部
1163 window.scrollTo({
1164 top: 0,
1165 behavior: 'smooth',
1166 });
1167 }
1168 };
1169
1170 // 获取专题分类和时间类型
1171 useEffect(() => {
1172 const fetchTopicData = async () => {
1173 try {
1174 // 获取专题分类
1175 const topicData = await platformApi.getMsgType();
1176 setMsgTypeList(topicData);
1177
1178 // 如果有分类,自动选择第一个并获取其时间类型
1179 if (topicData.length > 0) {
1180 setSelectedMsgType(topicData[0]);
1181 fetchTopicTimeTypes(topicData[0]);
1182 }
1183 } catch (error) {
1184 console.error('获取专题分类失败:', error);
1185 }
1186 };
1187
1188 fetchTopicData();
1189 }, []);
1190
1191 // 获取专题时间类型
1192 const fetchTopicTimeTypes = async (msgType: string) => {
1193 try {
1194 const timeTypeData = await platformApi.getTopicTimeTypes(msgType);
1195 setTimeTypes(timeTypeData);
1196
1197 // 如果有时间类型,自动选择第一个
1198 if (timeTypeData.length > 0) {
1199 setSelectedTimeType(timeTypeData[0]);
1200 }
1201 } catch (error) {
1202 console.error('获取专题时间类型失败:', error);
1203 setTimeTypes([]);
1204 }
1205 };
1206
1207 // 处理专题分类选择
1208 const handleMsgTypeSelect = (msgType: string) => {
1209 setSelectedMsgType(msgType);
1210 setSelectedTopicCategory('');
1211 setSelectedTopicSubCategory('');
1212
1213 // 获取该分类的时间类型
1214 fetchTopicTimeTypes(msgType);
1215
1216 // 重置分页
1217 setCurrentPage(1);
1218
1219 // 获取专题内容
1220 fetchTopicContents(msgType, '', '', 1, selectedTimeType);
1221 };
1222
1223 // 处理热门专题时间类型选择
1224 const handleTimeTypeSelect = (timeType: string) => {
1225 setSelectedTimeType(timeType);
1226
1227 // 重置分页
1228 setCurrentPage(1);
1229
1230 // 获取专题内容
1231 fetchTopicContents(
1232 selectedMsgType,
1233 selectedTopicCategory,
1234 selectedTopicSubCategory,
1235 1,
1236 timeType,
1237 );
1238 };
1239
1240 // 修改获取专题内容的函数
1241 const fetchTopicContents = async (
1242 msgType: string,
1243 category: string = '',
1244 subCategory: string = '',
1245 page: number = 1,
1246 timeType: string = '',
1247 ) => {
1248 if (!msgType) return;
1249
1250 setTopicLoading(true);
1251 try {
1252 // 构建查询参数
1253 const params: any = {
1254 msgType,
1255 page,
1256 limit: 10,
1257 };
1258
1259 // 添加分类参数
1260 if (category) {
1261 params.category = category;
1262 }
1263
1264 // 添加子分类参数
1265 if (subCategory) {
1266 params.subCategory = subCategory;
1267 }
1268
1269 // 添加时间类型参数
1270 if (timeType) {
1271 params.timeType = timeType;
1272 }
1273
1274 // 添加平台ID参数
1275 if (selectedPlatformId) {
1276 params.platformId = selectedPlatformId;
1277 }
1278
1279 // 添加专题类型参数
1280 if (selectedTopicType) {
1281 params.type = selectedTopicType;
1282 }
1283
1284 const { data, meta } = (await platformApi.getAllTopics(params)) as any;
1285 setTopicContents(data);
1286 setTopicPagination(meta);
1287 } catch (error) {
1288 console.error('获取专题内容失败:', error);
1289 setTopicContents([]);
1290 setTopicPagination(null);
1291 } finally {
1292 setTopicLoading(false);
1293 }
1294 };
1295
1296 // 在热门专题界面部分添加时间类型筛选
1297 <div className="flex items-center">
1298 <span className="mr-2 text-sm text-gray-500">时间类型:</span>
1299 <div className="flex flex-wrap gap-2">
1300 {timeTypes.map((timeType) => (
1301 <button
1302 key={timeType}
1303 className={`px-3 py-1.5 text-xs rounded-md transition-all duration-200 border-none outline-none ${
1304 selectedTimeType === timeType
1305 ? 'bg-[#a66ae4] text-white hover:bg-[#9559d1]'
1306 : 'bg-gray-50 text-gray-600 hover:bg-[#f4ebff] hover:text-[#a66ae4]'
1307 }`}
1308 onClick={() => handleTimeTypeSelect(timeType)}
1309 >
1310 {timeType}
1311 </button>
1312 ))}
1313 </div>
1314 </div>;
1315
1316 // 获取话题平台列表
1317 const fetchTalksPlatforms = async () => {
1318 setTalkLoading(true);
1319 try {
1320 const platforms = await platformApi.findTalksPlatforms();
1321 // const timeTypeData = await platformApi.getViralTitleTimeTypes();
1322 setTalkPlatforms(platforms);
1323 if (platforms.length > 0) {
1324 setSelectedTalkPlatform(platforms[0]);
1325 fetchTalkColumns(platforms[0].id); // 获取话题栏目
1326 // fetchViralTitleCategories(platforms[0].id);
1327 // fetchViralTitleContents(platforms[0].id, timeTypeData[0]);
1328 }
1329 } catch (error) {
1330 console.error('获取话题平台失败:', error);
1331 setTalkPlatforms([]);
1332 } finally {
1333 setTalkLoading(false);
1334 }
1335 };
1336
1337 // 修改话题点击处理函数
1338 const handleTalkExpandClick = async () => {
1339 const newTalkExpanded = !talkExpanded;
1340 console.log('切换话题展开状态:', newTalkExpanded);
1341
1342 // 更新展开状态
1343 setTalkExpanded(newTalkExpanded);
1344
1345 // 关闭其他展开的内容
1346 setContentExpanded(false);
1347 setHotPlatformExpanded(false);
1348 setHotEventExpanded(false);
1349 setViralTitleExpanded(false);
1350 setTopicExpanded(false);
1351
1352 // 如果是展开话题,并且有消息类型,则加载数据
1353 if (newTalkExpanded && msgTypeList.length > 0) {
1354 console.log('准备加载话题数据');
1355
1356 // 如果没有选择消息类型,则自动选择第一个
1357 if (!selectedMsgType && msgTypeList.length > 0) {
1358 setSelectedMsgType(msgTypeList[0]);
1359 }
1360
1361 // 使用当前选择的消息类型或第一个消息类型
1362 const msgType = selectedMsgType || msgTypeList[0];
1363
1364 // 如果没有选择平台,则使用第一个平台
1365 if (!selectedPlatformId && platforms.length > 0) {
1366 setSelectedPlatformId(platforms[0].id);
1367 }
1368
1369 // 调用处理函数获取数据
1370 setTopicLoading(true);
1371 try {
1372 // 获取二级分类
1373 await fetchTopicTypes(msgType);
1374
1375 // 获取专题数据 - 使用时间类型参数和当前选择的平台
1376 const hotTopicsData = await platformApi.getAllTopics({
1377 msgType: msgType,
1378 platformId:
1379 selectedPlatformId ||
1380 (platforms.length > 0 ? platforms[0].id : undefined),
1381 timeType: selectedTimeType || selectedTimeRange,
1382 });
1383
1384 if (hotTopicsData && hotTopicsData.items) {
1385 // 类型转换,确保类型兼容
1386 setTopicContents(hotTopicsData.items as unknown as TopicContent[]);
1387 if (hotTopicsData.meta) {
1388 setTopicPagination({
1389 currentPage: hotTopicsData.meta.currentPage || 1,
1390 totalPages: hotTopicsData.meta.totalPages || 1,
1391 totalItems: hotTopicsData.meta.totalItems || 0,
1392 itemCount: hotTopicsData.meta.itemCount || 0,
1393 itemsPerPage: hotTopicsData.meta.itemsPerPage || 20,
1394 });
1395 }
1396 } else {
1397 setTopicContents([]);
1398 }
1399 } catch (error) {
1400 console.error('获取专题数据失败:', error);
1401 setTopicContents([]);
1402 } finally {
1403 setTopicLoading(false);
1404 }
1405 }
1406 };
1407
1408 // 获取话题栏目
1409 const fetchTalkColumns = async (platformId: string) => {
1410 try {
1411 const allTalkColumns = await platformApi.findTalksColumn(platformId);
1412 console.log(allTalkColumns);
1413 // setViralTitleCategories(categories);
1414 // fetchViralTitleTimeTypes();
1415 // if (categories.length > 0) {
1416 // setSelectedViralCategory('');
1417 // }
1418 } catch (error) {
1419 console.error('获取话题栏目失败:', error);
1420 // setViralTitleCategories([]);
1421 }
1422 };
1423
1424 // 处理话题平台选择
1425 const handleTalkPlatformSelect = async (platform: Platform) => {
1426 setSelectedTalkPlatform(platform);
1427 // 小红书话题页面
1428 if (platform.id === platformIdParams.xhsPlatformId) {
1429 // params.category = category;
1430 console.log('小红书话题页面');
1431
1432 try {
1433 const xhsDatesList = await platformApi.getXhsDates();
1434 const xhsCategoryList = await platformApi.getXhsCategories();
1435 // setViralTitlePlatforms(platforms);
1436 if (platforms.length > 0) {
1437 // setSelectedViralPlatform(platforms[0]);
1438 // fetchViralTitleCategories(platforms[0].id);
1439 // fetchViralTitleContents(platforms[0].id, timeTypeData[0]);
1440 }
1441 } catch (error) {
1442 console.error('获取小红书话题平台失败:', error);
1443 // setViralTitlePlatforms([]);
1444 }
1445 }
1446
1447 // 抖音话题页面
1448 if (platform.id === platformIdParams.dyPlatformId) {
1449 // params.category = category;
1450 console.log('抖音话题页面');
1451 }
1452
1453 // 清空原有数据并显示加载动画
1454 // setSelectedViralCategory('全部');
1455 // setShowSingleCategory(false);
1456 // setViralTitleData([]);
1457 // fetchViralTitleCategories(platform.id);
1458 // fetchViralTitleTimeTypes(); // 获取时间类型
1459 // fetchViralTitleContents(platform.id, timeType);
1460 };
1461
1462 // 修改处理话题分类选择的函数
1463 const handleTalkCategorySelect = async (category: string) => {
1464 setSelectedTalkCategory(category);
1465 console.log('handleTalkCategorySelect:--');
1466
1467 // if (category && selectedTalkPlatform && selectedTalkTimeRange) {
1468 // // 如果选择了特定分类,调用API获取该分类数据
1469 // console.log(
1470 // 'handleViralCategorySelect:',
1471 // category,
1472 // selectedViralTimeRange,
1473 // selectedViralTimeType,
1474 // );
1475 // setSingleCategoryName(category);
1476 // setShowSingleCategory(true);
1477 // fetchSingleCategoryData(
1478 // selectedViralPlatform.id,
1479 // category,
1480 // 1,
1481 // selectedViralTimeType,
1482 // );
1483 // } else {
1484 // // 如果选择"全部",返回到分类概览
1485 // setShowSingleCategory(false);
1486 // setSingleCategoryData([]);
1487 // setSingleCategoryName('');
1488 // }
1489 };
1490
1491 // 处理话题时间类型选择 全部分类
1492 const handleTalkTimeTypeSelect = (category: string, timeType: string) => {
1493 console.log('handleTalkTimeTypeSelect:-- ');
1494 // setSelectedTalkTimeType(timeType);
1495 // console.log(
1496 // 'handleViralTimeTypeSelect:',
1497 // selectedViralCategory,
1498 // category,
1499 // timeType,
1500 // selectedViralTimeType,
1501 // selectedViralTimeRange,
1502 // );
1503 // if (category) {
1504 // // 获取单独分类
1505 // fetchSingleCategoryData(selectedViralPlatform!.id, category, 1, timeType);
1506 // } else {
1507 // // 获取爆款标题内容 全部分类
1508 // fetchViralTitleContents(selectedViralPlatform!.id, timeType);
1509 // }
1510 };
1511
1512 return (
1513 <>
1514 <div className="flex h-full bg-gray-50" style={{ overflow: 'auto' }}>
1515 {/* 左侧平台列表 */}
1516 <div className="flex-shrink-0 w-48 p-4 bg-white border-r border-gray-100">
1517 {/* 热门内容 */}
1518 <div className="mb-6">
1519 <div
1520 className="flex items-center justify-between font-medium text-gray-900 mb-3 cursor-pointer hover:text-[#a66ae4]"
1521 onClick={() => {
1522 setContentExpanded(!contentExpanded);
1523 setTopicExpanded(false);
1524 setHotPlatformExpanded(false);
1525 setHotEventExpanded(false);
1526 setViralTitleExpanded(false);
1527 setTalkExpanded(false);
1528 }}
1529 >
1530 <span className="text-base font-bold">热门内容</span>
1531 {contentExpanded ? <DownOutlined /> : <RightOutlined />}
1532 </div>
1533 {contentExpanded && (
1534 <ul className="space-y-2">
1535 {loading ? (
1536 <div className="flex items-center justify-center py-4">
1537 <span className="text-gray-500">加载中...</span>
1538 </div>
1539 ) : (
1540 platforms.map((platform) => (
1541 <li
1542 key={platform.id}
1543 className={`flex items-center space-x-2 p-2 rounded cursor-pointer transition-all duration-200
1544 ${
1545 selectedPlatform?.id === platform.id
1546 ? 'bg-[#f4ebff] text-[#a66ae4]'
1547 : 'hover:bg-gray-50'
1548 }`}
1549 onClick={() => {
1550 handlePlatformSelect(platform);
1551 setTopicExpanded(false);
1552 }}
1553 >
1554 <img
1555 src={getImageUrl(platform.icon)}
1556 alt={platform.name}
1557 className="w-5 h-5"
1558 />
1559 <span>{platform.name}</span>
1560 </li>
1561 ))
1562 )}
1563 </ul>
1564 )}
1565 </div>
1566
1567 {/* 热点事件 */}
1568 <div className="mb-6">
1569 <div
1570 className="flex items-center justify-between font-medium text-gray-900 mb-3 cursor-pointer hover:text-[#a66ae4]"
1571 onClick={() => {
1572 setHotEventExpanded(!hotEventExpanded);
1573 setViralTitleExpanded(false);
1574 }}
1575 >
1576 <span className="text-base font-bold">热点事件</span>
1577 {hotEventExpanded ? <DownOutlined /> : <RightOutlined />}
1578 </div>
1579 {hotEventExpanded && (
1580 <ul className="space-y-2">
1581 <li
1582 className={`flex items-center p-2 rounded cursor-pointer transition-all duration-200 hover:bg-gray-50
1583 ${hotPlatformExpanded ? 'bg-[#f4ebff] text-[#a66ae4]' : ''}`}
1584 onClick={() => {
1585 setHotPlatformExpanded(!hotPlatformExpanded);
1586 setContentExpanded(false);
1587 setTopicExpanded(false);
1588 setViralTitleExpanded(false);
1589 if (!hotPlatformExpanded) {
1590 fetchHotTopics();
1591 }
1592 }}
1593 >
1594 {/* <InfoCircleOutlined className="mr-2" /> */}
1595 <span>八大平台热点</span>
1596 </li>
1597 </ul>
1598 )}
1599 </div>
1600
1601 {/* 热门专题 */}
1602 <div className="mb-6">
1603 <div
1604 className="flex items-center justify-between font-medium text-gray-900 mb-3 cursor-pointer hover:text-[#a66ae4]"
1605 onClick={handleTopicExpandClick}
1606 >
1607 <span className="text-base font-bold">热门专题</span>
1608 {topicExpanded ? <DownOutlined /> : <RightOutlined />}
1609 </div>
1610 {topicExpanded && (
1611 <ul className="space-y-2">
1612 {loading ? (
1613 <div className="flex items-center justify-center py-4">
1614 <span className="text-gray-500">加载中...</span>
1615 </div>
1616 ) : (
1617 msgTypeList.map((type) => (
1618 <li
1619 key={type}
1620 className={`flex items-center p-2 rounded cursor-pointer transition-all duration-200 hover:bg-gray-50
1621 ${selectedMsgType === type ? 'bg-[#f4ebff] text-[#a66ae4]' : ''}`}
1622 onClick={() => handleMsgTypeClick(type)}
1623 >
1624 {/* <InfoCircleOutlined className="mr-2" /> */}
1625 <span>{type}</span>
1626 </li>
1627 ))
1628 )}
1629 </ul>
1630 )}
1631 </div>
1632
1633 {/* 爆款标题 - 新增菜单 */}
1634 <div className="mb-6">
1635 <div
1636 className="flex items-center justify-between font-medium text-gray-900 mb-3 cursor-pointer hover:text-[#a66ae4]"
1637 onClick={() => {
1638 setViralTitleExpanded(!viralTitleExpanded);
1639 setContentExpanded(false);
1640 setTopicExpanded(false);
1641 setHotPlatformExpanded(false);
1642 setHotEventExpanded(false);
1643 if (!viralTitleExpanded) {
1644 fetchViralTitlePlatforms();
1645 }
1646 }}
1647 >
1648 <span className="text-base font-bold">爆款标题</span>
1649 {viralTitleExpanded ? <DownOutlined /> : <RightOutlined />}
1650 </div>
1651 {viralTitleExpanded && (
1652 <ul className="space-y-2">
1653 {viralTitleLoading ? (
1654 <div className="flex items-center justify-center py-4">
1655 <span className="text-gray-500">加载中...</span>
1656 </div>
1657 ) : (
1658 viralTitlePlatforms.map((platform) => (
1659 <li
1660 key={platform.id}
1661 className={`flex items-center space-x-2 p-2 rounded cursor-pointer transition-all duration-200
1662 ${
1663 selectedViralPlatform?.id === platform.id
1664 ? 'bg-[#f4ebff] text-[#a66ae4]'
1665 : 'hover:bg-gray-50'
1666 }`}
1667 onClick={() =>
1668 handleViralPlatformSelect(
1669 platform,
1670 selectedViralTimeType,
1671 )
1672 }
1673 >
1674 <img
1675 src={getImageUrl(platform.icon)}
1676 alt={platform.name}
1677 className="w-5 h-5"
1678 />
1679 <span>{platform.name}</span>
1680 </li>
1681 ))
1682 )}
1683 </ul>
1684 )}
1685 </div>
1686
1687 {/* 话题 */}
1688 {/* <div className="mb-6">
1689 <div
1690 className="flex items-center justify-between font-medium text-gray-900 mb-3 cursor-pointer hover:text-[#a66ae4]"
1691 onClick={() => {
1692 setTalkExpanded(!talkExpanded);
1693 setContentExpanded(false);
1694 setTopicExpanded(false);
1695 setHotPlatformExpanded(false);
1696 setHotEventExpanded(false);
1697 if (!talkExpanded) {
1698 fetchTalksPlatforms();
1699 }
1700 }}
1701 >
1702 <span className="text-base font-bold">话题/热词</span>
1703 {talkExpanded ? <DownOutlined /> : <RightOutlined />}
1704 </div>
1705 {talkExpanded && (
1706 <ul className="space-y-2">
1707 {talkLoading ? (
1708 <div className="flex items-center justify-center py-4">
1709 <span className="text-gray-500">加载中...</span>
1710 </div>
1711 ) : (
1712 talkPlatforms.map((platform) => (
1713 <li
1714 key={platform.id}
1715 className={`flex items-center space-x-2 p-2 rounded cursor-pointer transition-all duration-200
1716 ${
1717 selectedTalkPlatform?.id === platform.id
1718 ? 'bg-[#f4ebff] text-[#a66ae4]'
1719 : 'hover:bg-gray-50'
1720 }`}
1721 onClick={() => handleTalkPlatformSelect(platform)}
1722 >
1723 <img
1724 src={getImageUrl(platform.icon)}
1725 alt={platform.name}
1726 className="w-5 h-5"
1727 />
1728 <span>{platform.name}</span>
1729 </li>
1730 ))
1731 )}
1732 </ul>
1733 )}
1734 </div> */}
1735 </div>
1736
1737 {/* 右侧内容区 */}
1738 <div className="flex-1 p-6" style={{ overflow: 'auto' }}>
1739 {viralTitleExpanded ? (
1740 // 爆款标题内容区域
1741 <div>
1742 {/* 顶部筛选区 */}
1743 <div className="p-4 mb-4 bg-white rounded-lg shadow-sm">
1744 {/* 分类筛选 - 始终显示 */}
1745 <div className="flex flex-col space-y-2">
1746 <div
1747 className={`grid gap-2 transition-[grid-template-rows,max-height] duration-300 ease-in-out relative pr-20`}
1748 style={{
1749 gridTemplateColumns:
1750 'repeat(auto-fill, minmax(100px, 1fr))',
1751 gridTemplateRows: isCategoryExpanded ? '1fr' : '40px',
1752 maxHeight: isCategoryExpanded ? '1000px' : '40px',
1753 overflow: 'hidden',
1754 }}
1755 >
1756 <div className="contents">
1757 <button
1758 className={`${buttonStyles.base} ${
1759 !selectedViralCategory
1760 ? buttonStyles.primary
1761 : buttonStyles.secondary
1762 } truncate h-10`}
1763 onClick={() => handleViralCategorySelect('')}
1764 >
1765 全部
1766 </button>
1767 {viralTitleCategories.map((category) => (
1768 <button
1769 key={category}
1770 className={`${buttonStyles.base} ${
1771 selectedViralCategory === category
1772 ? buttonStyles.primary
1773 : buttonStyles.secondary
1774 } truncate h-10`}
1775 onClick={() => handleViralCategorySelect(category)}
1776 >
1777 {category}
1778 </button>
1779 ))}
1780 </div>
1781 {viralTitleCategories.length > 8 && (
1782 <button
1783 className="absolute right-0 top-0 h-10 px-3 flex items-center text-sm text-gray-500 hover:text-[#a66ae4] transition-colors bg-transparent border-none outline-none shadow-none"
1784 onClick={() =>
1785 setIsCategoryExpanded(!isCategoryExpanded)
1786 }
1787 >
1788 <span className="mr-1">
1789 {isCategoryExpanded ? '收起' : '展开'}
1790 </span>
1791 <InfoCircleOutlined
1792 className={`transform transition-transform duration-300 ${
1793 isCategoryExpanded ? 'rotate-180' : ''
1794 }`}
1795 />
1796 </button>
1797 )}
1798 </div>
1799 </div>
1800
1801 {/* 爆款标题时间筛选 */}
1802 <div className="flex items-center p-4">
1803 <span className="mr-3 text-sm text-gray-500">时间范围:</span>
1804 <div className="flex flex-wrap gap-2">
1805 {timeTypes.map((timeType) => (
1806 <button
1807 key={timeType}
1808 className={`${buttonStyles.base} ${
1809 selectedViralTimeType === timeType
1810 ? buttonStyles.primary
1811 : buttonStyles.secondary
1812 }`}
1813 onClick={() =>
1814 handleViralTimeTypeSelect(
1815 selectedViralCategory,
1816 timeType,
1817 )
1818 }
1819 >
1820 {timeType}
1821 </button>
1822 ))}
1823 </div>
1824 </div>
1825 </div>
1826
1827 {/* 爆款标题内容展示 */}
1828 {viralTitleLoading || singleCategoryLoading ? (
1829 <div className="flex items-center justify-center py-8">
1830 <span className="text-gray-500">加载中...</span>
1831 </div>
1832 ) : !showSingleCategory ? (
1833 // 显示所有分类
1834 <div className="grid grid-cols-1 gap-6 md:grid-cols-2">
1835 {viralTitleData.map((categoryData) => (
1836 <div
1837 key={categoryData.category}
1838 className="p-4 bg-white rounded-lg shadow-sm"
1839 style={{
1840 display:
1841 !selectedViralCategory ||
1842 selectedViralCategory === categoryData.category
1843 ? 'block'
1844 : 'none',
1845 }}
1846 >
1847 {/* 分类标题 */}
1848 <div className="flex items-center justify-between mb-4">
1849 <h3 className="text-lg font-bold text-[#a66ae4]">
1850 {categoryData.category}
1851 </h3>
1852 <a
1853 href="#"
1854 className="text-sm text-gray-500 hover:text-[#a66ae4]"
1855 ></a>
1856 </div>
1857
1858 {/* 标题列表 - 单列布局 */}
1859 <div className="space-y-3">
1860 {categoryData.titles.slice(0, 5).map((title, index) => (
1861 <div
1862 key={title.id}
1863 className="flex items-center p-3 hover:bg-gray-50 rounded-lg cursor-pointer border border-transparent hover:border-[#e6d3f7] bg-gray-50"
1864 onClick={() =>
1865 handleContentClick(title.url, title.title)
1866 }
1867 >
1868 {/* 排名 */}
1869 <div className="w-8 text-lg font-bold text-orange-500">
1870 {index + 1}
1871 </div>
1872
1873 {/* 标题信息 */}
1874 <div className="flex-1 ml-2">
1875 <div className="text-base font-bold text-left hover:text-[#a66ae4]">
1876 {title.title}
1877 </div>
1878 </div>
1879
1880 {/* 数据指标 */}
1881 <div className="flex items-center space-x-4 text-sm">
1882 <div className="text-center">
1883 <div className="text-[#a66ae4]">
1884 {title.engagement.toLocaleString()}
1885 </div>
1886 <div className="text-xs text-gray-500">
1887 互动量
1888 </div>
1889 </div>
1890 </div>
1891 </div>
1892 ))}
1893 </div>
1894
1895 {/* 底部查看更多按钮 */}
1896 <div className="mt-4 text-center">
1897 <div
1898 className="px-4 py-2 text-sm text-gray-600 hover:text-[#a66ae4] border border-gray-200 rounded-full hover:border-[#e6d3f7]"
1899 onClick={() =>
1900 // handleViewMoreClick(categoryData.category, selectedViralTimeRange)
1901 handleViralCategorySelect(categoryData.category)
1902 }
1903 >
1904 查看更多
1905 </div>
1906 </div>
1907 </div>
1908 ))}
1909
1910 {viralTitleData.length === 0 && (
1911 <div className="py-8 text-center text-gray-500 md:col-span-2">
1912 暂无爆款标题数据
1913 </div>
1914 )}
1915 </div>
1916 ) : (
1917 // 显示单个分类的所有数据
1918 <div className="p-4 bg-white rounded-lg shadow-sm">
1919 <div className="space-y-3">
1920 {singleCategoryData.map((title, index) => (
1921 <div
1922 key={title.id}
1923 className="flex items-center p-3 hover:bg-gray-50 rounded-lg cursor-pointer border border-transparent hover:border-[#e6d3f7] bg-gray-50"
1924 onClick={() =>
1925 handleContentClick(title.url, title.title)
1926 }
1927 >
1928 {/* 排名 */}
1929 <div className="w-8 text-lg font-bold text-orange-500">
1930 {(singleCategoryPagination!.currentPage - 1) *
1931 (singleCategoryPagination?.itemsPerPage || 20) +
1932 index +
1933 1 || title.rank}
1934 </div>
1935
1936 {/* 标题信息 */}
1937 <div className="flex-1 ml-2">
1938 <div className="text-base font-bold text-left hover:text-[#a66ae4]">
1939 {title.title}
1940 </div>
1941 </div>
1942
1943 {/* 数据指标 */}
1944 <div className="flex items-center space-x-4 text-sm">
1945 <div className="text-center">
1946 <div className="text-[#a66ae4]">
1947 {title.engagement.toLocaleString()}
1948 </div>
1949 <div className="text-xs text-gray-500">互动量</div>
1950 </div>
1951 </div>
1952 </div>
1953 ))}
1954 </div>
1955
1956 {/* 分页组件 */}
1957 {singleCategoryPagination &&
1958 singleCategoryPagination.totalPages > 1 && (
1959 <div className="flex justify-center mt-6 mb-8">
1960 <Pagination
1961 current={singleCategoryPagination.currentPage}
1962 total={singleCategoryPagination.totalItems}
1963 pageSize={singleCategoryPagination.itemsPerPage}
1964 showSizeChanger={false}
1965 showQuickJumper
1966 showTotal={(total) => `共 ${total} 条`}
1967 onChange={handleSingleCategoryPageChange}
1968 />
1969 </div>
1970 )}
1971
1972 {singleCategoryData.length === 0 && (
1973 <div className="py-8 text-center text-gray-500">
1974 暂无爆款标题数据
1975 </div>
1976 )}
1977 </div>
1978 )}
1979 </div>
1980 ) : hotPlatformExpanded ? (
1981 <div>
1982 {/* 热点事件内容列表 */}
1983 <div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 justify-items-center">
1984 {hotTopicLoading ? (
1985 <div className="flex items-center justify-center py-8 col-span-full">
1986 <span className="text-gray-500">加载中...</span>
1987 </div>
1988 ) : hotTopics && hotTopics.length > 0 ? (
1989 <>
1990 {hotTopics.map((platformData: PlatformHotTopics) => (
1991 <div
1992 key={platformData.platform.id}
1993 className="flex flex-col w-full p-4 bg-white rounded-lg"
1994 style={{
1995 minWidth: '300px',
1996 maxWidth: '550px',
1997 height: '500px',
1998 }}
1999 >
2000 {/* 平台标题 */}
2001 <div className="flex items-center mb-4">
2002 <div className="flex items-center space-x-2">
2003 {platformData.platform.icon &&
2004 !imgErrors[
2005 `platform-${platformData.platform.id}`
2006 ] ? (
2007 <img
2008 src={getImageUrl(platformData.platform.icon)}
2009 alt={platformData.platform.name}
2010 className="w-6 h-6"
2011 onError={() =>
2012 handleImageError(
2013 `platform-${platformData.platform.id}`,
2014 )
2015 }
2016 />
2017 ) : (
2018 <div className="w-6 h-6 bg-[#fff1f0] rounded flex items-center justify-center">
2019 <span className="text-[#ff4d4f]">
2020 {platformData.platform.name
2021 ?.charAt(0)
2022 ?.toUpperCase() || '?'}
2023 </span>
2024 </div>
2025 )}
2026 <span className="text-base font-medium">
2027 {platformData.platform.name} · 热点
2028 </span>
2029 </div>
2030 </div>
2031
2032 {/* 热点列表 - 固定高度,超出滚动,隐藏滚动条 */}
2033 <div
2034 className="flex-1 pr-1 overflow-y-auto scrollbar-hide"
2035 style={{ maxHeight: '480px' }}
2036 >
2037 <div className="space-y-2">
2038 {platformData.topics &&
2039 Array.isArray(platformData.topics) ? (
2040 platformData.topics.map((topic, index) => (
2041 <div
2042 key={topic.id || index}
2043 className="flex items-center p-2 rounded cursor-pointer hover:bg-gray-50"
2044 onClick={() =>
2045 topic.url &&
2046 handleContentClick(topic.url, topic.title)
2047 }
2048 >
2049 {/* 排名 */}
2050 <div className="flex-shrink-0 w-6 text-base">
2051 <span
2052 className={`font-medium ${index < 3 ? 'text-[#ff4d4f]' : 'text-gray-400'}`}
2053 >
2054 {index + 1}
2055 </span>
2056 </div>
2057
2058 {/* 标题和热度 */}
2059 <div className="flex items-center justify-between flex-1 min-w-0">
2060 <div className="flex-1 min-w-0 mr-2">
2061 <span
2062 className="block text-gray-900 truncate"
2063 style={{
2064 textAlign: 'left',
2065 fontSize: '14px',
2066 }}
2067 >
2068 {typeof topic.title === 'string'
2069 ? topic.title
2070 : '无标题'}
2071 </span>
2072 </div>
2073 <div className="flex items-center flex-shrink-0 space-x-2">
2074 {topic.isRising && (
2075 <span className="text-xs text-[#ff4d4f] bg-[#fff1f0] px-1 rounded flex-shrink-0">
2076
2077 </span>
2078 )}
2079 <span className="text-[#ff4d4f] whitespace-nowrap">
2080 {(topic.hotValue / 10000).toFixed(1) +
2081 'w'}
2082 </span>
2083 <div className="relative flex-shrink-0 w-16 h-4 group">
2084 {/* 热度趋势图 */}
2085 <div className="relative w-full h-full">
2086 <svg
2087 width="100%"
2088 height="100%"
2089 viewBox="0 0 100 20"
2090 preserveAspectRatio="none"
2091 >
2092 <polyline
2093 points={
2094 Array.isArray(
2095 topic.hotValueHistory,
2096 )
2097 ? topic.hotValueHistory
2098 .map(
2099 (
2100 item: HotValueHistory,
2101 i: number,
2102 ) => {
2103 const x =
2104 (i /
2105 (topic
2106 .hotValueHistory
2107 .length -
2108 1)) *
2109 100 || 0;
2110 // 归一化热度值到0-20的范围
2111 const maxHot =
2112 Math.max(
2113 ...topic.hotValueHistory.map(
2114 (
2115 h: HotValueHistory,
2116 ) => h.hotValue,
2117 ),
2118 );
2119 const minHot =
2120 Math.min(
2121 ...topic.hotValueHistory.map(
2122 (
2123 h: HotValueHistory,
2124 ) => h.hotValue,
2125 ),
2126 );
2127 const range =
2128 maxHot - minHot;
2129 const y =
2130 range === 0
2131 ? 10
2132 : 20 -
2133 ((item.hotValue -
2134 minHot) /
2135 range) *
2136 20;
2137 return `${x},${y}`;
2138 },
2139 )
2140 .join(' ')
2141 : ''
2142 }
2143 fill="none"
2144 stroke="#ff4d4f"
2145 strokeWidth="1.5"
2146 />
2147 </svg>
2148 </div>
2149 </div>
2150 </div>
2151 </div>
2152 </div>
2153 ))
2154 ) : (
2155 <div className="text-center text-gray-500">
2156 暂无热点数据
2157 </div>
2158 )}
2159 </div>
2160 </div>
2161 </div>
2162 ))}
2163 </>
2164 ) : (
2165 <div className="py-8 text-center text-gray-500 col-span-full">
2166 暂无热点事件数据
2167 </div>
2168 )}
2169 </div>
2170 </div>
2171 ) : topicExpanded ? (
2172 // 热门专题界面
2173 <div>
2174 {/* 顶部筛选区 */}
2175 <div className="p-4 mb-4 bg-white rounded-lg shadow-sm">
2176 {/* 平台筛选 */}
2177 <div className="flex flex-col space-y-4">
2178 <div className="flex flex-wrap gap-2">
2179 {platforms.map((platform) => (
2180 <button
2181 key={platform.id}
2182 className={`${buttonStyles.base} ${
2183 selectedPlatformId === platform.id
2184 ? buttonStyles.primary
2185 : buttonStyles.secondary
2186 }`}
2187 onClick={() => {
2188 const platformId = platform.id;
2189 // 先设置平台 ID
2190 setSelectedPlatformId(platformId);
2191 // 直接调用查询,传入当前点击的平台 ID
2192 handleFilterChange(platformId);
2193 }}
2194 >
2195 <div className="flex items-center space-x-2">
2196 {platform.icon &&
2197 !imgErrors[`platform-${platform.id}`] ? (
2198 <img
2199 src={getImageUrl(platform.icon)}
2200 alt={platform.name}
2201 className="w-4 h-4"
2202 onError={() =>
2203 handleImageError(`platform-${platform.id}`)
2204 }
2205 />
2206 ) : (
2207 <div className="flex items-center justify-center w-4 h-4 bg-gray-200 rounded">
2208 <span className="text-xs text-gray-500">
2209 {platform.name?.charAt(0)?.toUpperCase() || '?'}
2210 </span>
2211 </div>
2212 )}
2213 <span>{platform.name}</span>
2214 </div>
2215 </button>
2216 ))}
2217 </div>
2218
2219 {/* 时间筛选 - 新增 */}
2220 <div className="flex items-center">
2221 <span className="mr-3 text-sm text-gray-500">
2222 时间范围:
2223 </span>
2224 <div className="flex flex-wrap gap-2">
2225 {timeTypes.map((timeRange) => (
2226 <button
2227 key={timeRange}
2228 className={`${buttonStyles.base} ${
2229 selectedTimeRange === timeRange
2230 ? buttonStyles.primary
2231 : buttonStyles.secondary
2232 }`}
2233 onClick={() => {
2234 // 先设置时间范围
2235 setSelectedTimeRange(timeRange);
2236 // 使用 setTimeout 确保状态更新后再调用查询
2237 setTimeout(() => {
2238 handleTimeRangeChange(timeRange);
2239 }, 0);
2240 }}
2241 >
2242 {timeRange}
2243 </button>
2244 ))}
2245 </div>
2246 </div>
2247
2248 {/* 分类筛选 - 如果有的话 */}
2249 {topicTypes.length > 1 && (
2250 <div className="flex items-center">
2251 <span className="mr-3 text-sm text-gray-500">分类:</span>
2252 <div className="flex flex-wrap gap-2">
2253 {topicTypes.map((type) => (
2254 <button
2255 key={type}
2256 className={`${buttonStyles.base} ${
2257 selectedTopicType === type
2258 ? buttonStyles.primary
2259 : buttonStyles.secondary
2260 }`}
2261 onClick={() => {
2262 setSelectedTopicType(
2263 type === selectedTopicType ? '' : type,
2264 );
2265 handleFilterChange();
2266 }}
2267 >
2268 {type}
2269 </button>
2270 ))}
2271 </div>
2272 </div>
2273 )}
2274 </div>
2275 </div>
2276
2277 {/* 专题内容列表 */}
2278 <div className="bg-white rounded-lg shadow-sm">
2279 {topicLoading ? (
2280 <div className="flex items-center justify-center py-8">
2281 <span className="text-gray-500">加载中...</span>
2282 </div>
2283 ) : topicContents.length > 0 ? (
2284 <>
2285 {/* 表头 */}
2286 <div className="grid grid-cols-12 p-4 text-sm text-gray-500 bg-gray-50">
2287 <div className="col-span-1 text-center">排名</div>
2288 <div className="col-span-2 pl-2">封面</div>
2289 <div className="col-span-4 pl-2">标题/作者</div>
2290 <div className="col-span-1 text-center">分类</div>
2291 <div className="col-span-1 text-center">点赞</div>
2292 <div className="col-span-1 text-center">分享</div>
2293 <div className="col-span-1 text-center">评论数</div>
2294 <div className="col-span-1 text-center">收藏数</div>
2295 </div>
2296
2297 {/* 内容列表 */}
2298 {topicContents.map((item, index) => (
2299 <div
2300 key={item.id}
2301 className="grid items-center grid-cols-12 px-4 py-5 transition-colors border-b border-gray-100 cursor-pointer hover:bg-gray-50"
2302 onClick={() => handleContentClick(item.url, item.title)}
2303 >
2304 {/* 排名 */}
2305 <div className="col-span-1 text-lg font-bold text-center text-orange-500">
2306 {((topicPagination?.currentPage || 1) - 1) *
2307 (topicPagination?.itemsPerPage || 20) +
2308 index +
2309 1}
2310 </div>
2311
2312 {/* 封面 */}
2313 <div className="col-span-2 pl-2">
2314 <div className="relative w-full overflow-hidden bg-gray-100 rounded-lg aspect-video">
2315 {item.cover && !imgErrors[item.id as string] ? (
2316 <img
2317 src={getImageUrl(item.cover)}
2318 alt={item.title}
2319 className="object-cover w-full h-full"
2320 onError={() =>
2321 handleImageError(item.id as string)
2322 }
2323 />
2324 ) : (
2325 <div className="flex items-center justify-center h-full text-center text-gray-400">
2326 暂无图片
2327 </div>
2328 )}
2329 {item.type === 'video' && (
2330 <div className="absolute px-2 py-1 text-xs text-white bg-black rounded bottom-2 right-2 bg-opacity-60">
2331 视频
2332 </div>
2333 )}
2334 </div>
2335 </div>
2336
2337 {/* 标题和作者信息 */}
2338 <div className="col-span-4 pl-4 ">
2339 <h3 className="text-base font-medium line-clamp-2 hover:text-[#a66ae4] text-left">
2340 {item.title}
2341 </h3>
2342 <div style={{ width: '100%', height: '60px' }}></div>
2343 <div className="flex items-center mt-2">
2344 <div className="flex items-center">
2345 {item.avatar &&
2346 !imgErrors[`avatar-${item.id}`] ? (
2347 <img
2348 src={getImageUrl(item.avatar)}
2349 alt={item.author}
2350 className="w-5 h-5 mr-1 rounded-full"
2351 onError={() =>
2352 handleImageError(`avatar-${item.id}`)
2353 }
2354 />
2355 ) : (
2356 <div className="flex items-center justify-center w-5 h-5 mr-1 bg-gray-200 rounded-full">
2357 <span className="text-xs text-gray-500">
2358 {item.author?.charAt(0)?.toUpperCase() ||
2359 '?'}
2360 </span>
2361 </div>
2362 )}
2363 <span className="mr-2 text-sm text-gray-600">
2364 {item.author}
2365 </span>
2366 {item.fans > 0 && (
2367 <span className="mr-2 text-xs text-gray-400">
2368 {item.fans >= 10000
2369 ? `${(item.fans / 10000).toFixed(1)}万粉丝`
2370 : `${item.fans}粉丝`}
2371 </span>
2372 )}
2373 <span className="text-xs text-gray-400">
2374 发布于{' '}
2375 {dayjs(item.publishTime).format(
2376 'YYYY-MM-DD HH:mm',
2377 )}
2378 </span>
2379 </div>
2380 </div>
2381 </div>
2382
2383 {/* 分类信息 */}
2384 <div className="col-span-1 text-center">
2385 <div className="text-sm text-gray-600">
2386 {item.category}
2387 </div>
2388 {item.subCategory && (
2389 <div className="mt-1 text-xs text-gray-400">
2390 {item.subCategory}
2391 </div>
2392 )}
2393 </div>
2394
2395 {/* 点赞数 */}
2396 <div className="col-span-1 text-center">
2397 <div className="text-[#a66ae4] font-medium">
2398 {item.likeCount >= 10000
2399 ? `${(item.likeCount / 10000).toFixed(1)}w`
2400 : item.likeCount}
2401 </div>
2402 <div className="text-xs text-gray-400">点赞</div>
2403 </div>
2404
2405 {/* 分享数 */}
2406 <div className="col-span-1 text-center">
2407 <div className="text-[#a66ae4] font-medium">
2408 {item.shareCount >= 10000
2409 ? `${(item.shareCount / 10000).toFixed(1)}w`
2410 : item.shareCount}
2411 </div>
2412 <div className="text-xs text-gray-400">分享</div>
2413 </div>
2414
2415 {/* 评论数 */}
2416 <div className="col-span-1 text-center">
2417 <div className="text-[#a66ae4] font-medium">
2418 {item.commentCount
2419 ? item.commentCount >= 10000
2420 ? `${(item.commentCount / 10000).toFixed(1)}w`
2421 : item.commentCount
2422 : '-'}
2423 </div>
2424 <div className="text-xs text-gray-400">
2425 {'评论数'}
2426 </div>
2427 </div>
2428
2429 {/* 收藏数 */}
2430 <div className="col-span-1 text-center">
2431 <div className="text-[#a66ae4] font-medium">
2432 {item.collectCount
2433 ? item.collectCount >= 10000
2434 ? `${(item.collectCount / 10000).toFixed(1)}w`
2435 : item.collectCount
2436 : '-'}
2437 </div>
2438 <div className="text-xs text-gray-400">
2439 {'收藏数'}
2440 </div>
2441 </div>
2442 </div>
2443 ))}
2444
2445 {/* 分页组件 */}
2446 {topicPagination && topicPagination.totalPages > 1 && (
2447 <div className="flex justify-center py-6">
2448 <Pagination
2449 current={topicPagination.currentPage}
2450 total={topicPagination.totalItems}
2451 pageSize={topicPagination.itemsPerPage}
2452 showSizeChanger={false}
2453 showQuickJumper
2454 showTotal={(total) => `共 ${total} 条`}
2455 onChange={handleTopicPageChange}
2456 />
2457 </div>
2458 )}
2459 </>
2460 ) : (
2461 <div className="py-8 text-center text-gray-500">
2462 暂无专题数据
2463 </div>
2464 )}
2465 </div>
2466 </div>
2467 ) : talkExpanded ? (
2468 // 话题内容区域
2469 <div>
2470 {/* 顶部筛选区 */}
2471 <div className="p-4 mb-4 bg-white rounded-lg shadow-sm">
2472 {/* 分类筛选 - 始终显示 */}
2473 <div className="flex flex-col space-y-2">
2474 <div
2475 className={`grid gap-2 transition-[grid-template-rows,max-height] duration-300 ease-in-out relative pr-20`}
2476 style={{
2477 gridTemplateColumns:
2478 'repeat(auto-fill, minmax(100px, 1fr))',
2479 gridTemplateRows: isCategoryExpanded ? '1fr' : '40px',
2480 maxHeight: isCategoryExpanded ? '1000px' : '40px',
2481 overflow: 'hidden',
2482 }}
2483 >
2484 <div className="contents">
2485 <button
2486 className={`${buttonStyles.base} ${
2487 !selectedViralCategory
2488 ? buttonStyles.primary
2489 : buttonStyles.secondary
2490 } truncate h-10`}
2491 onClick={() => handleTalkCategorySelect('')}
2492 >
2493 全部
2494 </button>
2495 {/* {talkCategory.map((category) => (
2496 <button
2497 key={category}
2498 className={`${buttonStyles.base} ${
2499 selectedViralCategory === category
2500 ? buttonStyles.primary
2501 : buttonStyles.secondary
2502 } truncate h-10`}
2503 onClick={() => handleViralCategorySelect(category)}
2504 >
2505 {category}
2506 </button>
2507 ))} */}
2508 </div>
2509 {/* {viralTitleCategories.length > 8 && (
2510 <button
2511 className="absolute right-0 top-0 h-10 px-3 flex items-center text-sm text-gray-500 hover:text-[#a66ae4] transition-colors bg-transparent border-none outline-none shadow-none"
2512 onClick={() =>
2513 setIsCategoryExpanded(!isCategoryExpanded)
2514 }
2515 >
2516 <span className="mr-1">
2517 {isCategoryExpanded ? '收起' : '展开'}
2518 </span>
2519 <InfoCircleOutlined
2520 className={`transform transition-transform duration-300 ${
2521 isCategoryExpanded ? 'rotate-180' : ''
2522 }`}
2523 />
2524 </button>
2525 )} */}
2526 </div>
2527 </div>
2528
2529 {/* 爆款标题时间筛选 */}
2530 <div className="flex items-center p-4">
2531 <span className="mr-3 text-sm text-gray-500">时间范围:</span>
2532 <div className="flex flex-wrap gap-2">
2533 {timeTypes.map((timeType) => (
2534 <button
2535 key={timeType}
2536 className={`${buttonStyles.base} ${
2537 selectedViralTimeType === timeType
2538 ? buttonStyles.primary
2539 : buttonStyles.secondary
2540 }`}
2541 onClick={() =>
2542 handleViralTimeTypeSelect(
2543 selectedViralCategory,
2544 timeType,
2545 )
2546 }
2547 >
2548 {timeType}
2549 </button>
2550 ))}
2551 </div>
2552 </div>
2553 </div>
2554 </div>
2555 ) : (
2556 // 热门内容界面
2557 <>
2558 {/* 榜单选择 */}
2559 {rankingList.length > 1 && (
2560 <div className="p-4 mb-4 bg-white rounded-lg shadow-sm">
2561 <div className="flex space-x-4">
2562 {rankingList
2563 .filter((ranking) => !ranking.parentId)
2564 .map((ranking) => (
2565 <button
2566 key={ranking.id}
2567 className={`${buttonStyles.base} ${
2568 selectedRanking?.id === ranking.id
2569 ? buttonStyles.primary
2570 : buttonStyles.secondary
2571 }`}
2572 onClick={() => handleRankingSelect(ranking)}
2573 >
2574 {ranking.name}
2575 </button>
2576 ))}
2577 </div>
2578 </div>
2579 )}
2580
2581 {/* 顶部筛选区 - 保持不变 */}
2582 <div className="p-4 mb-4 bg-white rounded-lg shadow-sm">
2583 {/* 分类筛选 */}
2584 <div className="flex flex-col space-y-2">
2585 <div
2586 className={`grid gap-2 transition-[grid-template-rows,max-height] duration-300 ease-in-out relative pr-20`}
2587 style={{
2588 gridTemplateColumns:
2589 'repeat(auto-fill, minmax(80px, 1fr))',
2590 gridTemplateRows: isExpanded ? '1fr' : '36px',
2591 maxHeight: isExpanded ? '1000px' : '36px',
2592 overflow: 'hidden',
2593 }}
2594 >
2595 <div className="contents">
2596 {categories.map((category) => (
2597 <button
2598 key={category}
2599 className={`${
2600 selectedCategory === category
2601 ? 'bg-[#a66ae4] text-white hover:bg-[#9559d1]'
2602 : 'bg-gray-50 text-gray-600 hover:bg-[#f4ebff] hover:text-[#a66ae4]'
2603 } px-2 py-1 rounded-md text-xs transition-all duration-200 border-none outline-none truncate h-8`}
2604 onClick={() => handleCategorySelect(category)}
2605 >
2606 {category}
2607 </button>
2608 ))}
2609 </div>
2610 {categories.length > 8 && (
2611 <button
2612 className="absolute right-0 top-0 h-8 px-2 flex items-center text-xs text-gray-500 hover:text-[#a66ae4] transition-colors bg-transparent border-none outline-none shadow-none"
2613 onClick={() => setIsExpanded(!isExpanded)}
2614 >
2615 <span className="mr-1">
2616 {isExpanded ? '收起' : '展开'}
2617 </span>
2618 <InfoCircleOutlined
2619 className={`transform transition-transform duration-300 ${
2620 isExpanded ? 'rotate-180' : ''
2621 }`}
2622 />
2623 </button>
2624 )}
2625 </div>
2626 </div>
2627
2628 {/* 日期选择和子榜单选择 */}
2629 <div className="flex items-center justify-between mt-4">
2630 <div className="flex items-center space-x-4">
2631 <DatePicker
2632 value={dayjs(selectedDate)}
2633 onChange={handleDateChange}
2634 locale={locale}
2635 allowClear={false}
2636 className="w-32"
2637 placeholder="选择日期"
2638 disabledDate={(current) => {
2639 return (
2640 current < dayjs(rankingMinDate) ||
2641 current > dayjs(rankingMaxDate)
2642 );
2643 }}
2644 // disabledDate={(current) => {
2645 // return current && current > dayjs().endOf('day');
2646 // }}
2647 />
2648
2649 {/* 子榜单选择 - 只在选择了父榜单后显示 */}
2650 {selectedRanking &&
2651 rankingList.filter(
2652 (ranking) =>
2653 // 如果当前选中的是子榜单,则显示与其父榜单相关的所有子榜单
2654 ranking.parentId ===
2655 (selectedRanking.parentId || selectedRanking.id),
2656 ).length > 0 && (
2657 <div className="flex flex-wrap gap-2 ml-4">
2658 {rankingList
2659 .filter(
2660 (ranking) =>
2661 // 如果当前选中的是子榜单,则显示与其父榜单相关的所有子榜单
2662 ranking.parentId ===
2663 (selectedRanking.parentId ||
2664 selectedRanking.id),
2665 )
2666 .map((ranking) => (
2667 <button
2668 key={ranking.id}
2669 className={`px-3 py-1.5 text-xs rounded-md transition-all duration-200 border-none outline-none ${
2670 selectedRanking?.id === ranking.id
2671 ? 'bg-[#a66ae4] text-white hover:bg-[#9559d1]'
2672 : 'bg-gray-50 text-gray-600 hover:bg-[#f4ebff] hover:text-[#a66ae4]'
2673 }`}
2674 onClick={() => handleRankingSelect(ranking)}
2675 >
2676 {ranking.name}
2677 </button>
2678 ))}
2679 </div>
2680 )}
2681 </div>
2682
2683 {selectedRanking && (
2684 <Popover
2685 content={<DataInfoContent ranking={selectedRanking} />}
2686 title="数据说明"
2687 trigger="hover"
2688 placement="bottomRight"
2689 overlayClassName="max-w-sm"
2690 >
2691 <div className="flex items-center space-x-1 cursor-pointer text-gray-600 hover:text-[#a66ae4] transition-colors">
2692 <InfoCircleOutlined />
2693 <span>数据说明</span>
2694 </div>
2695 </Popover>
2696 )}
2697 </div>
2698 </div>
2699
2700 {/* 内容列表 */}
2701 <div className="space-y-3">
2702 {rankingLoading ? (
2703 <div className="flex items-center justify-center py-8">
2704 <span className="text-gray-500">加载榜单数据中...</span>
2705 </div>
2706 ) : rankingContents.length > 0 ? (
2707 <>
2708 {/* 表头 */}
2709 <div
2710 className="flex p-4 text-sm text-gray-500 bg-gray-50"
2711 style={{
2712 display: 'flex',
2713 flexDirection: 'row',
2714 justifyContent: 'space-between',
2715 }}
2716 >
2717 <div
2718 style={{
2719 display: 'flex',
2720 flexDirection: 'row',
2721 justifyContent: 'flex-start',
2722 }}
2723 >
2724 <div className="w-8">排名</div>
2725 <div className="w-48">笔记信息</div>
2726 </div>
2727
2728 <div className="">
2729 <div className="flex items-center">
2730 <div className="w-32">作品分类</div>
2731 {/* 快手增量榜单字段单独设置 */}
2732 {selectedRanking?.name.includes('增量') && (selectedPlatform?.id === platformIdParams.ksPlatformId) && (
2733 <div className="flex items-center flex-1">
2734 <div className="flex items-center space-x-12">
2735 <div className="w-24 text-center">互动增量</div>
2736 <div className="w-24 text-center">新增播放</div>
2737 <div className="w-24 text-center">新增分享</div>
2738 <div className="w-24 text-center">新增评论</div>
2739 </div>
2740 </div>
2741 )}
2742
2743
2744 {selectedRanking?.name.includes('增量') && !(selectedPlatform?.id === platformIdParams.ksPlatformId) &&(
2745 <div className="flex items-center flex-1">
2746 <div className="flex items-center space-x-12">
2747 <div className="w-24 text-center">互动增量</div>
2748 <div className="w-24 text-center">新增收藏</div>
2749 <div className="w-24 text-center">新增分享</div>
2750 <div className="w-24 text-center">新增评论</div>
2751 </div>
2752 </div>
2753 )}
2754
2755 {(selectedRanking?.name.includes('阅读榜') ||
2756 selectedRanking?.name.includes('低粉爆文榜')) && (
2757 <div className="flex items-center flex-1">
2758 <div className="flex items-center space-x-12">
2759 <div className="w-24 text-center">在看数</div>
2760 <div className="w-24 text-center">阅读数</div>
2761 <div className="w-24 text-center">点赞数</div>
2762 <div className="w-24 text-center">转发数</div>
2763 </div>
2764 </div>
2765 )}
2766
2767 {!selectedRanking?.name.includes('增量') &&
2768 !selectedRanking?.name.includes('阅读榜') &&
2769 !selectedRanking?.name.includes('低粉爆文榜') && (
2770 <div className="flex items-center flex-1">
2771 <div className="flex items-center space-x-12">
2772 <div className="w-24 text-center">点赞</div>
2773 <div className="w-24 text-center">评论</div>
2774 <div className="w-24 text-center">分享</div>
2775 <div className="w-24 text-center">收藏</div>
2776 </div>
2777 </div>
2778 )}
2779 </div>
2780 </div>
2781 </div>
2782
2783 {rankingContents.map((item) => (
2784 <div
2785 key={item.id}
2786 className="flex bg-white p-4 rounded-lg hover:shadow-md transition-shadow cursor-pointer border border-transparent hover:border-[#e6d3f7]"
2787 onClick={() => handleContentClick(item.url, item.title)}
2788 >
2789 {/* 排名 */}
2790 <div className="w-8 text-lg font-bold text-orange-500">
2791 {item.rankingPosition}
2792 </div>
2793
2794 {/* 笔记信息区域 */}
2795 <div className="w-48">
2796 <div className="relative w-full overflow-hidden rounded-lg h-28">
2797 {item.cover && !imgErrors[item.id || ''] ? (
2798 <img
2799 src={getImageUrl(item.cover)}
2800 alt={item.title}
2801 className="object-cover w-full h-full"
2802 onError={() => handleImageError(item.id || '')}
2803 />
2804 ) : (
2805 <div className="text-center text-gray-400">
2806 暂无图片
2807 </div>
2808 )}
2809 </div>
2810 </div>
2811
2812 {/* 内容信息 */}
2813 <div
2814 className="ml-4"
2815 style={{
2816 display: 'flex',
2817 flex: 1,
2818 flexDirection: 'row',
2819 justifyContent: 'space-between',
2820 }}
2821 >
2822 <div className="flex">
2823 <div
2824 style={{
2825 display: 'flex',
2826 flex: 1,
2827 justifyContent: 'space-between',
2828 flexDirection: 'column',
2829 }}
2830 >
2831 <h3
2832 className="mb-2 text-base font-medium hover:text-blue-500"
2833 style={{
2834 textAlign: 'left',
2835 }}
2836 >
2837 {item.title}
2838 </h3>
2839 <div className="flex items-center space-x-2">
2840 {item.author &&
2841 !imgErrors[`${item.id || ''}-avatar`] ? (
2842 <img
2843 src={getImageUrl(item.author.avatar)}
2844 alt={item.author.name}
2845 className="w-5 h-5 rounded-full"
2846 onError={() =>
2847 handleImageError(
2848 `${item.id || ''}-avatar`,
2849 )
2850 }
2851 />
2852 ) : (
2853 <div className="flex items-center justify-center w-5 h-5 bg-gray-200 rounded-full">
2854 <UserOutlined className="text-xs text-gray-500" />
2855 </div>
2856 )}
2857 <span className="text-sm text-gray-600">
2858 {item.author.name}
2859 </span>
2860 <span className="text-xs text-gray-400">
2861 {item.author.fansCount !== null &&
2862 item.author.fansCount.toLocaleString() !==
2863 '' && (
2864 <>
2865 粉丝数{' '}
2866 {item.author.fansCount.toLocaleString()}
2867 </>
2868 )}
2869 </span>
2870
2871 <span className="text-xs text-gray-400">
2872 发布于{' '}
2873 {dayjs(item.publishTime).format(
2874 'YYYY-MM-DD HH:mm',
2875 )}
2876 </span>
2877 </div>
2878 </div>
2879 </div>
2880
2881 <div className="flex items-center text-sm">
2882 <div className="w-32 text-gray-500">
2883 <span>{item.category}</span>
2884 {/* <span className="ml-2">{item.type}</span> */}
2885 </div>
2886
2887 {/* 快手增量榜单字段单独设置 */}
2888 {selectedRanking?.name.includes('增量') && (selectedPlatform?.id === platformIdParams.ksPlatformId) && (
2889 <div className="flex items-center justify-between flex-1">
2890 <div className="flex items-center space-x-12">
2891 <div className="w-24 text-center">
2892 {item.anaAdd.addInteractiveCount ? (
2893 <span className="text-[#a66ae4] flex items-center justify-center">
2894 <span className="mr-1 font-bold text-red-500">
2895
2896 </span>
2897 {formatNumber(
2898 item.anaAdd.addInteractiveCount,
2899 )}
2900 </span>
2901 ) : (
2902 <span className="text-[#a66ae4] flex items-center justify-center">
2903 -
2904 </span>
2905 )}
2906
2907 {item.anaAdd.interactiveCount ? (
2908 <p
2909 className="text-[#a66ae4]"
2910 style={{
2911 fontSize: '12px',
2912 border: '1px solid #a66ae4',
2913 borderRadius: '15px',
2914 padding: '2px',
2915 marginTop: '6px',
2916 }}
2917 >
2918 <span className="mr-1 font-bold text-red-500">
2919
2920 </span>
2921
2922 {formatNumber(
2923 item.anaAdd.interactiveCount,
2924 )}
2925 </p>
2926 ) : (
2927 <p
2928 style={{
2929 fontSize: '12px',
2930 padding: '2px',
2931 marginTop: '6px',
2932 }}
2933 >
2934 -
2935 </p>
2936 )}
2937 </div>
2938 <div className="w-24 text-center">
2939 <span className="text-[#a66ae4] flex items-center justify-center">
2940 <span className="mr-1 text-red-500">
2941
2942 </span>
2943 {formatNumber(
2944 item.anaAdd.addLikeCount,
2945 )}
2946 </span>
2947 <p
2948 className="text-[#a66ae4]"
2949 style={{
2950 fontSize: '12px',
2951 border: '1px solid #a66ae4',
2952 borderRadius: '15px',
2953 padding: '2px',
2954 marginTop: '6px',
2955 }}
2956 >
2957
2958 {formatNumber(item.anaAdd.useLikeCount)}
2959 </p>
2960 </div>
2961 <div className="w-24 text-center">
2962 <span className="text-[#a66ae4] flex items-center justify-center">
2963 <span className="mr-1 text-red-500">
2964
2965 </span>
2966 {formatNumber(item.anaAdd.addShareCount)}
2967 </span>
2968 <p
2969 className="text-[#a66ae4]"
2970 style={{
2971 fontSize: '12px',
2972 border: '1px solid #a66ae4',
2973 borderRadius: '15px',
2974 padding: '2px',
2975 marginTop: '6px',
2976 }}
2977 >
2978
2979 {formatNumber(item.anaAdd.useShareCount)}
2980 </p>
2981 </div>
2982 <div className="w-24 text-center">
2983 <span className="text-[#a66ae4] flex items-center justify-center">
2984 <span className="mr-1 text-red-500">
2985
2986 </span>
2987 {formatNumber(
2988 item.anaAdd.addCommentCount,
2989 )}
2990 </span>
2991 <p
2992 className="text-[#a66ae4]"
2993 style={{
2994 fontSize: '12px',
2995 border: '1px solid #a66ae4',
2996 borderRadius: '15px',
2997 padding: '2px',
2998 marginTop: '6px',
2999 }}
3000 >
3001
3002 {formatNumber(
3003 item.anaAdd.useCommentCount,
3004 )}
3005 </p>
3006 </div>
3007 </div>
3008 </div>
3009 )}
3010
3011
3012 {selectedRanking?.name.includes('增量') && !(selectedPlatform?.id === platformIdParams.ksPlatformId) && (
3013 <div className="flex items-center justify-between flex-1">
3014 <div className="flex items-center space-x-12">
3015 <div className="w-24 text-center">
3016 {item.anaAdd.addInteractiveCount ? (
3017 <span className="text-[#a66ae4] flex items-center justify-center">
3018 <span className="mr-1 font-bold text-red-500">
3019
3020 </span>
3021 {formatNumber(
3022 item.anaAdd.addInteractiveCount,
3023 )}
3024 </span>
3025 ) : (
3026 <span className="text-[#a66ae4] flex items-center justify-center">
3027 -
3028 </span>
3029 )}
3030
3031 {item.anaAdd.interactiveCount ? (
3032 <p
3033 className="text-[#a66ae4]"
3034 style={{
3035 fontSize: '12px',
3036 border: '1px solid #a66ae4',
3037 borderRadius: '15px',
3038 padding: '2px',
3039 marginTop: '6px',
3040 }}
3041 >
3042 <span className="mr-1 font-bold text-red-500">
3043
3044 </span>
3045
3046 {formatNumber(
3047 item.anaAdd.interactiveCount,
3048 )}
3049 </p>
3050 ) : (
3051 <p
3052 style={{
3053 fontSize: '12px',
3054 padding: '2px',
3055 marginTop: '6px',
3056 }}
3057 >
3058 -
3059 </p>
3060 )}
3061 </div>
3062 <div className="w-24 text-center">
3063 <span className="text-[#a66ae4] flex items-center justify-center">
3064 <span className="mr-1 text-red-500">
3065
3066 </span>
3067 {formatNumber(
3068 item.anaAdd.addCollectCount,
3069 )}
3070 </span>
3071 <p
3072 className="text-[#a66ae4]"
3073 style={{
3074 fontSize: '12px',
3075 border: '1px solid #a66ae4',
3076 borderRadius: '15px',
3077 padding: '2px',
3078 marginTop: '6px',
3079 }}
3080 >
3081
3082 {formatNumber(item.anaAdd.useCollectCount)}
3083 </p>
3084 </div>
3085 <div className="w-24 text-center">
3086 <span className="text-[#a66ae4] flex items-center justify-center">
3087 <span className="mr-1 text-red-500">
3088
3089 </span>
3090 {formatNumber(item.anaAdd.addShareCount)}
3091 </span>
3092 <p
3093 className="text-[#a66ae4]"
3094 style={{
3095 fontSize: '12px',
3096 border: '1px solid #a66ae4',
3097 borderRadius: '15px',
3098 padding: '2px',
3099 marginTop: '6px',
3100 }}
3101 >
3102
3103 {formatNumber(item.anaAdd.useShareCount)}
3104 </p>
3105 </div>
3106 <div className="w-24 text-center">
3107 <span className="text-[#a66ae4] flex items-center justify-center">
3108 <span className="mr-1 text-red-500">
3109
3110 </span>
3111 {formatNumber(
3112 item.anaAdd.addCommentCount,
3113 )}
3114 </span>
3115 <p
3116 className="text-[#a66ae4]"
3117 style={{
3118 fontSize: '12px',
3119 border: '1px solid #a66ae4',
3120 borderRadius: '15px',
3121 padding: '2px',
3122 marginTop: '6px',
3123 }}
3124 >
3125
3126 {formatNumber(
3127 item.anaAdd.useCommentCount,
3128 )}
3129 </p>
3130 </div>
3131 </div>
3132 </div>
3133 )}
3134
3135 {(selectedRanking?.name.includes('阅读榜') ||
3136 selectedRanking?.name.includes('低粉爆文榜')) && (
3137 <div className="flex items-center justify-between flex-1">
3138 <div className="flex items-center space-x-12">
3139 <div className="w-24 text-center">
3140 <span className="text-[#a66ae4] flex items-center justify-center">
3141 {item.stats.watchCount || '-'}
3142 </span>
3143 </div>
3144 <div className="w-24 text-center">
3145 <span className="text-[#a66ae4] flex items-center justify-center">
3146 {item.stats.viewCount || '-'}
3147 </span>
3148 </div>
3149 <div className="w-24 text-center">
3150 <span className="text-[#a66ae4] flex items-center justify-center">
3151 {item.stats.likeCount || '-'}
3152 </span>
3153 </div>
3154 <div className="w-24 text-center">
3155 <span className="text-[#a66ae4] flex items-center justify-center">
3156 {(item as any).shareCount || '-'}
3157 </span>
3158 </div>
3159 </div>
3160 </div>
3161 )}
3162
3163 {!selectedRanking?.name.includes('增量') &&
3164 !selectedRanking?.name.includes('阅读榜') &&
3165 !selectedRanking?.name.includes('低粉爆文榜') && (
3166 <div className="flex items-center justify-between flex-1">
3167 <div className="flex items-center space-x-12">
3168 <div className="w-24 text-center">
3169 <span className="text-[#a66ae4] flex items-center justify-center">
3170 {item.stats.likeCount || '-'}
3171 </span>
3172 </div>
3173 <div className="w-24 text-center">
3174 <span className="text-[#a66ae4] flex items-center justify-center">
3175 {item.stats.commentCount || '-'}
3176 </span>
3177 </div>
3178 <div className="w-24 text-center">
3179 <span className="text-[#a66ae4] flex items-center justify-center">
3180 {(item as any).shareCount || '-'}
3181 </span>
3182 </div>
3183 <div className="w-24 text-center">
3184 <span className="text-[#a66ae4] flex items-center justify-center">
3185 {(item as any).collectCount || '-'}
3186 </span>
3187 </div>
3188 </div>
3189 </div>
3190 )}
3191 </div>
3192 </div>
3193 </div>
3194 ))}
3195
3196 {/* 分页 */}
3197 {pagination && pagination.totalPages > 1 && (
3198 <div className="flex justify-center mt-6 mb-8">
3199 <Pagination
3200 current={pagination.currentPage}
3201 total={pagination.totalItems}
3202 pageSize={pagination.itemsPerPage}
3203 showSizeChanger={false}
3204 showQuickJumper
3205 showTotal={(total) => `共 ${total} 条`}
3206 onChange={handlePageChange}
3207 className={`hover:text-[${THEME.primary}]`}
3208 />
3209 </div>
3210 )}
3211 </>
3212 ) : (
3213 <div className="py-8 text-center text-gray-500">
3214 暂无榜单数据
3215 </div>
3216 )}
3217 </div>
3218 </>
3219 )}
3220 <div style={{ width: '100%', height: '20px' }}></div>
3221 </div>
3222 </div>
3223
3224 {/* 内容预览模态框 */}
3225 <Modal
3226 title={
3227 <div
3228 className={`text-[${THEME.primary}] font-medium truncate max-w-3xl`}
3229 >
3230 {currentTitle}
3231 </div>
3232 }
3233 open={isModalVisible}
3234 onCancel={handleModalClose}
3235 footer={null}
3236 width="80%"
3237 destroyOnClose={true}
3238 styles={{
3239 body: {
3240 height: 'calc(100vh - 160px)',
3241 padding: 0,
3242 overflow: 'hidden',
3243 },
3244 content: {},
3245 mask: {
3246 backgroundColor: 'rgba(0, 0, 0, 0.65)',
3247 },
3248 }}
3249 style={{ top: 80, padding: 0 }}
3250 >
3251 {isModalVisible && (
3252 <webview
3253 src={currentUrl}
3254 style={{
3255 width: '100%',
3256 height: '100%',
3257 margin: 0,
3258 padding: 0,
3259 border: 'none',
3260 }}
3261 allowpopups={true}
3262 webpreferences="nativeWindowOpen=true"
3263 />
3264 )}
3265 </Modal>
3266
3267 {/* 添加必要的CSS和JavaScript */}
3268 <style
3269 dangerouslySetInnerHTML={{
3270 __html: `
3271 .hover-trigger:hover + circle {
3272 r: 3;
3273 }
3274 `,
3275 }}
3276 />
3277
3278 <script
3279 dangerouslySetInnerHTML={{
3280 __html: `
3281 document.addEventListener('DOMContentLoaded', function() {
3282 const hoverTriggers = document.querySelectorAll('.hover-trigger');
3283 const tooltip = document.querySelector('.tooltip');
3284 const hotvalueEl = document.querySelector('.tooltip .hotvalue');
3285 const timeEl = document.querySelector('.tooltip .time');
3286
3287 hoverTriggers.forEach(trigger => {
3288 trigger.addEventListener('mouseenter', function(e) {
3289 const value = this.getAttribute('data-value');
3290 const time = this.getAttribute('data-time');
3291
3292 hotvalueEl.textContent = (value / 10000).toFixed(1) + 'w';
3293 timeEl.textContent = time;
3294
3295 const rect = this.getBoundingClientRect();
3296 tooltip.style.left = rect.left + 'px';
3297 tooltip.style.top = (rect.top - 40) + 'px';
3298 tooltip.style.opacity = '1';
3299 });
3300
3301 trigger.addEventListener('mouseleave', function() {
3302 tooltip.style.opacity = '0';
3303 });
3304 });
3305 });
3306 `,
3307 }}
3308 />
3309
3310 {/* 添加隐藏滚动条的样式 */}
3311 <style
3312 dangerouslySetInnerHTML={{
3313 __html: `
3314 .scrollbar-hide::-webkit-scrollbar {
3315 display: none;
3316 }
3317 .scrollbar-hide {
3318 -ms-overflow-style: none;
3319 scrollbar-width: none;
3320 }
3321 `,
3322 }}
3323 />
3324 </>
3325 );
3326 };
3327
3328 export default Trending;
3329
3329 lines Plain Text