funel data
This commit is contained in:
@@ -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 />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user