132 lines
4.0 KiB
TypeScript
132 lines
4.0 KiB
TypeScript
|
|
import { type NextRequest, NextResponse } from "next/server"
|
|||
|
|
import crypto from "crypto"
|
|||
|
|
|
|||
|
|
// 存客宝API配置
|
|||
|
|
const CKB_API_KEY = process.env.CKB_API_KEY || "fyngh-ecy9h-qkdae-epwd5-rz6kd"
|
|||
|
|
const CKB_API_URL = "https://ckbapi.quwanzhi.com/v1/api/scenarios"
|
|||
|
|
|
|||
|
|
// 生成签名 - 根据文档实现
|
|||
|
|
function generateSign(params: Record<string, any>, apiKey: string): string {
|
|||
|
|
// 1. 移除 sign、apiKey、portrait 字段
|
|||
|
|
const filteredParams = { ...params }
|
|||
|
|
delete filteredParams.sign
|
|||
|
|
delete filteredParams.apiKey
|
|||
|
|
delete filteredParams.portrait
|
|||
|
|
|
|||
|
|
// 2. 移除空值字段
|
|||
|
|
const nonEmptyParams: Record<string, any> = {}
|
|||
|
|
for (const [key, value] of Object.entries(filteredParams)) {
|
|||
|
|
if (value !== null && value !== "") {
|
|||
|
|
nonEmptyParams[key] = value
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 按参数名升序排序
|
|||
|
|
const sortedKeys = Object.keys(nonEmptyParams).sort()
|
|||
|
|
|
|||
|
|
// 4. 拼接参数值
|
|||
|
|
const stringToSign = sortedKeys.map(key => nonEmptyParams[key]).join("")
|
|||
|
|
|
|||
|
|
// 5. 第一次 MD5
|
|||
|
|
const firstMd5 = crypto.createHash("md5").update(stringToSign).digest("hex")
|
|||
|
|
|
|||
|
|
// 6. 拼接 apiKey 再次 MD5
|
|||
|
|
const sign = crypto.createHash("md5").update(firstMd5 + apiKey).digest("hex")
|
|||
|
|
|
|||
|
|
return sign
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 匹配类型映射
|
|||
|
|
const matchTypeMap: Record<string, string> = {
|
|||
|
|
partner: "创业合伙",
|
|||
|
|
investor: "资源对接",
|
|||
|
|
mentor: "导师顾问",
|
|||
|
|
team: "团队招募",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export async function POST(request: NextRequest) {
|
|||
|
|
try {
|
|||
|
|
const body = await request.json()
|
|||
|
|
const { matchType, phone, wechat, userId, nickname, matchedUser } = body
|
|||
|
|
|
|||
|
|
// 验证必填参数 - 手机号或微信号至少一个
|
|||
|
|
if (!phone && !wechat) {
|
|||
|
|
return NextResponse.json({ success: false, message: "请提供手机号或微信号" }, { status: 400 })
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 生成时间戳(秒级)
|
|||
|
|
const timestamp = Math.floor(Date.now() / 1000)
|
|||
|
|
|
|||
|
|
// 构建请求参数(不包含sign)
|
|||
|
|
const requestParams: Record<string, any> = {
|
|||
|
|
timestamp,
|
|||
|
|
source: `创业实验-找伙伴匹配`,
|
|||
|
|
tags: `找伙伴,${matchTypeMap[matchType] || "创业合伙"}`,
|
|||
|
|
siteTags: "创业实验APP,匹配用户",
|
|||
|
|
remark: `用户发起${matchTypeMap[matchType] || "创业合伙"}匹配`,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 添加联系方式
|
|||
|
|
if (phone) requestParams.phone = phone
|
|||
|
|
if (wechat) requestParams.wechatId = wechat
|
|||
|
|
if (nickname) requestParams.name = nickname
|
|||
|
|
|
|||
|
|
// 生成签名
|
|||
|
|
const sign = generateSign(requestParams, CKB_API_KEY)
|
|||
|
|
|
|||
|
|
// 构建最终请求体
|
|||
|
|
const requestBody = {
|
|||
|
|
...requestParams,
|
|||
|
|
apiKey: CKB_API_KEY,
|
|||
|
|
sign,
|
|||
|
|
portrait: {
|
|||
|
|
type: 4, // 互动行为
|
|||
|
|
source: 0, // 本站
|
|||
|
|
sourceData: {
|
|||
|
|
action: "match",
|
|||
|
|
matchType: matchType,
|
|||
|
|
matchLabel: matchTypeMap[matchType] || "创业合伙",
|
|||
|
|
userId: userId || "",
|
|||
|
|
matchedUserId: matchedUser?.id || "",
|
|||
|
|
matchedUserNickname: matchedUser?.nickname || "",
|
|||
|
|
matchScore: matchedUser?.matchScore || 0,
|
|||
|
|
device: "webapp",
|
|||
|
|
timestamp: new Date().toISOString(),
|
|||
|
|
},
|
|||
|
|
remark: `找伙伴匹配-${matchTypeMap[matchType] || "创业合伙"}`,
|
|||
|
|
uniqueId: `soul_match_${phone || wechat}_${timestamp}`,
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 调用存客宝API
|
|||
|
|
const response = await fetch(CKB_API_URL, {
|
|||
|
|
method: "POST",
|
|||
|
|
headers: {
|
|||
|
|
"Content-Type": "application/json",
|
|||
|
|
},
|
|||
|
|
body: JSON.stringify(requestBody),
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
const result = await response.json()
|
|||
|
|
|
|||
|
|
if (result.code === 200) {
|
|||
|
|
return NextResponse.json({
|
|||
|
|
success: true,
|
|||
|
|
message: "匹配记录已上报",
|
|||
|
|
data: result.data,
|
|||
|
|
})
|
|||
|
|
} else {
|
|||
|
|
console.error("CKB Match API Error:", result)
|
|||
|
|
// 即使上报失败也返回成功,不影响用户体验
|
|||
|
|
return NextResponse.json({
|
|||
|
|
success: true,
|
|||
|
|
message: "匹配成功",
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error("存客宝匹配API调用失败:", error)
|
|||
|
|
// 即使出错也返回成功,不影响用户体验
|
|||
|
|
return NextResponse.json({ success: true, message: "匹配成功" })
|
|||
|
|
}
|
|||
|
|
}
|