Ensure compatibility with both default and named exports for useDebounce. Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
231 lines
6.5 KiB
TypeScript
231 lines
6.5 KiB
TypeScript
import { NextResponse, NextRequest } from "next/server"
|
||
import type { TrafficUser } from "@/types/traffic"
|
||
import { addUser, filterUsers, getDistinctTags, getUserById, queryUsers, type UserStatus } from "@/lib/mock-users"
|
||
|
||
// 中文名字生成器数据
|
||
const familyNames = [
|
||
"张",
|
||
"王",
|
||
"李",
|
||
"赵",
|
||
"陈",
|
||
"刘",
|
||
"杨",
|
||
"黄",
|
||
"周",
|
||
"吴",
|
||
"朱",
|
||
"孙",
|
||
"马",
|
||
"胡",
|
||
"郭",
|
||
"林",
|
||
"何",
|
||
"高",
|
||
"梁",
|
||
"郑",
|
||
"罗",
|
||
"宋",
|
||
"谢",
|
||
"唐",
|
||
"韩",
|
||
"曹",
|
||
"许",
|
||
"邓",
|
||
"萧",
|
||
"冯",
|
||
]
|
||
const givenNames1 = [
|
||
"志",
|
||
"建",
|
||
"文",
|
||
"明",
|
||
"永",
|
||
"春",
|
||
"秀",
|
||
"金",
|
||
"水",
|
||
"玉",
|
||
"国",
|
||
"立",
|
||
"德",
|
||
"海",
|
||
"和",
|
||
"荣",
|
||
"伟",
|
||
"新",
|
||
"英",
|
||
"佳",
|
||
]
|
||
const givenNames2 = [
|
||
"华",
|
||
"平",
|
||
"军",
|
||
"强",
|
||
"辉",
|
||
"敏",
|
||
"峰",
|
||
"磊",
|
||
"超",
|
||
"艳",
|
||
"娜",
|
||
"霞",
|
||
"燕",
|
||
"娟",
|
||
"静",
|
||
"丽",
|
||
"涛",
|
||
"洋",
|
||
"勇",
|
||
"龙",
|
||
]
|
||
|
||
// 生成固定的用户数据池
|
||
const userPool: TrafficUser[] = Array.from({ length: 1610 }, (_, i) => {
|
||
const familyName = familyNames[Math.floor(Math.random() * familyNames.length)]
|
||
const givenName1 = givenNames1[Math.floor(Math.random() * givenNames1.length)]
|
||
const givenName2 = givenNames2[Math.floor(Math.random() * givenNames2.length)]
|
||
const fullName = Math.random() > 0.5 ? familyName + givenName1 + givenName2 : familyName + givenName1
|
||
|
||
// 生成随机时间(在过去7天内)
|
||
const date = new Date()
|
||
date.setDate(date.getDate() - Math.floor(Math.random() * 7))
|
||
|
||
return {
|
||
id: `${Date.now()}-${i}`,
|
||
avatar: `/placeholder.svg?height=40&width=40&text=${fullName[0]}`,
|
||
nickname: fullName,
|
||
wechatId: `wxid_${Math.random().toString(36).substr(2, 8)}`,
|
||
phone: `1${["3", "5", "7", "8", "9"][Math.floor(Math.random() * 5)]}${Array.from({ length: 9 }, () => Math.floor(Math.random() * 10)).join("")}`,
|
||
region: [
|
||
"广东深圳",
|
||
"浙江杭州",
|
||
"江苏苏州",
|
||
"北京",
|
||
"上海",
|
||
"四川成都",
|
||
"湖北武汉",
|
||
"福建厦门",
|
||
"山东青岛",
|
||
"河南郑州",
|
||
][Math.floor(Math.random() * 10)],
|
||
note: [
|
||
"咨询产品价格",
|
||
"对产品很感兴趣",
|
||
"准备购买",
|
||
"需要更多信息",
|
||
"想了解优惠活动",
|
||
"询问产品规格",
|
||
"要求产品demo",
|
||
"索要产品目录",
|
||
"询问售后服务",
|
||
"要求上门演示",
|
||
][Math.floor(Math.random() * 10)],
|
||
status: ["pending", "added", "failed"][Math.floor(Math.random() * 3)] as TrafficUser["status"],
|
||
addTime: date.toISOString(),
|
||
source: ["抖音直播", "小红书", "微信朋友圈", "视频号", "公众号", "个人主页"][Math.floor(Math.random() * 6)],
|
||
assignedTo: "",
|
||
category: ["potential", "customer", "lost"][Math.floor(Math.random() * 3)] as TrafficUser["category"],
|
||
tags: [],
|
||
}
|
||
})
|
||
|
||
// 计算今日新增数量
|
||
const todayStart = new Date()
|
||
todayStart.setHours(0, 0, 0, 0)
|
||
const todayUsers = userPool.filter((user) => new Date(user.addTime) >= todayStart)
|
||
|
||
// 生成微信好友数据池
|
||
const generateWechatFriends = (wechatId: string, count: number) => {
|
||
return Array.from({ length: count }, (_, i) => {
|
||
const familyName = familyNames[Math.floor(Math.random() * familyNames.length)]
|
||
const givenName1 = givenNames1[Math.floor(Math.random() * givenNames1.length)]
|
||
const givenName2 = givenNames2[Math.floor(Math.random() * givenNames2.length)]
|
||
const fullName = Math.random() > 0.5 ? familyName + givenName1 + givenName2 : familyName + givenName1
|
||
|
||
// 生成随机时间(在过去30天内)
|
||
const date = new Date()
|
||
date.setDate(date.getDate() - Math.floor(Math.random() * 30))
|
||
|
||
return {
|
||
id: `wechat-${wechatId}-${i}`,
|
||
avatar: `/placeholder.svg?height=40&width=40&text=${fullName[0]}`,
|
||
nickname: fullName,
|
||
wechatId: `wxid_${Math.random().toString(36).substr(2, 8)}`,
|
||
phone: `1${["3", "5", "7", "8", "9"][Math.floor(Math.random() * 5)]}${Array.from({ length: 9 }, () => Math.floor(Math.random() * 10)).join("")}`,
|
||
region: [
|
||
"广东深圳",
|
||
"浙江杭州",
|
||
"江苏苏州",
|
||
"北京",
|
||
"上海",
|
||
"四川成都",
|
||
"湖北武汉",
|
||
"福建厦门",
|
||
"山东青岛",
|
||
"河南郑州",
|
||
][Math.floor(Math.random() * 10)],
|
||
note: [
|
||
"咨询产品价格",
|
||
"对产品很感兴趣",
|
||
"准备购买",
|
||
"需要更多信息",
|
||
"想了解优惠活动",
|
||
"询问产品规格",
|
||
"要求产品demo",
|
||
"索要产品目录",
|
||
"询问售后服务",
|
||
"要求上门演示",
|
||
][Math.floor(Math.random() * 10)],
|
||
status: ["pending", "added", "failed"][Math.floor(Math.random() * 3)] as TrafficUser["status"],
|
||
addTime: date.toISOString(),
|
||
source: ["抖音直播", "小红书", "微信朋友圈", "视频号", "公众号", "个人主页", "微信好友"][
|
||
Math.floor(Math.random() * 7)
|
||
],
|
||
assignedTo: "",
|
||
category: ["potential", "customer", "lost"][Math.floor(Math.random() * 3)] as TrafficUser["category"],
|
||
tags: [],
|
||
}
|
||
})
|
||
}
|
||
|
||
// 微信好友数据缓存
|
||
const wechatFriendsCache = new Map<string, TrafficUser[]>()
|
||
|
||
function parseArrayParam(v: string | null) {
|
||
if (!v) return []
|
||
return v.split(",").map((s) => s.trim()).filter(Boolean)
|
||
}
|
||
|
||
export async function GET(req: NextRequest) {
|
||
const { searchParams } = new URL(req.url)
|
||
|
||
// 详情优先
|
||
const id = searchParams.get('id')
|
||
if (id) {
|
||
const detail = getUserById(id)
|
||
return NextResponse.json({ data: detail }, { headers: { 'Cache-Control': 'no-store' } })
|
||
}
|
||
|
||
// 列表
|
||
const q = searchParams.get('q') ?? undefined
|
||
const tagsStr = searchParams.get('tags') ?? ''
|
||
const statusStr = searchParams.get('status') ?? ''
|
||
const rfmMin = Number(searchParams.get('rfmMin') ?? 0)
|
||
const rfmMax = Number(searchParams.get('rfmMax') ?? 100)
|
||
const page = Number(searchParams.get('page') ?? 1)
|
||
const pageSize = Number(searchParams.get('pageSize') ?? 20)
|
||
|
||
const tags = tagsStr ? tagsStr.split(',').filter(Boolean) : undefined
|
||
const status = statusStr ? (statusStr.split(',').filter(Boolean) as any) : undefined
|
||
|
||
const result = queryUsers({ q, tags, status, rfmMin, rfmMax, page, pageSize })
|
||
return NextResponse.json(result, { headers: { 'Cache-Control': 'no-store' } })
|
||
}
|
||
|
||
export async function POST(req: NextRequest) {
|
||
const body = await req.json().catch(() => ({}))
|
||
const created = addUser(body ?? {})
|
||
return NextResponse.json({ data: created }, { status: 201 })
|
||
}
|