From da2007386eb172eb8218d1c60da2a39f46622478 Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Tue, 9 Dec 2025 09:57:54 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20StockDetailPan?= =?UTF-8?q?el=20=E7=9B=AE=E5=BD=95=E7=BB=93=E6=9E=84=EF=BC=8C=E6=B8=85?= =?UTF-8?q?=E7=90=86=E6=9C=AA=E4=BD=BF=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 MiniTimelineChart 和 useEventStocks 迁移到 src/components/Charts/Stock/ - 更新 DynamicNewsDetailPanel 和 StockListItem 的导入路径 - 删除未使用的 SearchBox.js 和 useSearchEvents.js(约 300 行) - 建立统一的股票图表组件目录结构 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../Charts/Stock}/MiniTimelineChart.js | 2 +- src/components/Charts/Stock/hooks/index.js | 4 + .../Charts/Stock}/hooks/useEventStocks.js | 6 +- src/components/Charts/Stock/index.js | 5 + .../DynamicNewsDetailPanel.js | 2 +- .../EventDetailPanel/StockListItem.js | 2 +- src/hooks/useSearchEvents.js | 244 ------------------ src/views/Community/components/SearchBox.js | 59 ----- .../StockDetailPanel/components/index.js | 2 - 9 files changed, 15 insertions(+), 311 deletions(-) rename src/{views/Community/components/StockDetailPanel/components => components/Charts/Stock}/MiniTimelineChart.js (99%) create mode 100644 src/components/Charts/Stock/hooks/index.js rename src/{views/Community/components/StockDetailPanel => components/Charts/Stock}/hooks/useEventStocks.js (97%) create mode 100644 src/components/Charts/Stock/index.js delete mode 100644 src/hooks/useSearchEvents.js delete mode 100644 src/views/Community/components/SearchBox.js delete mode 100644 src/views/Community/components/StockDetailPanel/components/index.js diff --git a/src/views/Community/components/StockDetailPanel/components/MiniTimelineChart.js b/src/components/Charts/Stock/MiniTimelineChart.js similarity index 99% rename from src/views/Community/components/StockDetailPanel/components/MiniTimelineChart.js rename to src/components/Charts/Stock/MiniTimelineChart.js index 83eb843c..e839fed7 100644 --- a/src/views/Community/components/StockDetailPanel/components/MiniTimelineChart.js +++ b/src/components/Charts/Stock/MiniTimelineChart.js @@ -1,4 +1,4 @@ -// src/views/Community/components/StockDetailPanel/components/MiniTimelineChart.js +// src/components/Charts/Stock/MiniTimelineChart.js import React, { useState, useEffect, useMemo, useRef, useCallback } from 'react'; import ReactECharts from 'echarts-for-react'; import * as echarts from 'echarts'; diff --git a/src/components/Charts/Stock/hooks/index.js b/src/components/Charts/Stock/hooks/index.js new file mode 100644 index 00000000..9a90a094 --- /dev/null +++ b/src/components/Charts/Stock/hooks/index.js @@ -0,0 +1,4 @@ +// src/components/Charts/Stock/hooks/index.js +// 股票图表 Hooks 统一导出 + +export { useEventStocks } from './useEventStocks'; diff --git a/src/views/Community/components/StockDetailPanel/hooks/useEventStocks.js b/src/components/Charts/Stock/hooks/useEventStocks.js similarity index 97% rename from src/views/Community/components/StockDetailPanel/hooks/useEventStocks.js rename to src/components/Charts/Stock/hooks/useEventStocks.js index 0e7867ae..d3420e23 100644 --- a/src/views/Community/components/StockDetailPanel/hooks/useEventStocks.js +++ b/src/components/Charts/Stock/hooks/useEventStocks.js @@ -1,4 +1,4 @@ -// src/views/Community/components/StockDetailPanel/hooks/useEventStocks.js +// src/components/Charts/Stock/hooks/useEventStocks.js import { useSelector, useDispatch, shallowEqual } from 'react-redux'; import { useEffect, useCallback, useMemo } from 'react'; import { @@ -8,8 +8,8 @@ import { fetchHistoricalEvents, fetchChainAnalysis, fetchExpectationScore -} from '../../../../../store/slices/stockSlice'; -import { logger } from '../../../../../utils/logger'; +} from '@store/slices/stockSlice'; +import { logger } from '@utils/logger'; /** * 事件股票数据 Hook diff --git a/src/components/Charts/Stock/index.js b/src/components/Charts/Stock/index.js new file mode 100644 index 00000000..c714e907 --- /dev/null +++ b/src/components/Charts/Stock/index.js @@ -0,0 +1,5 @@ +// src/components/Charts/Stock/index.js +// 股票图表组件统一导出 + +export { default as MiniTimelineChart } from './MiniTimelineChart'; +export { useEventStocks } from './hooks/useEventStocks'; diff --git a/src/components/EventDetailPanel/DynamicNewsDetailPanel.js b/src/components/EventDetailPanel/DynamicNewsDetailPanel.js index f4100416..d6ceb26a 100644 --- a/src/components/EventDetailPanel/DynamicNewsDetailPanel.js +++ b/src/components/EventDetailPanel/DynamicNewsDetailPanel.js @@ -16,7 +16,7 @@ import { } from '@chakra-ui/react'; import { getImportanceConfig } from '@constants/importanceLevels'; import { eventService } from '@services/eventService'; -import { useEventStocks } from '@views/Community/components/StockDetailPanel/hooks/useEventStocks'; +import { useEventStocks } from '@components/Charts/Stock'; import { toggleEventFollow, selectEventFollowStatus } from '@store/slices/communityDataSlice'; import { useAuth } from '@contexts/AuthContext'; import EventHeaderInfo from './EventHeaderInfo'; diff --git a/src/components/EventDetailPanel/StockListItem.js b/src/components/EventDetailPanel/StockListItem.js index 9ac9bb25..fedf176c 100644 --- a/src/components/EventDetailPanel/StockListItem.js +++ b/src/components/EventDetailPanel/StockListItem.js @@ -20,7 +20,7 @@ import { StarIcon } from '@chakra-ui/icons'; import { Tag } from 'antd'; import { RobotOutlined } from '@ant-design/icons'; import { selectIsMobile } from '@store/slices/deviceSlice'; -import MiniTimelineChart from '@views/Community/components/StockDetailPanel/components/MiniTimelineChart'; +import { MiniTimelineChart } from '@components/Charts/Stock'; import MiniKLineChart from './MiniKLineChart'; import TimelineChartModal from '@components/StockChart/TimelineChartModal'; import KLineChartModal from '@components/StockChart/KLineChartModal'; diff --git a/src/hooks/useSearchEvents.js b/src/hooks/useSearchEvents.js deleted file mode 100644 index bd120042..00000000 --- a/src/hooks/useSearchEvents.js +++ /dev/null @@ -1,244 +0,0 @@ -// src/hooks/useSearchEvents.js -// 全局搜索功能事件追踪 Hook - -import { useCallback } from 'react'; -import { usePostHogTrack } from './usePostHogRedux'; -import { RETENTION_EVENTS } from '../lib/constants'; -import { logger } from '../utils/logger'; - -/** - * 全局搜索事件追踪 Hook - * @param {Object} options - 配置选项 - * @param {string} options.context - 搜索上下文 ('global' | 'stock' | 'news' | 'concept' | 'simulation') - * @returns {Object} 事件追踪处理函数集合 - */ -export const useSearchEvents = ({ context = 'global' } = {}) => { - const { track } = usePostHogTrack(); - - /** - * 追踪搜索开始(聚焦搜索框) - * @param {string} placeholder - 搜索框提示文本 - */ - const trackSearchInitiated = useCallback((placeholder = '') => { - track(RETENTION_EVENTS.SEARCH_INITIATED, { - context, - placeholder, - timestamp: new Date().toISOString(), - }); - - logger.debug('useSearchEvents', '🔍 Search Initiated', { - context, - placeholder, - }); - }, [track, context]); - - /** - * 追踪搜索查询提交 - * @param {string} query - 搜索查询词 - * @param {number} resultCount - 搜索结果数量 - * @param {Object} filters - 应用的筛选条件 - */ - const trackSearchQuerySubmitted = useCallback((query, resultCount = 0, filters = {}) => { - if (!query) { - logger.warn('useSearchEvents', 'trackSearchQuerySubmitted: query is required'); - return; - } - - track(RETENTION_EVENTS.SEARCH_QUERY_SUBMITTED, { - query, - query_length: query.length, - result_count: resultCount, - has_results: resultCount > 0, - context, - filters: filters, - filter_count: Object.keys(filters).length, - timestamp: new Date().toISOString(), - }); - - // 如果没有搜索结果,额外追踪 - if (resultCount === 0) { - track(RETENTION_EVENTS.SEARCH_NO_RESULTS, { - query, - context, - filters, - timestamp: new Date().toISOString(), - }); - - logger.debug('useSearchEvents', '❌ Search No Results', { - query, - context, - }); - } else { - logger.debug('useSearchEvents', '✅ Search Query Submitted', { - query, - resultCount, - context, - }); - } - }, [track, context]); - - /** - * 追踪搜索结果点击 - * @param {Object} result - 被点击的搜索结果 - * @param {string} result.type - 结果类型 ('stock' | 'news' | 'concept' | 'event') - * @param {string} result.id - 结果ID - * @param {string} result.title - 结果标题 - * @param {number} position - 在搜索结果中的位置 - * @param {string} query - 搜索查询词 - */ - const trackSearchResultClicked = useCallback((result, position = 0, query = '') => { - if (!result || !result.type) { - logger.warn('useSearchEvents', 'trackSearchResultClicked: result object with type is required'); - return; - } - - track(RETENTION_EVENTS.SEARCH_RESULT_CLICKED, { - result_type: result.type, - result_id: result.id || result.code || '', - result_title: result.title || result.name || '', - position, - query, - context, - timestamp: new Date().toISOString(), - }); - - logger.debug('useSearchEvents', '🎯 Search Result Clicked', { - type: result.type, - id: result.id || result.code, - position, - context, - }); - }, [track, context]); - - /** - * 追踪搜索筛选应用 - * @param {Object} filters - 应用的筛选条件 - * @param {string} filterType - 筛选类型 ('sort' | 'category' | 'date_range' | 'price_range') - * @param {any} filterValue - 筛选值 - */ - const trackSearchFilterApplied = useCallback((filterType, filterValue, filters = {}) => { - if (!filterType) { - logger.warn('useSearchEvents', 'trackSearchFilterApplied: filterType is required'); - return; - } - - track(RETENTION_EVENTS.SEARCH_FILTER_APPLIED, { - filter_type: filterType, - filter_value: String(filterValue), - all_filters: filters, - context, - timestamp: new Date().toISOString(), - }); - - logger.debug('useSearchEvents', '🔍 Search Filter Applied', { - filterType, - filterValue, - context, - }); - }, [track, context]); - - /** - * 追踪搜索建议点击(自动完成) - * @param {string} suggestion - 被点击的搜索建议 - * @param {number} position - 在建议列表中的位置 - * @param {string} source - 建议来源 ('history' | 'popular' | 'related') - */ - const trackSearchSuggestionClicked = useCallback((suggestion, position = 0, source = 'popular') => { - if (!suggestion) { - logger.warn('useSearchEvents', 'trackSearchSuggestionClicked: suggestion is required'); - return; - } - - track('Search Suggestion Clicked', { - suggestion, - position, - source, - context, - timestamp: new Date().toISOString(), - }); - - logger.debug('useSearchEvents', '💡 Search Suggestion Clicked', { - suggestion, - position, - source, - context, - }); - }, [track, context]); - - /** - * 追踪搜索历史查看 - * @param {number} historyCount - 历史记录数量 - */ - const trackSearchHistoryViewed = useCallback((historyCount = 0) => { - track('Search History Viewed', { - history_count: historyCount, - has_history: historyCount > 0, - context, - timestamp: new Date().toISOString(), - }); - - logger.debug('useSearchEvents', '📜 Search History Viewed', { - historyCount, - context, - }); - }, [track, context]); - - /** - * 追踪搜索历史清除 - */ - const trackSearchHistoryCleared = useCallback(() => { - track('Search History Cleared', { - context, - timestamp: new Date().toISOString(), - }); - - logger.debug('useSearchEvents', '🗑️ Search History Cleared', { - context, - }); - }, [track, context]); - - /** - * 追踪热门搜索词点击 - * @param {string} keyword - 被点击的热门关键词 - * @param {number} position - 在列表中的位置 - * @param {number} heatScore - 热度分数 - */ - const trackPopularKeywordClicked = useCallback((keyword, position = 0, heatScore = 0) => { - if (!keyword) { - logger.warn('useSearchEvents', 'trackPopularKeywordClicked: keyword is required'); - return; - } - - track('Popular Keyword Clicked', { - keyword, - position, - heat_score: heatScore, - context, - timestamp: new Date().toISOString(), - }); - - logger.debug('useSearchEvents', '🔥 Popular Keyword Clicked', { - keyword, - position, - context, - }); - }, [track, context]); - - return { - // 搜索流程事件 - trackSearchInitiated, - trackSearchQuerySubmitted, - trackSearchResultClicked, - - // 筛选和建议 - trackSearchFilterApplied, - trackSearchSuggestionClicked, - - // 历史和热门 - trackSearchHistoryViewed, - trackSearchHistoryCleared, - trackPopularKeywordClicked, - }; -}; - -export default useSearchEvents; diff --git a/src/views/Community/components/SearchBox.js b/src/views/Community/components/SearchBox.js deleted file mode 100644 index aa61ccc5..00000000 --- a/src/views/Community/components/SearchBox.js +++ /dev/null @@ -1,59 +0,0 @@ -// src/views/Community/components/SearchBox.js -import React from 'react'; -import { Card, Input, Radio, Form, Button } from 'antd'; -import { SearchOutlined } from '@ant-design/icons'; -import { useSearchEvents } from '../../../hooks/useSearchEvents'; - -const SearchBox = ({ onSearch }) => { - const [form] = Form.useForm(); - - // 🎯 初始化搜索埋点Hook - const searchEvents = useSearchEvents({ context: 'community' }); - - const handleSubmit = (values) => { - // 🎯 追踪搜索查询提交(在调用onSearch之前) - if (values.q) { - searchEvents.trackSearchQuerySubmitted(values.q, 0, { - search_type: values.search_type || 'topic' - }); - } - onSearch(values); - }; - - return ( - -
- - } - onSearch={(value) => { - form.setFieldsValue({ q: value }); - form.submit(); - }} - /> - - - - - 搜索话题 - 搜索股票 - - - - - - -
-
- ); -}; - -export default SearchBox; \ No newline at end of file diff --git a/src/views/Community/components/StockDetailPanel/components/index.js b/src/views/Community/components/StockDetailPanel/components/index.js deleted file mode 100644 index 938e8b05..00000000 --- a/src/views/Community/components/StockDetailPanel/components/index.js +++ /dev/null @@ -1,2 +0,0 @@ -// src/views/Community/components/StockDetailPanel/components/index.js -export { default as MiniTimelineChart } from './MiniTimelineChart';