hulai-website/server/api/contact.post.js
刘涛 a25f3a77ce sync: 同步最新呼籁官网代码到仓库
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 21:57:35 +08:00

95 行
3.1 KiB
JavaScript

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

/**
* POST /api/contact
* 联系表单提交接口(通用留言)
*
* 请求体:
* {
* name: string // 姓名(必填)
* phone: string // 手机号(必填)
* subject?: string // 咨询主题
* message: string // 留言内容(必填)
* }
*/
import { checkRateLimit } from '../utils/rateLimit'
import { appendRecord } from '../utils/storage'
import { notifyWecom } from '../utils/notify'
const PHONE_RE = /^1[3-9]\d{9}$/
export default defineEventHandler(async (event) => {
// ── 速率限制 ──────────────────────────────────────────
const ip = getRequestIP(event, { xForwardedFor: true }) ?? 'unknown'
const { allowed, remaining, resetAt } = checkRateLimit(`contact:${ip}`)
setResponseHeader(event, 'X-RateLimit-Remaining', String(remaining))
if (!allowed) {
const waitMin = Math.ceil((resetAt - Date.now()) / 60000)
throw createError({
statusCode: 429,
message: `提交过于频繁,请 ${waitMin} 分钟后再试`,
})
}
// ── 读取请求体 ─────────────────────────────────────────
const body = await readBody(event)
// ── 字段校验 ──────────────────────────────────────────
const errors = {}
if (!body?.name?.trim()) {
errors.name = '请填写您的姓名'
}
if (!body?.phone || !PHONE_RE.test(body.phone.trim())) {
errors.phone = '请填写正确的手机号码'
}
if (!body?.message?.trim() || body.message.trim().length < 5) {
errors.message = '请填写留言内容至少5个字'
}
if (body?.message?.trim().length > 1000) {
errors.message = '留言内容不超过1000字'
}
if (Object.keys(errors).length > 0) {
throw createError({
statusCode: 422,
data: { errors },
message: '提交内容有误,请检查后重试',
})
}
// ── 构建记录 ──────────────────────────────────────────
const record = {
id: `CT${Date.now()}`,
createdAt: new Date().toISOString(),
name: body.name.trim(),
phone: body.phone.trim(),
subject: body.subject?.trim() ?? '',
message: body.message.trim(),
ip,
source: 'contact-form',
}
// ── 持久化 ────────────────────────────────────────────
await appendRecord('contact.json', record)
// ── 企业微信通知(配置 WECOM_WEBHOOK_KEY 后生效)───────
await notifyWecom('📩 新联系留言 - 呼籁旅行', {
'编号': record.id,
'姓名': record.name,
'手机': record.phone,
'咨询主题': record.subject || '(未填)',
'留言内容': record.message,
})
return {
success: true,
id: record.id,
message: '留言已收到,我们会尽快与您联系',
}
})