/** * POST /api/customize * 定制表单提交接口 * * 请求体: * { * name: string // 姓名(必填) * phone: string // 手机号(必填) * wechat?: string // 微信号(选填) * adults: number // 成人数(必填) * children: number // 儿童数 * childAges: number[] // 儿童年龄列表 * date?: string // 出行日期 YYYY-MM-DD * duration?: string // 出行天数 * activities: string[]// 特殊需求标签 * budget?: string // 预算范围 * remarks?: string // 补充说明 * } */ import { checkRateLimit } from '../utils/rateLimit' import { notifyWecom } from '../utils/notify' import { notifyEmail } from '../utils/email' 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(`customize:${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 = '请填写正确的手机号码(11位大陆手机号)' } if (!Number.isInteger(body?.adults) || body.adults < 1 || body.adults > 20) { errors.adults = '成人人数不合法' } if (Object.keys(errors).length > 0) { throw createError({ statusCode: 422, data: { errors }, message: '提交内容有误,请检查后重试', }) } // ── 构建表单数据 ──────────────────────────────────────── const formData = { name: body.name.trim(), phone: body.phone.trim(), wechat: body.wechat?.trim() ?? '', adults: body.adults, children: body.children ?? 0, childAges: Array.isArray(body.childAges) ? body.childAges : [], date: body.date ?? '', duration: body.duration ?? '', activities: Array.isArray(body.activities) ? body.activities : [], budget: body.budget ?? '', remarks: body.remarks?.trim() ?? '', source: 'customize-form', } // ── 写入数据库 ──────────────────────────────────────── const db = useDB() const [record] = db.insert(schema.submissions) .values({ type: 'customize', data: JSON.stringify(formData), ip, }) .returning() .all() // ── 通知(配置后生效)──────────────────────────────── const notifyFields = { '编号': String(record.id), '姓名': formData.name, '手机': formData.phone, '微信': formData.wechat || '(同手机号)', '出行人数': `成人 ${formData.adults} 人${formData.children > 0 ? `、儿童 ${formData.children} 人(${formData.childAges.join('、')}岁)` : ''}`, '出行日期': formData.date || '未填写', '天数': formData.duration || '未选择', '特殊需求': formData.activities.length ? formData.activities.join('、') : '无', '预算': formData.budget || '未选择', '补充说明': formData.remarks || '无', } await Promise.all([ notifyWecom('🌿 新定制需求 - 呼籁旅行', notifyFields), notifyEmail('🌿 新定制需求 - 呼籁旅行', notifyFields), ]) // ── 返回 ────────────────────────────────────────────── return { success: true, id: record.id, message: '需求已收到,定制师将在2小时内联系您', } })