feat: LimitAnalyse(涨停分析) - 1 个 Hook,主页面集成

This commit is contained in:
zdl
2025-10-28 21:58:43 +08:00
parent 357b8bbdd7
commit e3721b22ff
2 changed files with 283 additions and 0 deletions

View File

@@ -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,
};
};

View File

@@ -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`, {