feat: LimitAnalyse(涨停分析) - 1 个 Hook,主页面集成
This commit is contained in:
252
src/views/LimitAnalyse/hooks/useLimitAnalyseEvents.js
Normal file
252
src/views/LimitAnalyse/hooks/useLimitAnalyseEvents.js
Normal 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,
|
||||
};
|
||||
};
|
||||
@@ -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`, {
|
||||
|
||||
Reference in New Issue
Block a user