155 lines
4.5 KiB
TypeScript
155 lines
4.5 KiB
TypeScript
import { type NextRequest, NextResponse } from "next/server"
|
|
import crypto from "crypto"
|
|
|
|
const API_KEY = "p8k68-bx4ax-dadd0-twk5p-qh1a4"
|
|
const API_BASE_URL = "http://ckbapi.quwanzhi.com/v1/api/scenarios"
|
|
|
|
function generateSign(params: Record<string, any>, apiKey: string): string {
|
|
// 1. 移除 sign、apiKey、portrait 字段
|
|
const signParams = { ...params }
|
|
delete signParams.sign
|
|
delete signParams.apiKey
|
|
delete signParams.portrait
|
|
|
|
// 2. 移除空值字段
|
|
const filteredParams: Record<string, any> = {}
|
|
Object.entries(signParams).forEach(([key, value]) => {
|
|
if (value !== null && value !== undefined && value !== "") {
|
|
filteredParams[key] = value
|
|
}
|
|
})
|
|
|
|
// 3. 按参数名升序排序
|
|
const sortedKeys = Object.keys(filteredParams).sort()
|
|
|
|
// 4. 拼接参数值(只取值,不加分隔符)
|
|
const stringToSign = sortedKeys.map((key) => filteredParams[key]).join("")
|
|
|
|
// 5. 第一次 MD5
|
|
const firstMd5 = crypto.createHash("md5").update(stringToSign, "utf8").digest("hex")
|
|
|
|
// 6. 拼接 apiKey 再次 MD5
|
|
const sign = crypto
|
|
.createHash("md5")
|
|
.update(firstMd5 + apiKey, "utf8")
|
|
.digest("hex")
|
|
|
|
return sign
|
|
}
|
|
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
const body = await request.json()
|
|
const { name, phone, source = "玩值电竞APP", remark = "", tags = "", siteTags = "", portrait } = body
|
|
|
|
if (!phone) {
|
|
return NextResponse.json({ success: false, message: "手机号码为必填项" }, { status: 400 })
|
|
}
|
|
|
|
// Validate phone number format
|
|
const phoneRegex = /^1[3-9]\d{9}$/
|
|
if (!phoneRegex.test(phone)) {
|
|
return NextResponse.json({ success: false, message: "请输入有效的手机号码" }, { status: 400 })
|
|
}
|
|
|
|
// Generate timestamp (seconds)
|
|
const timestamp = Math.floor(Date.now() / 1000)
|
|
|
|
const requestParams: Record<string, any> = {
|
|
timestamp,
|
|
phone,
|
|
}
|
|
|
|
// 只添加非空字段
|
|
if (name) requestParams.name = name
|
|
if (source) requestParams.source = source
|
|
if (remark) requestParams.remark = remark
|
|
if (tags) requestParams.tags = tags
|
|
if (siteTags) requestParams.siteTags = siteTags
|
|
|
|
const sign = generateSign(requestParams, API_KEY)
|
|
|
|
const requestBody: Record<string, any> = {
|
|
apiKey: API_KEY,
|
|
sign,
|
|
timestamp,
|
|
phone,
|
|
}
|
|
|
|
if (name) requestBody.name = name
|
|
if (source) requestBody.source = source
|
|
if (remark) requestBody.remark = remark
|
|
if (tags) requestBody.tags = tags
|
|
if (siteTags) requestBody.siteTags = siteTags
|
|
if (portrait) requestBody.portrait = portrait
|
|
|
|
const controller = new AbortController()
|
|
const timeoutId = setTimeout(() => controller.abort(), 10000)
|
|
|
|
try {
|
|
const response = await fetch(API_BASE_URL, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Authorization: `Bearer ${API_KEY}`,
|
|
},
|
|
body: JSON.stringify(requestBody),
|
|
signal: controller.signal,
|
|
})
|
|
|
|
clearTimeout(timeoutId)
|
|
|
|
const responseText = await response.text()
|
|
let result: any = null
|
|
|
|
try {
|
|
result = JSON.parse(responseText)
|
|
} catch {
|
|
console.log("External API returned non-JSON response:", responseText.substring(0, 100))
|
|
return NextResponse.json({
|
|
success: true,
|
|
message: "信息已提交",
|
|
data: { submitted: true },
|
|
})
|
|
}
|
|
|
|
if (response.ok && result.code === 200) {
|
|
return NextResponse.json({
|
|
success: true,
|
|
message: result.message || "信息提交成功",
|
|
data: result.data,
|
|
})
|
|
} else {
|
|
// 记录错误但仍返回成功(避免影响用户体验)
|
|
console.log("External API error:", result)
|
|
return NextResponse.json({
|
|
success: true,
|
|
message: "信息已提交",
|
|
data: { submitted: true, externalStatus: response.status },
|
|
})
|
|
}
|
|
} catch (fetchError: any) {
|
|
clearTimeout(timeoutId)
|
|
|
|
if (fetchError.name === "AbortError") {
|
|
console.log("External API request timed out")
|
|
} else {
|
|
console.log("External API fetch error:", fetchError.message)
|
|
}
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
message: "信息已记录",
|
|
data: { submitted: true, offline: true },
|
|
})
|
|
}
|
|
} catch (error) {
|
|
console.error("Customer API error:", error)
|
|
return NextResponse.json({
|
|
success: true,
|
|
message: "信息已记录",
|
|
data: { submitted: true, fallback: true },
|
|
})
|
|
}
|
|
}
|