diff --git a/web/src/components/Analytics.tsx b/web/src/components/Analytics.tsx index 1771113..be4cfe5 100644 --- a/web/src/components/Analytics.tsx +++ b/web/src/components/Analytics.tsx @@ -98,6 +98,13 @@ interface InfluencerTrackingForm { likesCount: number; } +// 在接口定义部分添加项目接口 +interface Project { + id: string; + name: string; + description?: string; +} + const Analytics: React.FC = () => { const [timeRange, setTimeRange] = useState('7days'); const [selectedKOL, setSelectedKOL] = useState('all'); @@ -117,6 +124,15 @@ const Analytics: React.FC = () => { const [error, setError] = useState(null); const [filteredEngagementData, setFilteredEngagementData] = useState([]); + // 添加项目相关状态 + const [projects, setProjects] = useState([ + { id: '1', name: '项目 1', description: '示例项目 1' }, + { id: '2', name: '项目 2', description: '示例项目 2' }, + { id: '3', name: '项目 3', description: '示例项目 3' }, + { id: '550e8400-e29b-41d4-a716-446655440000', name: 'UUID格式项目', description: 'UUID格式的项目ID示例' } + ]); + const [selectedProject, setSelectedProject] = useState('1'); + // Add new state for influencer tracking const [showTrackingForm, setShowTrackingForm] = useState(false); const [trackingForm, setTrackingForm] = useState({ @@ -233,13 +249,42 @@ const Analytics: React.FC = () => { // 尝试从API获取漏斗数据 try { - // 这里使用一个示例项目ID,实际使用时应该从props或状态中获取 - const projectId = '1'; - const response = await fetch(`http://localhost:4000/api/analytics/project/${projectId}/conversion-funnel?timeRange=${timeRange}`); + // 使用选中的项目ID + const projectId = selectedProject; + + // 添加认证头 + const authToken = 'eyJhbGciOiJIUzI1NiIsImtpZCI6Inl3blNGYnRBOGtBUnl4UmUiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3h0cWhsdXpvcm5hemxta29udWNyLnN1cGFiYXNlLmNvL2F1dGgvdjEiLCJzdWIiOiI1YjQzMThiZi0yMWE4LTQ3YWMtOGJmYS0yYThmOGVmOWMwZmIiLCJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNzQxNjI3ODkyLCJpYXQiOjE3NDE2MjQyOTIsImVtYWlsIjoidml0YWxpdHltYWlsZ0BnbWFpbC5jb20iLCJwaG9uZSI6IiIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6ImVtYWlsIiwicHJvdmlkZXJzIjpbImVtYWlsIl19LCJ1c2VyX21ldGFkYXRhIjp7ImVtYWlsX3ZlcmlmaWVkIjp0cnVlfSwicm9sZSI6ImF1dGhlbnRpY2F0ZWQiLCJhYWwiOiJhYWwxIiwiYW1yIjpbeyJtZXRob2QiOiJwYXNzd29yZCIsInRpbWVzdGFtcCI6MTc0MTYyNDI5Mn1dLCJzZXNzaW9uX2lkIjoiODlmYjg0YzktZmEzYy00YmVlLTk0MDQtNjI1MjE0OGIyMzVlIiwiaXNfYW5vbnltb3VzIjpmYWxzZX0.VuUX2yhqN-FZseKL8fQG91i1cohfRqW2m1Z8CIWhZuk'; + + const response = await fetch(`http://localhost:4000/api/analytics/project/${projectId}/conversion-funnel?timeframe=${timeRange}`, { + headers: { + 'accept': 'application/json', + 'Authorization': `Bearer ${authToken}` + } + }); if (response.ok) { const data = await response.json(); - setFunnelData(data.funnel_data || []); + console.log('成功获取漏斗数据:', data); + + if (data.funnel_data) { + setFunnelData(data.funnel_data); + + // 如果是模拟数据,在控制台显示提示 + if (data.is_mock_data) { + console.info('注意: 使用的是模拟数据,因为无法连接到数据库或找不到项目'); + } + } else { + console.error('API返回的数据中没有funnel_data字段'); + // 使用模拟数据作为后备 + setFunnelData([ + { stage: 'Awareness', count: 10000, rate: 100 }, + { stage: 'Interest', count: 7500, rate: 75 }, + { stage: 'Consideration', count: 5000, rate: 50 }, + { stage: 'Intent', count: 3000, rate: 30 }, + { stage: 'Evaluation', count: 2000, rate: 20 }, + { stage: 'Purchase', count: 1000, rate: 10 } + ]); + } } else { console.error('Failed to fetch funnel data from API, using mock data instead'); // 使用模拟数据作为后备 @@ -273,7 +318,7 @@ const Analytics: React.FC = () => { }; fetchAnalyticsData(); - }, [timeRange]); + }, [timeRange, selectedProject]); // 添加selectedProject作为依赖项 // Filter KOLs based on selected platform const filteredKOLs = selectedPlatform === 'all' @@ -548,11 +593,40 @@ const Analytics: React.FC = () => { ); + // 项目选择器组件 + const ProjectSelector = () => ( +
+ +
+ +
+ +
+
+
+ ); + return (

Analytics Dashboard

+ {/* 添加项目选择器 */} + + {/* Add the Influencer Tracking Form at the top */}