From b61f7a5048fdf0a12fae12aeaca9b806c0831585 Mon Sep 17 00:00:00 2001 From: zzlgreat Date: Sun, 21 Dec 2025 19:29:42 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0Company=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E7=9A=84UI=E4=B8=BAFUI=E9=A3=8E=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 3 + public/images/services/wechat-app.jpg | Bin 0 -> 66054 bytes src/mocks/data/events.js | 56 +- src/mocks/handlers/concept.js | 18 + .../components/DynamicNews/DynamicNewsCard.js | 14 +- .../components/DynamicNews/EventScrollList.js | 34 +- .../DynamicNews/ModeToggleButtons.js | 8 +- .../components/DynamicNews/constants.js | 1 + .../DynamicNews/hooks/usePagination.js | 13 +- .../DynamicNews/layouts/GroupedFourRowGrid.js | 612 ++++++++++++++++++ 10 files changed, 736 insertions(+), 23 deletions(-) create mode 100644 public/images/services/wechat-app.jpg create mode 100644 src/views/Community/components/DynamicNews/layouts/GroupedFourRowGrid.js diff --git a/app.py b/app.py index 1bcb92fb..d7b76b34 100755 --- a/app.py +++ b/app.py @@ -11829,6 +11829,9 @@ def broadcast_new_event(event): else: print(f'[WebSocket] 已推送新事件到房间: events_all') + # 清除事件列表缓存,确保用户刷新页面时获取最新数据 + clear_events_cache() + print(f'[WebSocket DEBUG] ========== 广播完成 ==========\n') except Exception as e: diff --git a/public/images/services/wechat-app.jpg b/public/images/services/wechat-app.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e473e0c288111aef518ebcd6b7aadfdc7d9aecab GIT binary patch literal 66054 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%0D&)v+77<55eX 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 PPhgw>)$eWpck=%L{w1$F literal 0 HcmV?d00001 diff --git a/src/mocks/data/events.js b/src/mocks/data/events.js index 37f6aed4..162b9b72 100644 --- a/src/mocks/data/events.js +++ b/src/mocks/data/events.js @@ -609,6 +609,49 @@ function generateEventDescription(industry, importance, seed) { return impacts[importance] + details[seed % details.length]; } +// 概念到层级结构的映射(模拟真实 API 的 concept_hierarchy) +const conceptHierarchyMap = { + // 人工智能主线 + '大模型': { lv1: '人工智能', lv1_id: 'AI', lv2: 'AI大模型与应用', lv2_id: 'AI_MODEL_APP', lv3: 'AI大模型', lv3_id: 'AI_LLM' }, + 'AI应用': { lv1: '人工智能', lv1_id: 'AI', lv2: 'AI大模型与应用', lv2_id: 'AI_MODEL_APP', lv3: 'AI应用场景', lv3_id: 'AI_APP' }, + '算力': { lv1: '人工智能', lv1_id: 'AI', lv2: 'AI算力与基础设施', lv2_id: 'AI_INFRA', lv3: 'AI芯片与硬件', lv3_id: 'AI_CHIP' }, + '数据': { lv1: '人工智能', lv1_id: 'AI', lv2: 'AI大模型与应用', lv2_id: 'AI_MODEL_APP', lv3: '数据要素', lv3_id: 'DATA' }, + '机器学习': { lv1: '人工智能', lv1_id: 'AI', lv2: 'AI大模型与应用', lv2_id: 'AI_MODEL_APP', lv3: 'AI算法', lv3_id: 'AI_ALGO' }, + 'AI芯片': { lv1: '人工智能', lv1_id: 'AI', lv2: 'AI算力与基础设施', lv2_id: 'AI_INFRA', lv3: 'AI芯片与硬件', lv3_id: 'AI_CHIP' }, + // 半导体主线 + '芯片': { lv1: '半导体', lv1_id: 'SEMI', lv2: '芯片设计', lv2_id: 'CHIP_DESIGN', lv3: '芯片设计', lv3_id: 'CHIP' }, + '晶圆': { lv1: '半导体', lv1_id: 'SEMI', lv2: '芯片制造', lv2_id: 'CHIP_MFG', lv3: '晶圆代工', lv3_id: 'WAFER' }, + '封测': { lv1: '半导体', lv1_id: 'SEMI', lv2: '封装测试', lv2_id: 'PKG_TEST', lv3: '封装测试', lv3_id: 'PKG' }, + '国产替代': { lv1: '半导体', lv1_id: 'SEMI', lv2: '国产替代', lv2_id: 'DOMESTIC', lv3: '自主可控', lv3_id: 'SELF_CTRL' }, + // 新能源主线 + '电池': { lv1: '新能源', lv1_id: 'ENERGY', lv2: '新能源汽车', lv2_id: 'EV', lv3: '动力电池', lv3_id: 'BATTERY' }, + '光伏': { lv1: '新能源', lv1_id: 'ENERGY', lv2: '光伏产业', lv2_id: 'SOLAR', lv3: '光伏组件', lv3_id: 'PV_MODULE' }, + '储能': { lv1: '新能源', lv1_id: 'ENERGY', lv2: '储能产业', lv2_id: 'ESS', lv3: '电化学储能', lv3_id: 'ESS_CHEM' }, + '新能源车': { lv1: '新能源', lv1_id: 'ENERGY', lv2: '新能源汽车', lv2_id: 'EV', lv3: '整车制造', lv3_id: 'EV_OEM' }, + '锂电': { lv1: '新能源', lv1_id: 'ENERGY', lv2: '新能源汽车', lv2_id: 'EV', lv3: '锂电池材料', lv3_id: 'LI_MATERIAL' }, + // 医药主线 + '创新药': { lv1: '医药生物', lv1_id: 'PHARMA', lv2: '创新药', lv2_id: 'INNOV_DRUG', lv3: '创新药研发', lv3_id: 'DRUG_RD' }, + 'CRO': { lv1: '医药生物', lv1_id: 'PHARMA', lv2: '医药服务', lv2_id: 'PHARMA_SVC', lv3: 'CRO/CDMO', lv3_id: 'CRO' }, + '医疗器械': { lv1: '医药生物', lv1_id: 'PHARMA', lv2: '医疗器械', lv2_id: 'MED_DEVICE', lv3: '高端器械', lv3_id: 'HI_DEVICE' }, + '生物制药': { lv1: '医药生物', lv1_id: 'PHARMA', lv2: '生物制药', lv2_id: 'BIO_PHARMA', lv3: '生物药', lv3_id: 'BIO_DRUG' }, + '仿制药': { lv1: '医药生物', lv1_id: 'PHARMA', lv2: '仿制药', lv2_id: 'GENERIC', lv3: '仿制药', lv3_id: 'GEN_DRUG' }, + // 消费主线 + '白酒': { lv1: '消费', lv1_id: 'CONSUMER', lv2: '食品饮料', lv2_id: 'FOOD_BEV', lv3: '白酒', lv3_id: 'BAIJIU' }, + '食品': { lv1: '消费', lv1_id: 'CONSUMER', lv2: '食品饮料', lv2_id: 'FOOD_BEV', lv3: '食品加工', lv3_id: 'FOOD' }, + '家电': { lv1: '消费', lv1_id: 'CONSUMER', lv2: '家电', lv2_id: 'HOME_APPL', lv3: '白色家电', lv3_id: 'WHITE_APPL' }, + '零售': { lv1: '消费', lv1_id: 'CONSUMER', lv2: '商贸零售', lv2_id: 'RETAIL', lv3: '零售连锁', lv3_id: 'CHAIN' }, + '免税': { lv1: '消费', lv1_id: 'CONSUMER', lv2: '商贸零售', lv2_id: 'RETAIL', lv3: '免税', lv3_id: 'DUTY_FREE' }, + // 通用概念(分配到多个主线) + '政策': { lv1: '宏观政策', lv1_id: 'MACRO', lv2: '产业政策', lv2_id: 'POLICY', lv3: null, lv3_id: null }, + '利好': { lv1: '市场情绪', lv1_id: 'SENTIMENT', lv2: '利好因素', lv2_id: 'POSITIVE', lv3: null, lv3_id: null }, + '业绩': { lv1: '基本面', lv1_id: 'FUNDAMENTAL', lv2: '业绩增长', lv2_id: 'EARNINGS', lv3: null, lv3_id: null }, + '涨停': { lv1: '市场情绪', lv1_id: 'SENTIMENT', lv2: '涨停板', lv2_id: 'LIMIT_UP', lv3: null, lv3_id: null }, + '龙头': { lv1: '投资策略', lv1_id: 'STRATEGY', lv2: '龙头股', lv2_id: 'LEADER', lv3: null, lv3_id: null }, + '突破': { lv1: '技术面', lv1_id: 'TECHNICAL', lv2: '技术突破', lv2_id: 'BREAKOUT', lv3: null, lv3_id: null }, + '合作': { lv1: '公司动态', lv1_id: 'CORP_ACTION', lv2: '战略合作', lv2_id: 'PARTNERSHIP', lv3: null, lv3_id: null }, + '投资': { lv1: '公司动态', lv1_id: 'CORP_ACTION', lv2: '投资并购', lv2_id: 'MA', lv3: null, lv3_id: null }, +}; + // 生成关键词(对象数组格式,包含完整信息) function generateKeywords(industry, seed) { const commonKeywords = ['政策', '利好', '业绩', '涨停', '龙头', '突破', '合作', '投资']; @@ -701,6 +744,16 @@ function generateKeywords(industry, seed) { const score = (70 + Math.floor((seed * 7 + index * 11) % 30)) / 100; // 0.70-0.99的分数 const avgChangePct = (Math.random() * 15 - 5).toFixed(2); // -5% ~ +10% 的涨跌幅 + // 获取概念的层级信息 + const hierarchy = conceptHierarchyMap[name] || { + lv1: industry || '其他', + lv1_id: 'OTHER', + lv2: '未分类', + lv2_id: 'UNCATEGORIZED', + lv3: null, + lv3_id: null + }; + return { concept: name, // 使用 concept 字段而不是 name stock_count: 10 + Math.floor((seed + index) % 30), // 10-39个相关股票 @@ -711,7 +764,8 @@ function generateKeywords(industry, seed) { }, match_type: matchTypes[(seed + index) % 3], // 随机匹配类型 happened_times: generateHappenedTimes(seed + index), // 历史触发时间 - stocks: generateRelatedStocks(name, seed + index) // 核心相关股票 + stocks: generateRelatedStocks(name, seed + index), // 核心相关股票 + hierarchy: hierarchy // 层级信息(用于按主线分组) }; }); } diff --git a/src/mocks/handlers/concept.js b/src/mocks/handlers/concept.js index 8762e072..efa7fe1a 100644 --- a/src/mocks/handlers/concept.js +++ b/src/mocks/handlers/concept.js @@ -1009,6 +1009,24 @@ export const conceptHandlers = [ { id: 'lv2_15_1', name: '国际贸易', concept_count: 15, concepts: ['跨境电商', '出口', '贸易摩擦', '人民币国际化', '中美贸易', '中欧贸易', '东盟贸易'] }, { id: 'lv2_15_2', name: '宏观主题', concept_count: 10, concepts: ['美联储加息', '美债', '汇率', '通胀', '衰退预期', '地缘政治'] } ] + }, + { + id: 'lv1_16', + name: '传统能源与资源', + concept_count: 30, + children: [ + { id: 'lv2_16_1', name: '煤炭石油', concept_count: 15, concepts: ['煤炭', '动力煤', '焦煤', '石油', '天然气', '页岩油', '油服', '油气开采', '煤化工', '石油化工'] }, + { id: 'lv2_16_2', name: '钢铁建材', concept_count: 15, concepts: ['钢铁', '特钢', '铁矿石', '水泥', '玻璃', '建材', '基建', '房地产', '装配式建筑'] } + ] + }, + { + id: 'lv1_17', + name: '公用事业与交运', + concept_count: 25, + children: [ + { id: 'lv2_17_1', name: '公用事业', concept_count: 12, concepts: ['电力', '水务', '燃气', '环保', '垃圾处理', '污水处理', '园林绿化'] }, + { id: 'lv2_17_2', name: '交通运输', concept_count: 13, concepts: ['航空', '机场', '港口', '航运', '铁路', '公路', '物流', '快递', '冷链物流'] } + ] } ]; diff --git a/src/views/Community/components/DynamicNews/DynamicNewsCard.js b/src/views/Community/components/DynamicNews/DynamicNewsCard.js index 7ca96b52..ab9f9f9f 100644 --- a/src/views/Community/components/DynamicNews/DynamicNewsCard.js +++ b/src/views/Community/components/DynamicNews/DynamicNewsCard.js @@ -113,9 +113,9 @@ const [currentMode, setCurrentMode] = useState('vertical'); // 根据模式选择数据源(使用 useMemo 缓存,避免重复计算) // 纵向模式:data 是页码映射 { 1: [...], 2: [...] } - // 平铺模式:data 是数组 [...] + // 平铺模式 / 主线模式:data 是数组 [...] (共用 fourRowData) const modeData = useMemo( - () => currentMode === 'four-row' ? fourRowData : verticalData, + () => (currentMode === 'four-row' || currentMode === 'mainline') ? fourRowData : verticalData, [currentMode, fourRowData, verticalData] ); const { @@ -134,7 +134,7 @@ const [currentMode, setCurrentMode] = useState('vertical'); [currentMode, data] ); const allCachedEvents = useMemo( - () => currentMode === 'four-row' ? data : undefined, + () => (currentMode === 'four-row' || currentMode === 'mainline') ? data : undefined, [currentMode, data] ); @@ -249,14 +249,14 @@ const [currentMode, setCurrentMode] = useState('vertical'); } else { console.log(`[DynamicNewsCard] 纵向模式 + 第${state.currentPage}页 → 不刷新(避免打断用户)`); } - } else if (mode === 'four-row') { - // ========== 平铺模式 ========== + } else if (mode === 'four-row' || mode === 'mainline') { + // ========== 平铺模式 / 主线模式 ========== // 检查滚动位置,只有在顶部时才刷新 const scrollPos = virtualizedGridRef.current?.getScrollPosition(); if (scrollPos?.isNearTop) { // 用户在顶部 10% 区域,安全刷新 - console.log('[DynamicNewsCard] 平铺模式 + 滚动在顶部 → 刷新列表'); + console.log(`[DynamicNewsCard] ${mode === 'mainline' ? '主线' : '平铺'}模式 + 滚动在顶部 → 刷新列表`); handlePageChange(1); // 清空并刷新 toast({ title: '检测到新事件,已刷新', @@ -266,7 +266,7 @@ const [currentMode, setCurrentMode] = useState('vertical'); }); } else { // 用户不在顶部,显示提示但不自动刷新 - console.log('[DynamicNewsCard] 平铺模式 + 滚动不在顶部 → 仅提示,不刷新'); + console.log(`[DynamicNewsCard] ${mode === 'mainline' ? '主线' : '平铺'}模式 + 滚动不在顶部 → 仅提示,不刷新`); toast({ title: '有新事件发布', description: '滚动到顶部查看', diff --git a/src/views/Community/components/DynamicNews/EventScrollList.js b/src/views/Community/components/DynamicNews/EventScrollList.js index c1ebf70d..d9be9205 100644 --- a/src/views/Community/components/DynamicNews/EventScrollList.js +++ b/src/views/Community/components/DynamicNews/EventScrollList.js @@ -7,15 +7,16 @@ import { useColorModeValue } from '@chakra-ui/react'; import VirtualizedFourRowGrid from './layouts/VirtualizedFourRowGrid'; +import GroupedFourRowGrid from './layouts/GroupedFourRowGrid'; import VerticalModeLayout from './layouts/VerticalModeLayout'; /** - * 事件列表组件 - 支持纵向和平铺两种展示模式 + * 事件列表组件 - 支持纵向、平铺、主线三种展示模式 * @param {Array} events - 当前页的事件列表(服务端已分页) - * @param {Array} displayEvents - 累积显示的事件列表(平铺模式用) + * @param {Array} displayEvents - 累积显示的事件列表(平铺/主线模式用) * @param {Function} loadNextPage - 加载下一页(无限滚动) * @param {Function} loadPrevPage - 加载上一页(双向无限滚动) - * @param {Function} onFourRowEventClick - 平铺模式事件点击回调(打开弹窗) + * @param {Function} onFourRowEventClick - 平铺/主线模式事件点击回调(打开弹窗) * @param {Object} selectedEvent - 当前选中的事件 * @param {Function} onEventSelect - 事件选择回调 * @param {string} borderColor - 边框颜色 @@ -24,11 +25,11 @@ import VerticalModeLayout from './layouts/VerticalModeLayout'; * @param {Function} onPageChange - 页码改变回调 * @param {boolean} loading - 全局加载状态 * @param {Object} error - 错误状态 - * @param {string} mode - 展示模式:'vertical'(纵向分栏)| 'four-row'(平铺网格) + * @param {string} mode - 展示模式:'vertical'(纵向分栏)| 'four-row'(平铺网格)| 'mainline'(主线分组) * @param {boolean} hasMore - 是否还有更多数据 * @param {Object} eventFollowStatus - 事件关注状态 { [eventId]: { isFollowing, followerCount } } * @param {Function} onToggleFollow - 关注按钮回调 - * @param {React.Ref} virtualizedGridRef - VirtualizedFourRowGrid 的 ref(用于获取滚动位置) + * @param {React.Ref} virtualizedGridRef - VirtualizedFourRowGrid/GroupedFourRowGrid 的 ref(用于获取滚动位置) */ const EventScrollList = React.memo(({ events, @@ -87,7 +88,7 @@ const EventScrollList = React.memo(({ h="100%" pt={0} pb={4} - px={mode === 'four-row' ? 0 : { base: 0, md: 2 }} + px={mode === 'four-row' || mode === 'mainline' ? 0 : { base: 0, md: 2 }} position="relative" data-scroll-container="true" css={{ @@ -113,7 +114,7 @@ const EventScrollList = React.memo(({ > {/* 平铺网格模式 - 使用虚拟滚动 + 双向无限滚动 */} + {/* 主线分组模式 - 按 lv2 概念分组 */} + + {/* 纵向分栏模式 */} { @@ -20,11 +20,11 @@ const ModeToggleButtons = React.memo(({ mode, onModeChange }) => { 列表 ); diff --git a/src/views/Community/components/DynamicNews/constants.js b/src/views/Community/components/DynamicNews/constants.js index 82f60e85..e8bf56ca 100644 --- a/src/views/Community/components/DynamicNews/constants.js +++ b/src/views/Community/components/DynamicNews/constants.js @@ -29,6 +29,7 @@ export const PAGINATION_CONFIG = { export const DISPLAY_MODES = { FOUR_ROW: 'four-row', // 平铺网格模式 VERTICAL: 'vertical', // 纵向分栏模式 + MAINLINE: 'mainline', // 主线分组模式(按 lv2 概念分组) }; export const DEFAULT_MODE = DISPLAY_MODES.VERTICAL; diff --git a/src/views/Community/components/DynamicNews/hooks/usePagination.js b/src/views/Community/components/DynamicNews/hooks/usePagination.js index 942d5855..edf35b22 100644 --- a/src/views/Community/components/DynamicNews/hooks/usePagination.js +++ b/src/views/Community/components/DynamicNews/hooks/usePagination.js @@ -49,9 +49,11 @@ export const usePagination = ({ filtersRef.current = filters; // 根据模式决定每页显示数量 + // mainline 模式复用 four-row 的分页配置 const pageSize = (() => { switch (mode) { case DISPLAY_MODES.FOUR_ROW: + case DISPLAY_MODES.MAINLINE: return PAGINATION_CONFIG.FOUR_ROW_PAGE_SIZE; case DISPLAY_MODES.VERTICAL: return PAGINATION_CONFIG.VERTICAL_PAGE_SIZE; @@ -73,15 +75,15 @@ export const usePagination = ({ // 纵向模式:从页码映射获取当前页 return allCachedEventsByPage?.[currentPage] || []; } else { - // 平铺模式:返回全部累积数据 + // 平铺模式 / 主线模式:返回全部累积数据 return allCachedEvents || []; } }, [mode, allCachedEventsByPage, allCachedEvents, currentPage]); // 当前显示的事件列表 const displayEvents = useMemo(() => { - if (mode === DISPLAY_MODES.FOUR_ROW) { - // 平铺模式:返回全部累积数据 + if (mode === DISPLAY_MODES.FOUR_ROW || mode === DISPLAY_MODES.MAINLINE) { + // 平铺模式 / 主线模式:返回全部累积数据 return allCachedEvents || []; } else { // 纵向模式:返回当前页数据 @@ -122,8 +124,11 @@ export const usePagination = ({ filters: filtersRef.current }); + // mainline 模式使用 four-row 的 API 模式(共用同一份数据) + const apiMode = mode === DISPLAY_MODES.MAINLINE ? DISPLAY_MODES.FOUR_ROW : mode; + const result = await dispatch(fetchDynamicNews({ - mode: mode, // 传递 mode 参数 + mode: apiMode, // 传递 API mode 参数(mainline 映射为 four-row) per_page: pageSize, pageSize: pageSize, clearCache: clearCache, // 传递 clearCache 参数 diff --git a/src/views/Community/components/DynamicNews/layouts/GroupedFourRowGrid.js b/src/views/Community/components/DynamicNews/layouts/GroupedFourRowGrid.js new file mode 100644 index 00000000..09765649 --- /dev/null +++ b/src/views/Community/components/DynamicNews/layouts/GroupedFourRowGrid.js @@ -0,0 +1,612 @@ +// src/views/Community/components/DynamicNews/layouts/GroupedFourRowGrid.js +// 按主线(lv2)分组的网格布局组件 + +import React, { useRef, useMemo, useEffect, forwardRef, useImperativeHandle, useState } from 'react'; +import { useVirtualizer } from '@tanstack/react-virtual'; +import { + Box, + Grid, + Spinner, + Text, + VStack, + Center, + HStack, + IconButton, + useBreakpointValue, + useColorModeValue, + Flex, + Badge, + Icon, + Collapse, +} from '@chakra-ui/react'; +import { RepeatIcon, ChevronDownIcon, ChevronRightIcon } from '@chakra-ui/icons'; +import DynamicNewsEventCard from '../../EventCard/DynamicNewsEventCard'; +import { getApiBase } from '@utils/apiConfig'; + +// ============ 概念层级映射缓存 ============ +// 全局缓存,避免重复请求 +let conceptHierarchyCache = null; +let conceptHierarchyPromise = null; + +/** + * 获取概念层级映射(概念名称 -> lv2) + * @returns {Promise} { '煤炭': 'lv2名称', ... } + */ +const fetchConceptHierarchy = async () => { + // 如果已有缓存,直接返回 + if (conceptHierarchyCache) { + return conceptHierarchyCache; + } + + // 如果正在请求中,等待结果 + if (conceptHierarchyPromise) { + return conceptHierarchyPromise; + } + + // 发起请求 + conceptHierarchyPromise = (async () => { + try { + const apiBase = getApiBase(); + const response = await fetch(`${apiBase}/concept-api/hierarchy`); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + + // 构建概念名称 -> lv2 映射 + const mapping = {}; + const hierarchy = data.hierarchy || []; + + /** + * 递归添加概念到映射 + * @param {Array} concepts - 概念数组(字符串或对象) + * @param {string} lv1Name - lv1 名称 + * @param {string} lv2Name - lv2 名称 + * @param {string} lv3Name - lv3 名称(可选) + */ + const addConceptsToMapping = (concepts, lv1Name, lv2Name, lv3Name = null) => { + if (!concepts || !Array.isArray(concepts)) return; + concepts.forEach(concept => { + const conceptName = typeof concept === 'string' ? concept : (concept.name || concept.concept); + if (conceptName) { + mapping[conceptName] = { lv1: lv1Name, lv2: lv2Name, lv3: lv3Name }; + } + }); + }; + + hierarchy.forEach(lv1 => { + const lv1Name = lv1.name; + const lv2List = lv1.children || []; + + lv2List.forEach(lv2 => { + const lv2Name = lv2.name; + const lv3List = lv2.children || []; + + // 情况1: lv2 直接包含 concepts(无 lv3) + if (lv2.concepts) { + addConceptsToMapping(lv2.concepts, lv1Name, lv2Name, null); + } + + // 情况2: lv2 包含 lv3 children + lv3List.forEach(lv3 => { + const lv3Name = lv3.name; + // lv3 下的 concepts 或 leaf_concepts + const leafConcepts = lv3.concepts || lv3.leaf_concepts || []; + addConceptsToMapping(leafConcepts, lv1Name, lv2Name, lv3Name); + }); + }); + }); + + console.log('[GroupedFourRowGrid] 概念层级映射加载完成,共', Object.keys(mapping).length, '个概念'); + conceptHierarchyCache = mapping; + return mapping; + } catch (error) { + console.error('[GroupedFourRowGrid] 获取概念层级失败:', error); + conceptHierarchyPromise = null; // 允许重试 + return {}; + } + })(); + + return conceptHierarchyPromise; +}; + +/** + * 自定义 Hook:获取概念层级映射 + */ +const useConceptHierarchy = () => { + const [hierarchyMap, setHierarchyMap] = useState(conceptHierarchyCache || {}); + const [loading, setLoading] = useState(!conceptHierarchyCache); + + useEffect(() => { + if (!conceptHierarchyCache) { + fetchConceptHierarchy().then(map => { + setHierarchyMap(map); + setLoading(false); + }); + } + }, []); + + return { hierarchyMap, loading }; +}; + +/** + * 从事件的 keywords (related_concepts) 中提取主要的 lv2 分类 + * @param {Object} event - 事件对象 + * @param {Object} hierarchyMap - 概念层级映射 { 概念名: { lv1, lv2, lv3 } } + * @returns {string} lv2 分类名称 + */ +const getEventMainLine = (event, hierarchyMap = {}) => { + // keywords 即 related_concepts + // 真实数据结构: [{ concept: '煤炭', reason: '...' }, ...] + // Mock 数据可能有 hierarchy 字段 + const keywords = event.keywords || event.related_concepts || []; + + if (!keywords.length) { + return '其他'; + } + + // 统计各 lv2 出现次数,取出现最多的 + const lv2Counts = {}; + keywords.forEach(keyword => { + // 优先使用 keyword 自带的 hierarchy(Mock 数据) + let lv2 = keyword.hierarchy?.lv2; + + // 如果没有,从映射表查找(真实数据) + if (!lv2) { + const conceptName = keyword.concept || keyword.name || keyword; + const hierarchy = hierarchyMap[conceptName]; + lv2 = hierarchy?.lv2; + } + + if (lv2) { + lv2Counts[lv2] = (lv2Counts[lv2] || 0) + 1; + } + }); + + // 找出出现次数最多的 lv2 + let maxCount = 0; + let mainLv2 = '其他'; + Object.entries(lv2Counts).forEach(([lv2, count]) => { + if (count > maxCount) { + maxCount = count; + mainLv2 = lv2; + } + }); + + return mainLv2; +}; + +/** + * 按 lv2 分组事件 + * @param {Array} events - 事件列表 + * @param {Object} hierarchyMap - 概念层级映射 + * @returns {Array} 分组后的数组 [{ lv2, events: [] }, ...] + */ +const groupEventsByLv2 = (events, hierarchyMap = {}) => { + const groups = {}; + + events.forEach(event => { + const lv2 = getEventMainLine(event, hierarchyMap); + if (!groups[lv2]) { + groups[lv2] = []; + } + groups[lv2].push(event); + }); + + // 转换为数组并按事件数量排序(多的在前) + return Object.entries(groups) + .map(([lv2, groupEvents]) => ({ + lv2, + events: groupEvents, + eventCount: groupEvents.length, + })) + .sort((a, b) => b.eventCount - a.eventCount); +}; + +/** + * 单个分组的标题组件 + */ +const GroupHeader = ({ lv2, eventCount, isExpanded, onToggle, colorScheme }) => { + const headerBg = useColorModeValue('gray.50', 'gray.700'); + const headerHoverBg = useColorModeValue('gray.100', 'gray.650'); + const textColor = useColorModeValue('gray.700', 'gray.200'); + const borderColor = useColorModeValue('gray.200', 'gray.600'); + + // 根据主线类型获取配色 + const getColorScheme = (lv2Name) => { + const colorMap = { + // 人工智能相关 + 'AI基础设施': 'purple', + 'AI模型与软件': 'purple', + 'AI应用': 'purple', + // 半导体相关 + '半导体设备': 'blue', + '半导体材料': 'blue', + '芯片设计与制造': 'blue', + '先进封装': 'blue', + // 机器人相关 + '人形机器人整机': 'pink', + '机器人核心零部件': 'pink', + '其他类型机器人': 'pink', + // 消费电子相关 + '智能终端': 'cyan', + 'XR与空间计算': 'cyan', + '华为产业链': 'cyan', + // 智能驾驶相关 + '自动驾驶解决方案': 'teal', + '智能汽车产业链': 'teal', + '车路协同': 'teal', + // 新能源相关 + '新型电池技术': 'green', + '电力设备与电网': 'green', + '清洁能源': 'green', + // 低空与航天 + '低空经济': 'orange', + '商业航天': 'orange', + // 国防军工 + '无人作战与信息化': 'red', + '海军装备': 'red', + '军贸出海': 'red', + // 医药健康 + '创新药': 'messenger', + '医疗器械': 'messenger', + '中医药': 'messenger', + // 消费相关 + '食品饮料': 'yellow', + '消费服务': 'yellow', + // 传统能源与资源 + '煤炭石油': 'blackAlpha', + '钢铁建材': 'blackAlpha', + // 公用事业与交运 + '公用事业': 'gray', + '交通运输': 'gray', + // 其他 + '国家战略': 'red', + '区域发展': 'red', + '有色金属': 'orange', + '化工材料': 'orange', + '金融科技': 'linkedin', + '数字化转型': 'linkedin', + '量子科技': 'purple', + '脑机接口': 'purple', + '国际贸易': 'facebook', + '宏观主题': 'facebook', + }; + return colorMap[lv2Name] || 'gray'; + }; + + const scheme = colorScheme || getColorScheme(lv2); + + return ( + + + + + {lv2} + + + {eventCount} 条事件 + + + + ); +}; + +/** + * 按主线(lv2)分组的网格布局组件 + */ +const GroupedFourRowGridComponent = forwardRef(({ + display = 'block', + events, + columnsPerRow = 4, + CardComponent = DynamicNewsEventCard, + selectedEvent, + onEventSelect, + eventFollowStatus, + onToggleFollow, + getTimelineBoxStyle, + borderColor, + loadNextPage, + onRefreshFirstPage, + hasMore, + loading, + error, + onRetry, +}, ref) => { + const parentRef = useRef(null); + const isLoadingMore = useRef(false); + const lastRefreshTime = useRef(0); + + // 获取概念层级映射(从 /concept-api/hierarchy 接口) + const { hierarchyMap, loading: hierarchyLoading } = useConceptHierarchy(); + + // 记录每个分组的展开状态 + const [expandedGroups, setExpandedGroups] = useState({}); + + // 滚动条颜色(主题适配) + const scrollbarTrackBg = useColorModeValue('#f1f1f1', '#2D3748'); + const scrollbarThumbBg = useColorModeValue('#888', '#4A5568'); + const scrollbarThumbHoverBg = useColorModeValue('#555', '#718096'); + + // 响应式列数 + const responsiveColumns = useBreakpointValue({ + base: 1, + sm: 2, + md: 2, + lg: 3, + xl: 4, + }); + + const actualColumnsPerRow = responsiveColumns || columnsPerRow; + + // 按 lv2 分组事件(使用层级映射) + const groupedEvents = useMemo(() => { + return groupEventsByLv2(events, hierarchyMap); + }, [events, hierarchyMap]); + + // 初始化展开状态(默认全部展开) + useEffect(() => { + const initialExpanded = {}; + groupedEvents.forEach(group => { + // 只初始化新的分组,保留已有的状态 + if (expandedGroups[group.lv2] === undefined) { + initialExpanded[group.lv2] = true; + } + }); + if (Object.keys(initialExpanded).length > 0) { + setExpandedGroups(prev => ({ ...prev, ...initialExpanded })); + } + }, [groupedEvents]); + + // 切换分组展开/折叠 + const toggleGroup = (lv2) => { + setExpandedGroups(prev => ({ + ...prev, + [lv2]: !prev[lv2] + })); + }; + + // 暴露方法给父组件 + useImperativeHandle(ref, () => ({ + getScrollPosition: () => { + const scrollElement = parentRef.current; + if (!scrollElement) return null; + + const { scrollTop, scrollHeight, clientHeight } = scrollElement; + const isNearTop = scrollTop < clientHeight * 0.1; + + return { + scrollTop, + scrollHeight, + clientHeight, + isNearTop, + scrollPercentage: ((scrollTop + clientHeight) / scrollHeight) * 100, + }; + }, + }), []); + + // 滚动事件处理(无限滚动 + 顶部刷新) + useEffect(() => { + if (display === 'none') return; + + const scrollElement = parentRef.current; + if (!scrollElement) return; + + const handleScroll = async () => { + if (isLoadingMore.current || loading) return; + + const { scrollTop, scrollHeight, clientHeight } = scrollElement; + const scrollPercentage = (scrollTop + clientHeight) / scrollHeight; + + // 向下滚动:加载更多 + if (loadNextPage && hasMore && scrollPercentage > 0.9) { + isLoadingMore.current = true; + await loadNextPage(); + isLoadingMore.current = false; + } + + // 向上滚动到顶部:刷新 + if (onRefreshFirstPage && scrollTop < clientHeight * 0.1) { + const now = Date.now(); + if (now - lastRefreshTime.current >= 30000) { + isLoadingMore.current = true; + lastRefreshTime.current = now; + await onRefreshFirstPage(); + isLoadingMore.current = false; + } + } + }; + + scrollElement.addEventListener('scroll', handleScroll); + return () => scrollElement.removeEventListener('scroll', handleScroll); + }, [display, loadNextPage, onRefreshFirstPage, hasMore, loading]); + + // 内容不足时主动加载 + useEffect(() => { + if (display === 'none') return; + + const scrollElement = parentRef.current; + if (!scrollElement || !loadNextPage) return; + + const timer = setTimeout(() => { + if (isLoadingMore.current || !hasMore || loading) return; + + const { scrollHeight, clientHeight } = scrollElement; + if (scrollHeight <= clientHeight) { + isLoadingMore.current = true; + loadNextPage().finally(() => { + isLoadingMore.current = false; + }); + } + }, 500); + + return () => clearTimeout(timer); + }, [display, events.length, hasMore, loading, loadNextPage]); + + // 错误指示器 + const renderErrorIndicator = () => { + if (!error) return null; + + return ( +
+ + + 数据加载失败, + + } + size="sm" + colorScheme="blue" + variant="ghost" + onClick={onRetry} + aria-label="刷新" + /> + + 刷新 + + +
+ ); + }; + + // 底部加载指示器 + const renderLoadingIndicator = () => { + if (!hasMore) { + return ( +
+ + 已加载全部内容 + +
+ ); + } + if (loading) { + return ( +
+ + + + 加载中... + + +
+ ); + } + return null; + }; + + return ( + + {/* 分组列表 */} + + {groupedEvents.map((group) => ( + + {/* 分组标题 */} + toggleGroup(group.lv2)} + /> + + {/* 分组内容 */} + + + {group.events.map((event, index) => ( + + { + onEventSelect(clickedEvent); + }} + onTitleClick={(e) => { + e.preventDefault(); + e.stopPropagation(); + onEventSelect(event); + }} + onToggleFollow={() => onToggleFollow?.(event.id)} + timelineStyle={getTimelineBoxStyle?.()} + borderColor={borderColor} + /> + + ))} + + + + ))} + + + {/* 底部指示器 */} + + {error ? renderErrorIndicator() : renderLoadingIndicator()} + + + ); +}); + +GroupedFourRowGridComponent.displayName = 'GroupedFourRowGrid'; + +const GroupedFourRowGrid = React.memo(GroupedFourRowGridComponent); + +export default GroupedFourRowGrid;