chore: 以本地为准,上传全部并替换 GitHub

This commit is contained in:
卡若
2026-02-03 11:36:53 +08:00
parent 1219166526
commit b404bf546e
131 changed files with 37618 additions and 3930 deletions

View File

@@ -0,0 +1,286 @@
import { NextRequest, NextResponse } from 'next/server'
import { getMongoClient } from '@/lib/mongodb'
// 项目定义(基于真实数据库)
const PROJECTS = {
ckb: {
id: 'ckb',
name: '存客宝',
database: 'KR_存客宝',
collection: '用户资产统一视图',
color: 'blue',
icon: 'Users'
},
dlm: {
id: 'dlm',
name: '点了码',
database: 'KR_点了码',
collection: '用户资产统一视图',
color: 'green',
icon: 'QrCode'
},
weibo: {
id: 'weibo',
name: '微博',
database: 'KR_微博',
collection: '微博uid+手机',
color: 'orange',
icon: 'Globe'
},
qq: {
id: 'qq',
name: 'QQ社交',
database: 'KR_腾讯',
collection: 'QQ+手机',
color: 'purple',
icon: 'MessageCircle'
}
}
// 获取项目列表及统计
async function getProjectStats() {
const client = await getMongoClient()
const stats = []
for (const [key, project] of Object.entries(PROJECTS)) {
try {
const db = client.db(project.database)
const count = await db.collection(project.collection).estimatedDocumentCount()
stats.push({
...project,
userCount: count,
status: 'active'
})
} catch {
stats.push({
...project,
userCount: 0,
status: 'error'
})
}
}
return stats
}
// 获取项目下的流量池/标签分类
async function getProjectPools(projectId: string) {
const client = await getMongoClient()
const project = PROJECTS[projectId as keyof typeof PROJECTS]
if (!project) {
return { error: '项目不存在' }
}
const db = client.db(project.database)
const collection = db.collection(project.collection)
// 根据项目类型获取不同的分组字段
let pools: any[] = []
if (projectId === 'ckb') {
// 存客宝按流量池分组
const poolStats = await collection.aggregate([
{ $sample: { size: 50000 } },
{ $group: {
_id: '$traffic_pool.pool_name',
count: { $sum: 1 },
avgScore: { $avg: '$user_evaluation_score' }
}},
{ $sort: { count: -1 } }
], { maxTimeMS: 10000 }).toArray()
// 按标签分组
const tagStats = await collection.aggregate([
{ $sample: { size: 50000 } },
{ $unwind: '$unified_tags' },
{ $group: { _id: '$unified_tags', count: { $sum: 1 } }},
{ $sort: { count: -1 } },
{ $limit: 20 }
], { maxTimeMS: 10000 }).toArray()
const total = await collection.estimatedDocumentCount()
const ratio = total / 50000
pools = [
...poolStats.filter(p => p._id).map(p => ({
id: `pool_${p._id}`,
name: p._id,
type: 'pool',
count: Math.round(p.count * ratio),
avgScore: Math.round(p.avgScore || 0)
})),
...tagStats.filter(t => t._id).map(t => ({
id: `tag_${t._id}`,
name: t._id,
type: 'tag',
count: Math.round(t.count * ratio)
}))
]
} else if (projectId === 'dlm') {
// 点了码按角色标签分组
const roleStats = await collection.aggregate([
{ $unwind: { path: '$角色标签', preserveNullAndEmptyArrays: true } },
{ $group: { _id: '$角色标签', count: { $sum: 1 } }},
{ $sort: { count: -1 } }
], { maxTimeMS: 10000 }).toArray()
// 按用户等级分组
const levelStats = await collection.aggregate([
{ $group: { _id: '$用户等级', count: { $sum: 1 } }},
{ $sort: { count: -1 } }
], { maxTimeMS: 10000 }).toArray()
pools = [
...roleStats.filter(r => r._id).map(r => ({
id: `role_${r._id}`,
name: r._id,
type: 'role',
count: r.count
})),
...levelStats.filter(l => l._id).map(l => ({
id: `level_${l._id}`,
name: `${l._id}级用户`,
type: 'level',
count: l.count
}))
]
} else if (projectId === 'qq') {
// QQ按省份分组
const provinceStats = await collection.aggregate([
{ $sample: { size: 100000 } },
{ $match: { '省份': { $exists: true, $ne: null } } },
{ $group: { _id: '$省份', count: { $sum: 1 } }},
{ $sort: { count: -1 } },
{ $limit: 20 }
], { maxTimeMS: 10000 }).toArray()
const total = await collection.estimatedDocumentCount()
const ratio = total / 100000
pools = provinceStats.map(p => ({
id: `province_${p._id}`,
name: p._id,
type: 'province',
count: Math.round(p.count * ratio)
}))
} else if (projectId === 'weibo') {
// 微博简单统计
const total = await collection.estimatedDocumentCount()
pools = [{
id: 'weibo_all',
name: '微博用户',
type: 'all',
count: total
}]
}
return {
project,
pools,
totalPools: pools.length
}
}
// 获取流量池内的用户列表
async function getPoolUsers(projectId: string, poolId: string, page: number = 1, limit: number = 20) {
const client = await getMongoClient()
const project = PROJECTS[projectId as keyof typeof PROJECTS]
if (!project) {
return { error: '项目不存在' }
}
const db = client.db(project.database)
const collection = db.collection(project.collection)
// 解析poolId构建查询条件
let query: any = {}
const [type, ...nameParts] = poolId.split('_')
const name = nameParts.join('_')
console.log('Pool query:', { type, name, projectId, poolId })
if (type === 'pool') {
query['traffic_pool.pool_name'] = name
} else if (type === 'tag') {
query['unified_tags'] = name
} else if (type === 'role') {
query['角色标签'] = name
} else if (type === 'level') {
query['用户等级'] = name.replace('级用户', '')
} else if (type === 'province') {
query['省份'] = name
}
// 如果没有匹配条件尝试直接用name搜索
if (Object.keys(query).length === 0 || type === 'all') {
query = {}
}
const skip = (page - 1) * limit
const [users, total] = await Promise.all([
collection.find(query)
.project({
phone_masked: 1,
name: 1,
'core_profile.name': 1,
user_evaluation_score: 1,
unified_tags: 1,
'角色标签': 1,
'用户等级': 1,
'rfm_scores.user_level': 1,
created_at: 1
})
.skip(skip)
.limit(limit)
.toArray(),
collection.countDocuments(query)
])
return {
users: users.map(u => ({
id: u._id.toString(),
phone: u.phone_masked || '未知',
name: u.name || u.core_profile?.name || '未知用户',
score: u.user_evaluation_score || 0,
level: u.rfm_scores?.user_level || u['用户等级'] || '-',
tags: u.unified_tags || u['角色标签'] || [],
createdAt: u.created_at
})),
total,
page,
totalPages: Math.ceil(total / limit)
}
}
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url)
const action = searchParams.get('action') || 'projects'
const projectId = searchParams.get('projectId')
const poolId = searchParams.get('poolId')
const page = parseInt(searchParams.get('page') || '1')
try {
if (action === 'projects') {
const stats = await getProjectStats()
return NextResponse.json({ success: true, projects: stats })
}
if (action === 'pools' && projectId) {
const pools = await getProjectPools(projectId)
return NextResponse.json({ success: true, ...pools })
}
if (action === 'users' && projectId && poolId) {
const users = await getPoolUsers(projectId, poolId, page)
return NextResponse.json({ success: true, ...users })
}
return NextResponse.json({ error: '无效的操作' }, { status: 400 })
} catch (error) {
console.error('流量池API错误:', error)
return NextResponse.json({ error: '查询失败' }, { status: 500 })
}
}