chore: 以本地为准,强制同步全部内容
This commit is contained in:
@@ -1,52 +1,177 @@
|
||||
import { type NextRequest, NextResponse } from "next/server"
|
||||
import { getIntelligentSearchService } from "@/services/intelligent-search-service"
|
||||
/**
|
||||
* 智能搜索 API 路由
|
||||
* 对接神射手 MongoDB - 跨库查询
|
||||
*/
|
||||
|
||||
import { type NextRequest, NextResponse } from "next/server"
|
||||
import {
|
||||
intelligentSearch,
|
||||
queryFullProfile,
|
||||
queryPhoneByQQ,
|
||||
UserValuationDoc
|
||||
} from "@/lib/mongodb"
|
||||
|
||||
/**
|
||||
* 脱敏手机号
|
||||
*/
|
||||
function maskPhone(phone: string | undefined): string {
|
||||
if (!phone) return ''
|
||||
if (phone.length !== 11) return phone
|
||||
return `${phone.slice(0, 3)}****${phone.slice(-4)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换搜索结果
|
||||
*/
|
||||
function transformSearchResult(doc: UserValuationDoc, queryType: string): any {
|
||||
const name = doc.name || '未知用户'
|
||||
return {
|
||||
id: doc._id?.toString(),
|
||||
type: 'user',
|
||||
title: name,
|
||||
subtitle: doc.phone_masked || maskPhone(doc.phone),
|
||||
description: `${doc.province || ''}${doc.city || ''} | ${doc.user_level || '未分级'} | RFM: ${doc.rfm_composite_score?.toFixed(2) || 'N/A'}`,
|
||||
data: {
|
||||
phone: doc.phone,
|
||||
phone_masked: doc.phone_masked || maskPhone(doc.phone),
|
||||
name: doc.name,
|
||||
province: doc.province,
|
||||
city: doc.city,
|
||||
userLevel: doc.user_level,
|
||||
rfmScore: doc.rfm_composite_score,
|
||||
tags: doc.tags || [],
|
||||
email: doc.email
|
||||
},
|
||||
matchedBy: queryType,
|
||||
relevanceScore: doc.rfm_composite_score || 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/search
|
||||
* 智能搜索
|
||||
*/
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url)
|
||||
const query = searchParams.get("q") || ""
|
||||
const type = (searchParams.get("type") as "user" | "traffic" | "all") || "all"
|
||||
const limit = Number.parseInt(searchParams.get("limit") || "50")
|
||||
const offset = Number.parseInt(searchParams.get("offset") || "0")
|
||||
const useAI = searchParams.get("ai") === "true"
|
||||
const includeInsights = searchParams.get("insights") === "true"
|
||||
|
||||
if (!query.trim()) {
|
||||
return NextResponse.json({ error: "搜索查询不能为空" }, { status: 400 })
|
||||
return NextResponse.json({
|
||||
error: "搜索查询不能为空"
|
||||
}, { status: 400 })
|
||||
}
|
||||
|
||||
const searchService = getIntelligentSearchService()
|
||||
// 执行智能搜索
|
||||
const result = await intelligentSearch(query, { limit, offset })
|
||||
|
||||
// 转换结果
|
||||
const items = result.users.map(doc => transformSearchResult(doc, result.queryType))
|
||||
|
||||
// 如果是 QQ 查询,补充 QQ 信息
|
||||
if (result.queryType === 'qq' && result.users.length > 0) {
|
||||
const qqInfo = await queryPhoneByQQ(query.trim())
|
||||
if (qqInfo) {
|
||||
items[0].data.qq = qqInfo.qq
|
||||
items[0].data.qqScore = qqInfo.QQ号评分
|
||||
items[0].data.carrier = qqInfo.运营商
|
||||
}
|
||||
}
|
||||
|
||||
const results = await searchService.search(query, type, {
|
||||
limit,
|
||||
offset,
|
||||
useAI,
|
||||
includeInsights,
|
||||
filters: {},
|
||||
return NextResponse.json({
|
||||
query,
|
||||
queryType: result.queryType,
|
||||
total: result.total,
|
||||
items,
|
||||
pagination: {
|
||||
limit,
|
||||
offset,
|
||||
hasMore: offset + items.length < result.total
|
||||
}
|
||||
})
|
||||
|
||||
return NextResponse.json(results)
|
||||
|
||||
} catch (error) {
|
||||
console.error("搜索API错误:", error)
|
||||
return NextResponse.json({ error: "搜索失败,请稍后重试" }, { status: 500 })
|
||||
return NextResponse.json({
|
||||
error: "搜索失败,请稍后重试",
|
||||
details: error instanceof Error ? error.message : 'Unknown error'
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/search
|
||||
* 高级搜索(支持更多参数)
|
||||
* 返回格式适配前端 SearchResponse 接口
|
||||
*/
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const startTime = Date.now()
|
||||
const body = await request.json()
|
||||
const { query, type = "all", options = {} } = body
|
||||
|
||||
if (!query || !query.trim()) {
|
||||
return NextResponse.json({ error: "搜索查询不能为空" }, { status: 400 })
|
||||
return NextResponse.json({
|
||||
error: "搜索查询不能为空"
|
||||
}, { status: 400 })
|
||||
}
|
||||
|
||||
const searchService = getIntelligentSearchService()
|
||||
const results = await searchService.search(query, type, options)
|
||||
const limit = options.limit || 50
|
||||
const offset = options.offset || 0
|
||||
|
||||
const result = await intelligentSearch(query, { limit, offset })
|
||||
|
||||
// 转换为前端期望的格式
|
||||
const results = result.users.map(doc => {
|
||||
const name = doc.name || '未知用户'
|
||||
return {
|
||||
id: doc._id?.toString() || '',
|
||||
type: 'user' as const,
|
||||
title: name,
|
||||
description: `${doc.province || ''}${doc.city || ''} | 估值: ${doc.user_evaluation_score || 'N/A'}`,
|
||||
tags: doc.tags || [],
|
||||
relevanceScore: doc.user_evaluation_score || 0,
|
||||
updatedAt: doc.computed_at?.toISOString() || new Date().toISOString(),
|
||||
metadata: {
|
||||
phone: doc.phone,
|
||||
phone_masked: doc.phone_masked || maskPhone(doc.phone),
|
||||
province: doc.province,
|
||||
city: doc.city,
|
||||
gender: doc.gender,
|
||||
age_range: doc.age_range,
|
||||
userLevel: doc.user_level,
|
||||
rfmScore: doc.rfm_composite_score,
|
||||
evaluationScore: doc.user_evaluation_score,
|
||||
dataQuality: doc.data_quality
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return NextResponse.json(results)
|
||||
const queryTime = Date.now() - startTime
|
||||
|
||||
// 返回前端期望的 SearchResponse 格式
|
||||
return NextResponse.json({
|
||||
results,
|
||||
stats: {
|
||||
totalResults: result.total,
|
||||
queryTime,
|
||||
suggestions: [],
|
||||
filters: {
|
||||
queryType: result.queryType
|
||||
}
|
||||
},
|
||||
hasMore: offset + results.length < result.total
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error("搜索API错误:", error)
|
||||
return NextResponse.json({ error: "搜索失败,请稍后重试" }, { status: 500 })
|
||||
return NextResponse.json({
|
||||
error: "搜索失败,请稍后重试",
|
||||
results: [],
|
||||
stats: { totalResults: 0, queryTime: 0, suggestions: [], filters: {} },
|
||||
hasMore: false
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user