351 lines
11 KiB
JavaScript
351 lines
11 KiB
JavaScript
// 生成KOL合作转换漏斗测试数据的脚本
|
||
const { createClient } = require('@supabase/supabase-js');
|
||
const dotenv = require('dotenv');
|
||
const path = require('path');
|
||
|
||
// 加载环境变量
|
||
dotenv.config({ path: path.resolve(__dirname, '../.env') });
|
||
|
||
// 创建Supabase客户端
|
||
const supabaseUrl = process.env.SUPABASE_URL;
|
||
const supabaseKey = process.env.SUPABASE_KEY;
|
||
|
||
if (!supabaseUrl || !supabaseKey) {
|
||
console.error('缺少Supabase配置。请确保.env文件中包含SUPABASE_URL和SUPABASE_KEY');
|
||
process.exit(1);
|
||
}
|
||
|
||
const supabase = createClient(supabaseUrl, supabaseKey);
|
||
|
||
// 生成随机字符串
|
||
const generateRandomString = (length = 8) => {
|
||
return Math.random().toString(36).substring(2, length + 2);
|
||
};
|
||
|
||
// 生成随机日期
|
||
const generateRandomDate = (startDate, endDate) => {
|
||
const start = startDate.getTime();
|
||
const end = endDate.getTime();
|
||
const randomTime = start + Math.random() * (end - start);
|
||
return new Date(randomTime).toISOString();
|
||
};
|
||
|
||
// 生成随机数字
|
||
const generateRandomNumber = (min, max) => {
|
||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||
};
|
||
|
||
// 创建测试项目
|
||
const createTestProject = async () => {
|
||
console.log('创建测试项目...');
|
||
|
||
const projectName = `漏斗测试项目-${generateRandomString()}`;
|
||
|
||
const { data, error } = await supabase
|
||
.from('projects')
|
||
.insert({
|
||
name: projectName,
|
||
description: '这是一个用于测试KOL合作转换漏斗API的项目',
|
||
created_at: new Date().toISOString(),
|
||
updated_at: new Date().toISOString()
|
||
})
|
||
.select()
|
||
.single();
|
||
|
||
if (error) {
|
||
console.error('创建测试项目失败:', error);
|
||
process.exit(1);
|
||
}
|
||
|
||
console.log(`测试项目创建成功: ${data.name} (ID: ${data.id})`);
|
||
return data.id;
|
||
};
|
||
|
||
// 创建测试KOL
|
||
const createTestInfluencers = async (count) => {
|
||
console.log(`创建${count}个测试KOL...`);
|
||
|
||
const platforms = ['instagram', 'youtube', 'tiktok', 'twitter', 'facebook'];
|
||
const influencers = [];
|
||
|
||
// 创建不同阶段的KOL
|
||
// 1. 认知阶段 - 所有KOL (100%)
|
||
// 2. 兴趣阶段 - 75%的KOL有内容
|
||
// 3. 考虑阶段 - 50%的KOL有高互动率
|
||
// 4. 意向阶段 - 30%的KOL有多篇内容
|
||
// 5. 评估阶段 - 20%的KOL有高浏览量
|
||
// 6. 购买阶段 - 10%的KOL是长期合作(3个月以上)
|
||
|
||
// 计算各阶段的KOL数量
|
||
const awarenessCount = count;
|
||
const interestCount = Math.floor(count * 0.75);
|
||
const considerationCount = Math.floor(count * 0.5);
|
||
const intentCount = Math.floor(count * 0.3);
|
||
const evaluationCount = Math.floor(count * 0.2);
|
||
const purchaseCount = Math.floor(count * 0.1);
|
||
|
||
// 创建所有KOL
|
||
for (let i = 0; i < count; i++) {
|
||
const platform = platforms[Math.floor(Math.random() * platforms.length)];
|
||
|
||
// 根据KOL所处阶段设置不同的创建日期
|
||
let createdAt;
|
||
|
||
if (i < purchaseCount) {
|
||
// 购买阶段 - 创建日期在3个月以前
|
||
createdAt = generateRandomDate(
|
||
new Date(Date.now() - 365 * 24 * 60 * 60 * 1000), // 1年前
|
||
new Date(Date.now() - 90 * 24 * 60 * 60 * 1000) // 3个月前
|
||
);
|
||
} else if (i < evaluationCount) {
|
||
// 评估阶段 - 创建日期在1-3个月之间
|
||
createdAt = generateRandomDate(
|
||
new Date(Date.now() - 90 * 24 * 60 * 60 * 1000), // 3个月前
|
||
new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) // 1个月前
|
||
);
|
||
} else if (i < intentCount) {
|
||
// 意向阶段 - 创建日期在2周-1个月之间
|
||
createdAt = generateRandomDate(
|
||
new Date(Date.now() - 30 * 24 * 60 * 60 * 1000), // 1个月前
|
||
new Date(Date.now() - 14 * 24 * 60 * 60 * 1000) // 2周前
|
||
);
|
||
} else if (i < considerationCount) {
|
||
// 考虑阶段 - 创建日期在1-2周之间
|
||
createdAt = generateRandomDate(
|
||
new Date(Date.now() - 14 * 24 * 60 * 60 * 1000), // 2周前
|
||
new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) // 1周前
|
||
);
|
||
} else if (i < interestCount) {
|
||
// 兴趣阶段 - 创建日期在3天-1周之间
|
||
createdAt = generateRandomDate(
|
||
new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), // 1周前
|
||
new Date(Date.now() - 3 * 24 * 60 * 60 * 1000) // 3天前
|
||
);
|
||
} else {
|
||
// 认知阶段 - 创建日期在3天内
|
||
createdAt = generateRandomDate(
|
||
new Date(Date.now() - 3 * 24 * 60 * 60 * 1000), // 3天前
|
||
new Date() // 现在
|
||
);
|
||
}
|
||
|
||
influencers.push({
|
||
name: `测试KOL-${generateRandomString()}`,
|
||
platform,
|
||
profile_url: `https://${platform}.com/user${generateRandomString()}`,
|
||
followers_count: generateRandomNumber(1000, 1000000),
|
||
created_at: createdAt,
|
||
updated_at: new Date().toISOString()
|
||
});
|
||
}
|
||
|
||
const { data, error } = await supabase
|
||
.from('influencers')
|
||
.insert(influencers)
|
||
.select();
|
||
|
||
if (error) {
|
||
console.error('创建测试KOL失败:', error);
|
||
process.exit(1);
|
||
}
|
||
|
||
console.log(`${data.length}个测试KOL创建成功`);
|
||
return data;
|
||
};
|
||
|
||
// 将KOL添加到项目
|
||
const addInfluencersToProject = async (projectId, influencers) => {
|
||
console.log(`将KOL添加到项目 ${projectId}...`);
|
||
|
||
const projectInfluencers = influencers.map(influencer => ({
|
||
project_id: projectId,
|
||
influencer_id: influencer.id,
|
||
created_at: new Date().toISOString(),
|
||
updated_at: new Date().toISOString()
|
||
}));
|
||
|
||
const { data, error } = await supabase
|
||
.from('project_influencers')
|
||
.insert(projectInfluencers)
|
||
.select();
|
||
|
||
if (error) {
|
||
console.error('将KOL添加到项目失败:', error);
|
||
process.exit(1);
|
||
}
|
||
|
||
console.log(`${data.length}个KOL成功添加到项目`);
|
||
return data;
|
||
};
|
||
|
||
// 创建测试内容
|
||
const createTestPosts = async (projectId, influencers) => {
|
||
console.log(`为项目 ${projectId} 创建测试内容...`);
|
||
|
||
const posts = [];
|
||
|
||
// 为不同阶段的KOL创建不同数量的内容
|
||
const awarenessCount = influencers.length;
|
||
const interestCount = Math.floor(influencers.length * 0.75);
|
||
const considerationCount = Math.floor(influencers.length * 0.5);
|
||
const intentCount = Math.floor(influencers.length * 0.3);
|
||
const evaluationCount = Math.floor(influencers.length * 0.2);
|
||
|
||
for (let i = 0; i < influencers.length; i++) {
|
||
const influencer = influencers[i];
|
||
|
||
// 根据KOL所处阶段创建不同数量的内容
|
||
let postCount;
|
||
|
||
if (i < evaluationCount) {
|
||
// 评估阶段 - 3-5篇内容
|
||
postCount = generateRandomNumber(3, 5);
|
||
} else if (i < intentCount) {
|
||
// 意向阶段 - 2-3篇内容
|
||
postCount = generateRandomNumber(2, 3);
|
||
} else if (i < considerationCount) {
|
||
// 考虑阶段 - 1-2篇内容
|
||
postCount = generateRandomNumber(1, 2);
|
||
} else if (i < interestCount) {
|
||
// 兴趣阶段 - 1篇内容
|
||
postCount = 1;
|
||
} else {
|
||
// 认知阶段 - 无内容
|
||
postCount = 0;
|
||
}
|
||
|
||
for (let j = 0; j < postCount; j++) {
|
||
const publishedAt = generateRandomDate(
|
||
new Date(Date.now() - 90 * 24 * 60 * 60 * 1000), // 3个月前
|
||
new Date() // 现在
|
||
);
|
||
|
||
posts.push({
|
||
project_id: projectId,
|
||
influencer_id: influencer.id,
|
||
platform: influencer.platform,
|
||
title: `测试内容-${generateRandomString()}`,
|
||
description: `这是KOL ${influencer.name} 的测试内容`,
|
||
post_url: `https://${influencer.platform}.com/post/${generateRandomString()}`,
|
||
published_at: publishedAt,
|
||
created_at: new Date().toISOString(),
|
||
updated_at: new Date().toISOString()
|
||
});
|
||
}
|
||
}
|
||
|
||
if (posts.length === 0) {
|
||
console.log('没有创建任何内容');
|
||
return [];
|
||
}
|
||
|
||
const { data, error } = await supabase
|
||
.from('posts')
|
||
.insert(posts)
|
||
.select();
|
||
|
||
if (error) {
|
||
console.error('创建测试内容失败:', error);
|
||
process.exit(1);
|
||
}
|
||
|
||
console.log(`${data.length}篇测试内容创建成功`);
|
||
return data;
|
||
};
|
||
|
||
// 测试KOL合作转换漏斗API
|
||
const testConversionFunnelAPI = async (projectId) => {
|
||
console.log(`测试KOL合作转换漏斗API,项目ID: ${projectId}...`);
|
||
|
||
try {
|
||
const url = `http://localhost:4000/api/analytics/project/${projectId}/conversion-funnel`;
|
||
console.log(`请求URL: ${url}`);
|
||
|
||
// 使用http模块发送请求
|
||
const http = require('http');
|
||
|
||
return new Promise((resolve, reject) => {
|
||
const req = http.get(url, (res) => {
|
||
let data = '';
|
||
|
||
res.on('data', (chunk) => {
|
||
data += chunk;
|
||
});
|
||
|
||
res.on('end', () => {
|
||
if (res.statusCode !== 200) {
|
||
console.error(`API请求失败: ${res.statusCode}`);
|
||
reject(new Error(`API请求失败: ${res.statusCode}`));
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const jsonData = JSON.parse(data);
|
||
console.log('API响应:');
|
||
console.log(JSON.stringify(jsonData, null, 2));
|
||
resolve(jsonData);
|
||
} catch (error) {
|
||
console.error('解析API响应失败:', error);
|
||
reject(error);
|
||
}
|
||
});
|
||
});
|
||
|
||
req.on('error', (error) => {
|
||
console.error('请求出错:', error);
|
||
reject(error);
|
||
});
|
||
|
||
req.end();
|
||
});
|
||
} catch (error) {
|
||
console.error('测试API失败:', error);
|
||
console.log('请确保后端服务器正在运行,并且可以访问API端点');
|
||
console.log('运行命令: cd /Users/liam/code/promote/backend && npm run dev');
|
||
}
|
||
};
|
||
|
||
// 主函数
|
||
const main = async () => {
|
||
try {
|
||
// 创建测试项目
|
||
const projectId = await createTestProject();
|
||
|
||
// 创建测试KOL - 创建100个KOL以便有足够的数据来测试漏斗的各个阶段
|
||
const influencers = await createTestInfluencers(100);
|
||
|
||
// 将KOL添加到项目
|
||
await addInfluencersToProject(projectId, influencers);
|
||
|
||
// 创建测试内容
|
||
await createTestPosts(projectId, influencers);
|
||
|
||
console.log('\n测试数据生成完成!');
|
||
console.log(`项目ID: ${projectId}`);
|
||
console.log('KOL数量: 100');
|
||
console.log('内容数量: 根据KOL所处阶段不同');
|
||
console.log('\n漏斗阶段分布:');
|
||
console.log('- 认知阶段 (Awareness): 100个KOL (100%)');
|
||
console.log('- 兴趣阶段 (Interest): 75个KOL (75%)');
|
||
console.log('- 考虑阶段 (Consideration): 50个KOL (50%)');
|
||
console.log('- 意向阶段 (Intent): 30个KOL (30%)');
|
||
console.log('- 评估阶段 (Evaluation): 20个KOL (20%)');
|
||
console.log('- 购买阶段 (Purchase): 10个KOL (10%)');
|
||
|
||
console.log('\n现在您可以使用以下命令测试KOL合作转换漏斗API:');
|
||
console.log(`curl http://localhost:4000/api/analytics/project/${projectId}/conversion-funnel`);
|
||
console.log('\n或者在浏览器中访问Swagger UI:');
|
||
console.log('http://localhost:4000/swagger');
|
||
|
||
// 尝试测试API
|
||
console.log('\n尝试测试API...');
|
||
await testConversionFunnelAPI(projectId);
|
||
|
||
} catch (error) {
|
||
console.error('测试数据生成过程中出错:', error);
|
||
process.exit(1);
|
||
}
|
||
};
|
||
|
||
// 运行主函数
|
||
main();
|