Files
soul-yongping/next-project/app/api/ckb/join/route.ts
2026-02-09 14:43:35 +08:00

138 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}
// 不同类型对应的source标签
const sourceMap: Record<string, string> = {
team: "团队招募",
investor: "资源对接",
mentor: "导师顾问",
partner: "创业合伙",
}
const tagsMap: Record<string, string> = {
team: "切片团队,团队招募",
investor: "资源对接,资源群",
mentor: "导师顾问,咨询服务",
partner: "创业合伙,创业伙伴",
}
export async function POST(request: NextRequest) {
try {
const body = await request.json()
const { type, phone, wechat, name, userId, remark } = body
// 验证必填参数 - 手机号或微信号至少一个
if (!phone && !wechat) {
return NextResponse.json({ success: false, message: "请提供手机号或微信号" }, { status: 400 })
}
// 验证类型
if (!["team", "investor", "mentor", "partner"].includes(type)) {
return NextResponse.json({ success: false, message: "无效的加入类型" }, { status: 400 })
}
// 生成时间戳(秒级)
const timestamp = Math.floor(Date.now() / 1000)
// 构建请求参数不包含sign
const requestParams: Record<string, any> = {
timestamp,
source: `创业实验-${sourceMap[type]}`,
tags: tagsMap[type],
siteTags: "创业实验APP",
remark: remark || `用户通过创业实验APP申请${sourceMap[type]}`,
}
// 添加可选字段
if (phone) requestParams.phone = phone
if (wechat) requestParams.wechatId = wechat
if (name) requestParams.name = name
// 生成签名
const sign = generateSign(requestParams, CKB_API_KEY)
// 构建最终请求体
const requestBody = {
...requestParams,
apiKey: CKB_API_KEY,
sign,
portrait: {
type: 4, // 互动行为
source: 0, // 本站
sourceData: {
joinType: type,
joinLabel: sourceMap[type],
userId: userId || "",
device: "webapp",
timestamp: new Date().toISOString(),
},
remark: `${sourceMap[type]}申请`,
uniqueId: `soul_${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: result.message === "已存在" ? "您已加入,我们会尽快联系您" : `成功加入${sourceMap[type]}`,
data: result.data,
})
} else {
console.error("CKB API Error:", result)
return NextResponse.json({
success: false,
message: result.message || "加入失败,请稍后重试",
})
}
} catch (error) {
console.error("存客宝API调用失败:", error)
return NextResponse.json({ success: false, message: "服务器错误,请稍后重试" }, { status: 500 })
}
}