funel data

This commit is contained in:
2025-03-11 00:49:11 +08:00
parent bc42ff4dbf
commit db2aedf0a6

View File

@@ -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<string | null>(null);
const [filteredEngagementData, setFilteredEngagementData] = useState<EngagementData[]>([]);
// 添加项目相关状态
const [projects, setProjects] = useState<Project[]>([
{ 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<string>('1');
// Add new state for influencer tracking
const [showTrackingForm, setShowTrackingForm] = useState(false);
const [trackingForm, setTrackingForm] = useState<InfluencerTrackingForm>({
@@ -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 = () => {
</div>
);
// 项目选择器组件
const ProjectSelector = () => (
<div className="mb-6">
<label htmlFor="project-select" className="block text-sm font-medium text-gray-700 mb-2">
</label>
<div className="relative">
<select
id="project-select"
value={selectedProject}
onChange={(e) => setSelectedProject(e.target.value)}
className="block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md"
>
{projects.map((project) => (
<option key={project.id} value={project.id}>
{project.name}
</option>
))}
</select>
<div className="absolute inset-y-0 right-0 flex items-center px-2 pointer-events-none">
<ArrowRight className="h-4 w-4 text-gray-400" />
</div>
</div>
</div>
);
return (
<div className="flex-1 overflow-auto">
<div className="p-6">
<h1 className="mb-6 text-2xl font-bold">Analytics Dashboard</h1>
{/* 添加项目选择器 */}
<ProjectSelector />
{/* Add the Influencer Tracking Form at the top */}
<InfluencerTrackingFormComponent />