/** * POST /api/contact * 联系表单提交接口(通用留言) * * 请求体: * { * name: string // 姓名(必填) * phone: string // 手机号(必填) * subject?: string // 咨询主题 * message: string // 留言内容(必填) * } */ import { checkRateLimit } from '../utils/rateLimit' import { notifyWecom } from '../utils/notify' import { useDB, schema } from '../utils/db.js' 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 formData = { name: body.name.trim(), phone: body.phone.trim(), subject: body.subject?.trim() ?? '', message: body.message.trim(), source: 'contact-form', } // ── 写入数据库 ──────────────────────────────────────── const db = useDB() const [record] = db.insert(schema.submissions) .values({ type: 'contact', data: JSON.stringify(formData), ip, }) .returning() .all() // ── 飞书通知 ────────────────────────────────────────── await notifyWecom('📩 新联系留言 - 呼籁旅行', { '编号': String(record.id), '姓名': formData.name, '手机': formData.phone, '主题': formData.subject || '(未填)', '留言': formData.message, }) return { success: true, id: record.id, message: '留言已收到,我们会尽快与您联系', } })