From e3721b22ff09fc998d50fda1d58d9b6152e53517 Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Tue, 28 Oct 2025 21:58:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20LimitAnalyse=EF=BC=88=E6=B6=A8=E5=81=9C?= =?UTF-8?q?=E5=88=86=E6=9E=90=EF=BC=89=20-=201=20=E4=B8=AA=20Hook=EF=BC=8C?= =?UTF-8?q?=E4=B8=BB=E9=A1=B5=E9=9D=A2=E9=9B=86=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hooks/useLimitAnalyseEvents.js | 252 ++++++++++++++++++ src/views/LimitAnalyse/index.js | 31 +++ 2 files changed, 283 insertions(+) create mode 100644 src/views/LimitAnalyse/hooks/useLimitAnalyseEvents.js diff --git a/src/views/LimitAnalyse/hooks/useLimitAnalyseEvents.js b/src/views/LimitAnalyse/hooks/useLimitAnalyseEvents.js new file mode 100644 index 00000000..7a0c245e --- /dev/null +++ b/src/views/LimitAnalyse/hooks/useLimitAnalyseEvents.js @@ -0,0 +1,252 @@ +// src/views/LimitAnalyse/hooks/useLimitAnalyseEvents.js +// 涨停分析页面事件追踪 Hook + +import { useCallback, useEffect } from 'react'; +import { usePostHogTrack } from '../../../hooks/usePostHogRedux'; +import { RETENTION_EVENTS } from '../../../lib/constants'; +import { logger } from '../../../utils/logger'; + +/** + * 涨停分析事件追踪 Hook + * @param {Object} options - 配置选项 + * @param {Function} options.navigate - 路由导航函数 + * @returns {Object} 事件追踪方法集合 + */ +export const useLimitAnalyseEvents = ({ navigate } = {}) => { + const { track } = usePostHogTrack(); + + // 页面浏览追踪 - 组件加载时自动触发 + useEffect(() => { + track(RETENTION_EVENTS.LIMIT_ANALYSE_PAGE_VIEWED, { + timestamp: new Date().toISOString(), + }); + logger.debug('useLimitAnalyseEvents', '👁️ Limit Analyse Page Viewed'); + }, [track]); + + /** + * 追踪日期选择 + * @param {string} date - 选择的日期(YYYYMMDD 格式) + * @param {string} previousDate - 之前的日期 + */ + const trackDateSelected = useCallback((date, previousDate = null) => { + track(RETENTION_EVENTS.SEARCH_FILTER_APPLIED, { + filter_type: 'date', + filter_value: date, + previous_value: previousDate, + context: 'limit_analyse', + }); + + logger.debug('useLimitAnalyseEvents', '📅 Date Selected', { + date, + previousDate, + }); + }, [track]); + + /** + * 追踪每日统计数据查看 + * @param {Object} stats - 统计数据 + * @param {string} date - 日期 + */ + const trackDailyStatsViewed = useCallback((stats, date) => { + if (!stats) return; + + track(RETENTION_EVENTS.LIMIT_ANALYSE_PAGE_VIEWED, { + date, + total_stocks: stats.total_stocks, + sector_count: stats.sectors?.length || 0, + hot_sector: stats.hot_sector?.name, + view_type: 'daily_stats', + }); + + logger.debug('useLimitAnalyseEvents', '📊 Daily Stats Viewed', { + date, + totalStocks: stats.total_stocks, + }); + }, [track]); + + /** + * 追踪板块展开/收起 + * @param {string} sectorName - 板块名称 + * @param {boolean} isExpanded - 是否展开 + * @param {number} stockCount - 板块内股票数量 + */ + const trackSectorToggled = useCallback((sectorName, isExpanded, stockCount = 0) => { + track(RETENTION_EVENTS.LIMIT_SECTOR_EXPANDED, { + sector_name: sectorName, + action: isExpanded ? 'expand' : 'collapse', + stock_count: stockCount, + source: 'limit_analyse', + }); + + logger.debug('useLimitAnalyseEvents', '🔽 Sector Toggled', { + sectorName, + isExpanded, + stockCount, + }); + }, [track]); + + /** + * 追踪板块点击 + * @param {Object} sector - 板块对象 + */ + const trackSectorClicked = useCallback((sector) => { + track(RETENTION_EVENTS.LIMIT_BOARD_CLICKED, { + sector_name: sector.name, + stock_count: sector.count, + source: 'limit_analyse', + }); + + logger.debug('useLimitAnalyseEvents', '🎯 Sector Clicked', { + sectorName: sector.name, + }); + }, [track]); + + /** + * 追踪涨停股票点击 + * @param {Object} stock - 股票对象 + * @param {string} sectorName - 所属板块 + */ + const trackLimitStockClicked = useCallback((stock, sectorName = '') => { + track(RETENTION_EVENTS.LIMIT_STOCK_CLICKED, { + stock_code: stock.code || stock.stock_code, + stock_name: stock.name || stock.stock_name, + sector_name: sectorName, + limit_time: stock.limit_time, + source: 'limit_analyse', + }); + + logger.debug('useLimitAnalyseEvents', '📈 Limit Stock Clicked', { + stockCode: stock.code || stock.stock_code, + sectorName, + }); + }, [track]); + + /** + * 追踪搜索发起 + * @param {string} query - 搜索关键词 + * @param {string} searchType - 搜索类型(all/sector/stock) + * @param {string} searchMode - 搜索模式(hybrid/standard) + */ + const trackSearchInitiated = useCallback((query, searchType = 'all', searchMode = 'hybrid') => { + track(RETENTION_EVENTS.SEARCH_INITIATED, { + context: 'limit_analyse', + }); + + track(RETENTION_EVENTS.SEARCH_QUERY_SUBMITTED, { + query, + category: 'limit_analyse', + search_type: searchType, + search_mode: searchMode, + }); + + logger.debug('useLimitAnalyseEvents', '🔍 Search Initiated', { + query, + searchType, + searchMode, + }); + }, [track]); + + /** + * 追踪搜索结果点击 + * @param {Object} result - 搜索结果对象 + * @param {number} position - 在结果列表中的位置 + */ + const trackSearchResultClicked = useCallback((result, position = 0) => { + track(RETENTION_EVENTS.SEARCH_RESULT_CLICKED, { + result_type: result.type, + result_id: result.id || result.code, + result_name: result.name, + position, + context: 'limit_analyse', + }); + + logger.debug('useLimitAnalyseEvents', '🎯 Search Result Clicked', { + type: result.type, + name: result.name, + position, + }); + }, [track]); + + /** + * 追踪高位股查看 + * @param {string} date - 日期 + * @param {Object} stats - 高位股统计数据 + */ + const trackHighPositionStocksViewed = useCallback((date, stats = {}) => { + track(RETENTION_EVENTS.LIMIT_ANALYSE_PAGE_VIEWED, { + date, + view_type: 'high_position_stocks', + total_count: stats.total_count || 0, + max_consecutive_days: stats.max_consecutive_days || 0, + }); + + logger.debug('useLimitAnalyseEvents', '📊 High Position Stocks Viewed', { + date, + stats, + }); + }, [track]); + + /** + * 追踪板块分析查看(分布图/关联图) + * @param {string} date - 日期 + * @param {string} analysisType - 分析类型(distribution/relation/wordcloud) + */ + const trackSectorAnalysisViewed = useCallback((date, analysisType) => { + track(RETENTION_EVENTS.LIMIT_SECTOR_ANALYSIS_VIEWED, { + date, + analysis_type: analysisType, + source: 'limit_analyse', + }); + + logger.debug('useLimitAnalyseEvents', '📊 Sector Analysis Viewed', { + date, + analysisType, + }); + }, [track]); + + /** + * 追踪数据刷新 + * @param {string} date - 刷新的日期 + */ + const trackDataRefreshed = useCallback((date) => { + track(RETENTION_EVENTS.SEARCH_FILTER_APPLIED, { + filter_type: 'refresh', + filter_value: date, + context: 'limit_analyse', + }); + + logger.debug('useLimitAnalyseEvents', '🔄 Data Refreshed', { date }); + }, [track]); + + /** + * 追踪股票详情Modal打开 + * @param {string} stockCode - 股票代码 + * @param {string} stockName - 股票名称 + */ + const trackStockDetailViewed = useCallback((stockCode, stockName) => { + track(RETENTION_EVENTS.STOCK_DETAIL_VIEWED, { + stock_code: stockCode, + stock_name: stockName, + source: 'limit_analyse_modal', + }); + + logger.debug('useLimitAnalyseEvents', '👁️ Stock Detail Modal Opened', { + stockCode, + stockName, + }); + }, [track]); + + return { + trackDateSelected, + trackDailyStatsViewed, + trackSectorToggled, + trackSectorClicked, + trackLimitStockClicked, + trackSearchInitiated, + trackSearchResultClicked, + trackHighPositionStocksViewed, + trackSectorAnalysisViewed, + trackDataRefreshed, + trackStockDetailViewed, + }; +}; diff --git a/src/views/LimitAnalyse/index.js b/src/views/LimitAnalyse/index.js index 8278dde9..18ca03f1 100755 --- a/src/views/LimitAnalyse/index.js +++ b/src/views/LimitAnalyse/index.js @@ -48,6 +48,7 @@ import { AdvancedSearch, SearchResultsModal } from './components/SearchComponent // 导入高位股统计组件 import HighPositionStocks from './components/HighPositionStocks'; import { logger } from '../../utils/logger'; +import { useLimitAnalyseEvents } from './hooks/useLimitAnalyseEvents'; // 主组件 export default function LimitAnalyse() { @@ -62,6 +63,21 @@ export default function LimitAnalyse() { const toast = useToast(); + // 🎯 PostHog 事件追踪 + const { + trackDateSelected, + trackDailyStatsViewed, + trackSectorToggled, + trackSectorClicked, + trackLimitStockClicked, + trackSearchInitiated, + trackSearchResultClicked, + trackHighPositionStocksViewed, + trackSectorAnalysisViewed, + trackDataRefreshed, + trackStockDetailViewed, + } = useLimitAnalyseEvents(); + const bgColor = useColorModeValue('gray.50', 'gray.900'); const cardBg = useColorModeValue('white', 'gray.800'); const accentColor = useColorModeValue('blue.500', 'blue.300'); @@ -126,6 +142,9 @@ export default function LimitAnalyse() { if (data.success) { setDailyData(data.data); + // 🎯 追踪每日统计数据查看 + trackDailyStatsViewed(data.data, date); + // 获取词云数据 fetchWordCloudData(date); @@ -169,14 +188,26 @@ export default function LimitAnalyse() { // 处理日期选择 const handleDateChange = (date) => { + const previousDateStr = dateStr; setSelectedDate(date); const dateString = formatDateStr(date); setDateStr(dateString); + + // 🎯 追踪日期选择 + trackDateSelected(dateString, previousDateStr); + fetchDailyAnalysis(dateString); }; // 处理搜索 const handleSearch = async (searchParams) => { + // 🎯 追踪搜索开始 + trackSearchInitiated( + searchParams.query, + searchParams.type || 'all', + searchParams.mode || 'hybrid' + ); + setLoading(true); try { const response = await fetch(`${API_URL}/api/v1/stocks/search/hybrid`, {