Files
vf_react/src/views/Community/hooks/useCommunityEvents.js
zdl 1cf6169370 feat: 创建了 4个核心埋点Hook
-  覆盖了 45+个追踪事件
  -  补充了 4个核心功能模块的完整埋点
  -  提供了 详细的集成指南和示例代码
  -  提升了 Retention指标覆盖率至90%
  -  建立了 Revenue转化追踪基础
2025-10-29 11:40:32 +08:00

282 lines
8.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/views/Community/hooks/useCommunityEvents.js
// 新闻催化分析页面事件追踪 Hook
import { useCallback, useEffect } from 'react';
import { usePostHogTrack } from '../../../hooks/usePostHogRedux';
import { RETENTION_EVENTS } from '../../../lib/constants';
import { logger } from '../../../utils/logger';
/**
* 新闻催化分析Community事件追踪 Hook
* @param {Object} options - 配置选项
* @param {Function} options.navigate - 路由导航函数
* @returns {Object} 事件追踪处理函数集合
*/
export const useCommunityEvents = ({ navigate } = {}) => {
const { track } = usePostHogTrack();
// 🎯 页面浏览事件 - 页面加载时触发
useEffect(() => {
track(RETENTION_EVENTS.COMMUNITY_PAGE_VIEWED, {
timestamp: new Date().toISOString(),
});
logger.debug('useCommunityEvents', '📰 Community Page Viewed');
}, [track]);
/**
* 追踪新闻列表查看
* @param {Object} params - 列表参数
* @param {number} params.totalCount - 新闻总数
* @param {string} params.sortBy - 排序方式 ('new' | 'hot' | 'returns')
* @param {string} params.importance - 重要性筛选 ('all' | 'high' | 'medium' | 'low')
* @param {string} params.dateRange - 日期范围
* @param {string} params.industryFilter - 行业筛选
*/
const trackNewsListViewed = useCallback((params = {}) => {
track(RETENTION_EVENTS.NEWS_LIST_VIEWED, {
total_count: params.totalCount || 0,
sort_by: params.sortBy || 'new',
importance_filter: params.importance || 'all',
date_range: params.dateRange || 'all',
industry_filter: params.industryFilter || 'all',
timestamp: new Date().toISOString(),
});
logger.debug('useCommunityEvents', '📋 News List Viewed', params);
}, [track]);
/**
* 追踪新闻文章点击
* @param {Object} news - 新闻对象
* @param {number} news.id - 新闻ID
* @param {string} news.title - 新闻标题
* @param {string} news.importance - 重要性等级
* @param {number} position - 在列表中的位置
* @param {string} source - 点击来源 ('list' | 'search' | 'recommendation')
*/
const trackNewsArticleClicked = useCallback((news, position = 0, source = 'list') => {
if (!news || !news.id) {
logger.warn('useCommunityEvents', 'trackNewsArticleClicked: news object is required');
return;
}
track(RETENTION_EVENTS.NEWS_ARTICLE_CLICKED, {
news_id: news.id,
news_title: news.title || '',
importance: news.importance || 'unknown',
position,
source,
timestamp: new Date().toISOString(),
});
logger.debug('useCommunityEvents', '🖱️ News Article Clicked', {
id: news.id,
position,
source,
});
}, [track]);
/**
* 追踪新闻详情打开
* @param {Object} news - 新闻对象
* @param {number} news.id - 新闻ID
* @param {string} news.title - 新闻标题
* @param {string} news.importance - 重要性等级
* @param {string} viewMode - 查看模式 ('modal' | 'page')
*/
const trackNewsDetailOpened = useCallback((news, viewMode = 'modal') => {
if (!news || !news.id) {
logger.warn('useCommunityEvents', 'trackNewsDetailOpened: news object is required');
return;
}
track(RETENTION_EVENTS.NEWS_DETAIL_OPENED, {
news_id: news.id,
news_title: news.title || '',
importance: news.importance || 'unknown',
view_mode: viewMode,
timestamp: new Date().toISOString(),
});
logger.debug('useCommunityEvents', '📖 News Detail Opened', {
id: news.id,
viewMode,
});
}, [track]);
/**
* 追踪新闻标签页切换
* @param {string} tabName - 标签名称 ('related_stocks' | 'related_concepts' | 'timeline')
* @param {number} newsId - 新闻ID
*/
const trackNewsTabClicked = useCallback((tabName, newsId = null) => {
if (!tabName) {
logger.warn('useCommunityEvents', 'trackNewsTabClicked: tabName is required');
return;
}
track(RETENTION_EVENTS.NEWS_TAB_CLICKED, {
tab_name: tabName,
news_id: newsId,
timestamp: new Date().toISOString(),
});
logger.debug('useCommunityEvents', '📑 News Tab Clicked', {
tabName,
newsId,
});
}, [track]);
/**
* 追踪新闻筛选应用
* @param {Object} filters - 筛选条件
* @param {string} filters.importance - 重要性筛选
* @param {string} filters.dateRange - 日期范围
* @param {string} filters.industryClassification - 行业分类
* @param {string} filters.industryCode - 行业代码
*/
const trackNewsFilterApplied = useCallback((filters = {}) => {
track(RETENTION_EVENTS.NEWS_FILTER_APPLIED, {
importance: filters.importance || 'all',
date_range: filters.dateRange || 'all',
industry_classification: filters.industryClassification || 'all',
industry_code: filters.industryCode || 'all',
filter_count: Object.keys(filters).filter(key => filters[key] && filters[key] !== 'all').length,
timestamp: new Date().toISOString(),
});
logger.debug('useCommunityEvents', '🔍 News Filter Applied', filters);
}, [track]);
/**
* 追踪新闻排序方式变更
* @param {string} sortBy - 排序方式 ('new' | 'hot' | 'returns')
* @param {string} previousSort - 之前的排序方式
*/
const trackNewsSorted = useCallback((sortBy, previousSort = 'new') => {
if (!sortBy) {
logger.warn('useCommunityEvents', 'trackNewsSorted: sortBy is required');
return;
}
track(RETENTION_EVENTS.NEWS_SORTED, {
sort_by: sortBy,
previous_sort: previousSort,
timestamp: new Date().toISOString(),
});
logger.debug('useCommunityEvents', '🔄 News Sorted', {
sortBy,
previousSort,
});
}, [track]);
/**
* 追踪搜索事件(新闻搜索)
* @param {string} query - 搜索关键词
* @param {number} resultCount - 搜索结果数量
*/
const trackNewsSearched = useCallback((query, resultCount = 0) => {
if (!query) return;
track(RETENTION_EVENTS.SEARCH_QUERY_SUBMITTED, {
query,
result_count: resultCount,
has_results: resultCount > 0,
context: 'community_news',
timestamp: new Date().toISOString(),
});
// 如果没有搜索结果,额外追踪
if (resultCount === 0) {
track(RETENTION_EVENTS.SEARCH_NO_RESULTS, {
query,
context: 'community_news',
timestamp: new Date().toISOString(),
});
}
logger.debug('useCommunityEvents', '🔍 News Searched', {
query,
resultCount,
});
}, [track]);
/**
* 追踪相关股票点击(从新闻详情)
* @param {Object} stock - 股票对象
* @param {string} stock.code - 股票代码
* @param {string} stock.name - 股票名称
* @param {number} newsId - 关联的新闻ID
*/
const trackRelatedStockClicked = useCallback((stock, newsId = null) => {
if (!stock || !stock.code) {
logger.warn('useCommunityEvents', 'trackRelatedStockClicked: stock object is required');
return;
}
track(RETENTION_EVENTS.STOCK_CLICKED, {
stock_code: stock.code,
stock_name: stock.name || '',
source: 'news_related_stocks',
news_id: newsId,
timestamp: new Date().toISOString(),
});
logger.debug('useCommunityEvents', '🎯 Related Stock Clicked', {
stockCode: stock.code,
newsId,
});
}, [track]);
/**
* 追踪相关概念点击(从新闻详情)
* @param {Object} concept - 概念对象
* @param {string} concept.code - 概念代码
* @param {string} concept.name - 概念名称
* @param {number} newsId - 关联的新闻ID
*/
const trackRelatedConceptClicked = useCallback((concept, newsId = null) => {
if (!concept || !concept.code) {
logger.warn('useCommunityEvents', 'trackRelatedConceptClicked: concept object is required');
return;
}
track(RETENTION_EVENTS.CONCEPT_CLICKED, {
concept_code: concept.code,
concept_name: concept.name || '',
source: 'news_related_concepts',
news_id: newsId,
timestamp: new Date().toISOString(),
});
logger.debug('useCommunityEvents', '🏷️ Related Concept Clicked', {
conceptCode: concept.code,
newsId,
});
}, [track]);
return {
// 页面级事件
trackNewsListViewed,
// 新闻交互事件
trackNewsArticleClicked,
trackNewsDetailOpened,
trackNewsTabClicked,
// 筛选和排序事件
trackNewsFilterApplied,
trackNewsSorted,
// 搜索事件
trackNewsSearched,
// 关联内容点击事件
trackRelatedStockClicked,
trackRelatedConceptClicked,
};
};
export default useCommunityEvents;