const express = require('express'); const router = express.Router(); const { Contact } = require('../models'); const { sendContactNotification, sendAutoReply } = require('../utils/emailService'); const { successResponse, errorResponse } = require('../utils/responese'); /** * @api {post} /contact 提交联系我们表单 * @apiName CreateContact * @apiGroup Contact * * @apiParam {String} name 联系人姓名(必填) * @apiParam {String} email 联系人邮箱(必填) * @apiParam {String} [phone] 联系电话 * @apiParam {String} [company] 公司名称 * @apiParam {String} subject 留言主题(必填) * @apiParam {String} message 留言内容(必填) * * @apiSuccess {Boolean} status 请求状态 * @apiSuccess {String} message 响应消息 * @apiSuccess {Object} data 创建的联系信息 * * @apiSuccessExample {json} Success-Response: * HTTP/1.1 201 Created * { * "status": true, * "message": "留言提交成功,我们会尽快回复您", * "data": { * "id": 1, * "message": "感谢您的留言,我们已收到并会在24小时内回复" * } * } */ router.post('/', async (req, res) => { try { const { name, email, phone, company, subject, message } = req.body; // 参数验证 const errors = []; if (!name || name.trim().length === 0) { errors.push('联系人姓名不能为空'); } if (!email || email.trim().length === 0) { errors.push('联系人邮箱不能为空'); } if (!subject || subject.trim().length === 0) { errors.push('留言主题不能为空'); } if (!message || message.trim().length === 0) { errors.push('留言内容不能为空'); } // 邮箱格式验证 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (email && !emailRegex.test(email)) { errors.push('邮箱格式不正确'); } // 字符长度验证 if (name && name.trim().length > 100) { errors.push('联系人姓名不能超过100个字符'); } if (subject && subject.trim().length > 200) { errors.push('留言主题不能超过200个字符'); } if (company && company.trim().length > 200) { errors.push('公司名称不能超过200个字符'); } if (phone && phone.trim().length > 20) { errors.push('联系电话不能超过20个字符'); } if (errors.length > 0) { return res.status(400).json(errorResponse('参数验证失败', errors)); } // 保存到数据库 const contactData = await Contact.create({ name: name.trim(), email: email.trim().toLowerCase(), phone: phone ? phone.trim() : null, company: company ? company.trim() : null, subject: subject.trim(), message: message.trim() }); // 异步发送邮件(不阻塞响应) setImmediate(async () => { try { // 发送通知邮件给管理员 const notificationSent = await sendContactNotification(contactData.toJSON()); // 发送自动回复给客户 const autoReplySent = await sendAutoReply(contactData.toJSON()); // 更新邮件发送状态 if (notificationSent || autoReplySent) { await contactData.update({ isEmailSent: true }); } console.log(`联系表单处理完成 - ID: ${contactData.id}, 通知邮件: ${notificationSent ? '成功' : '失败'}, 自动回复: ${autoReplySent ? '成功' : '失败'}`); } catch (emailError) { console.error('邮件发送过程出错:', emailError); } }); // 立即返回成功响应 res.status(201).json(successResponse('留言提交成功,我们会尽快回复您', { id: contactData.id, message: '感谢您的留言,我们已收到并会在24小时内回复' })); } catch (error) { console.error('提交联系表单失败:', error); res.status(500).json(errorResponse('服务器内部错误')); } }); /** * @api {get} /contact 获取联系我们列表(管理员用) * @apiName GetContacts * @apiGroup Contact * * @apiParam {Number} [page=1] 页码 * @apiParam {Number} [limit=10] 每页数量 * @apiParam {Number} [status] 处理状态筛选(0-未处理,1-已处理) */ router.get('/', async (req, res) => { try { const { page = 1, limit = 10, status } = req.query; const offset = (page - 1) * limit; const whereConditions = {}; if (status !== undefined) { whereConditions.status = parseInt(status); } const { count, rows } = await Contact.findAndCountAll({ where: whereConditions, order: [['createdAt', 'DESC']], limit: parseInt(limit), offset: parseInt(offset) }); res.json(successResponse('获取成功', { contacts: rows, pagination: { total: count, page: parseInt(page), limit: parseInt(limit), totalPages: Math.ceil(count / limit) } })); } catch (error) { console.error('获取联系列表失败:', error); res.status(500).json(errorResponse('服务器内部错误')); } }); /** * @api {get} /contact/:id 获取联系详情 * @apiName GetContactDetail * @apiGroup Contact */ router.get('/:id', async (req, res) => { try { const { id } = req.params; const contact = await Contact.findByPk(id); if (!contact) { return res.status(404).json(errorResponse('联系记录不存在')); } res.json(successResponse('获取成功', contact)); } catch (error) { console.error('获取联系详情失败:', error); res.status(500).json(errorResponse('服务器内部错误')); } }); /** * @api {put} /contact/:id/status 更新处理状态 * @apiName UpdateContactStatus * @apiGroup Contact * * @apiParam {Number} status 处理状态(0-未处理,1-已处理) */ router.put('/:id/status', async (req, res) => { try { const { id } = req.params; const { status } = req.body; if (![0, 1].includes(parseInt(status))) { return res.status(400).json(errorResponse('状态值只能是0或1')); } const contact = await Contact.findByPk(id); if (!contact) { return res.status(404).json(errorResponse('联系记录不存在')); } await contact.update({ status: parseInt(status) }); res.json(successResponse('状态更新成功', contact)); } catch (error) { console.error('更新联系状态失败:', error); res.status(500).json(errorResponse('服务器内部错误')); } }); /** * @api {delete} /contact/:id 删除联系记录 * @apiName DeleteContact * @apiGroup Contact */ router.delete('/:id', async (req, res) => { try { const { id } = req.params; const contact = await Contact.findByPk(id); if (!contact) { return res.status(404).json(errorResponse('联系记录不存在')); } await contact.destroy(); res.json(successResponse('删除成功')); } catch (error) { console.error('删除联系记录失败:', error); res.status(500).json(errorResponse('服务器内部错误')); } }); module.exports = router;