|
|
|
@ -151,7 +151,8 @@ |
|
|
|
<div class="flex items-center space-x-2"> |
|
|
|
<div |
|
|
|
class="w-10 h-10 rounded-lg bg-gradient-to-r from-primary to-secondary flex items-center justify-center"> |
|
|
|
<img alt="夺宝奇兵" src="https://hc.homilychart.com/hc/250121/img/20230711171637.png" style="width: 40px;height: 40px;"> |
|
|
|
<img alt="夺宝奇兵" src="https://hc.homilychart.com/hc/250121/img/20230711171637.png" |
|
|
|
style="width: 40px;height: 40px;"> |
|
|
|
</div> |
|
|
|
<span |
|
|
|
class="text-xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-secondary">意见反馈</span> |
|
|
|
@ -193,7 +194,7 @@ |
|
|
|
|
|
|
|
<!-- 反馈表单卡片 --> |
|
|
|
<div class="bg-white rounded-xl p-6 md:p-8 mb-10 fade-in delay-100 card-shadow"> |
|
|
|
<form id="feedbackForm" action="feedbackinfo.asp" method="post" class="space-y-6"> |
|
|
|
<form id="feedbackForm" class="space-y-6"> |
|
|
|
<!-- 姓名输入 --> |
|
|
|
<div class="form-group"> |
|
|
|
<label for="name" class="block text-gray-700 font-medium mb-2">姓名 <span |
|
|
|
@ -363,18 +364,18 @@ |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 反馈内容 --> |
|
|
|
<!-- 反馈内容(增加最大长度500字的实时限制与校验) --> |
|
|
|
<div class="form-group"> |
|
|
|
<label for="feedbackContent" class="block text-gray-700 font-medium mb-2">反馈内容 <span |
|
|
|
class="text-danger">*</span></label> |
|
|
|
<div class="relative"> |
|
|
|
<textarea id="fcontent" name="fcontent" rows="5" required |
|
|
|
<textarea id="fcontent" name="fcontent" rows="5" required maxlength="500" |
|
|
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg input-focus transition-colors resize-none" |
|
|
|
placeholder="请详细描述您的意见或建议..."></textarea> |
|
|
|
placeholder="请详细描述您的意见或建议...(最多500字)"></textarea> |
|
|
|
<div class="absolute right-3 bottom-3 text-gray-400 text-sm"> |
|
|
|
<span id="charCount">0</span> / 500 |
|
|
|
</div> |
|
|
|
<div class="error-message" id="feedbackContentError">请输入反馈内容(至少10个字符)</div> |
|
|
|
<div class="error-message" id="feedbackContentError">请输入反馈内容(至少10个字符,最多500字)</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
@ -411,27 +412,29 @@ |
|
|
|
<i class="fa fa-check-circle text-success mt-1 mr-2 flex-shrink-0"></i> |
|
|
|
<span>您的个人信息仅用于反馈跟进,我们将严格保密</span> |
|
|
|
</li> |
|
|
|
<li class="flex items-start"> |
|
|
|
<i class="fa fa-check-circle text-success mt-1 mr-2 flex-shrink-0"></i> |
|
|
|
<span>反馈内容限500字以内,请合理控制字数</span> |
|
|
|
</li> |
|
|
|
</ul> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</main> |
|
|
|
|
|
|
|
<!-- 通用弹窗 --> |
|
|
|
<div id="statusModal" class="modal-backdrop" role="dialog" aria-modal="true"> |
|
|
|
<!-- 成功弹窗(与参考页面样式一致,点击确定按钮关闭) --> |
|
|
|
<div id="successModal" class="modal-backdrop" role="dialog" aria-modal="true"> |
|
|
|
<div class="modal-content p-6"> |
|
|
|
<div class="text-center mb-6"> |
|
|
|
<div id="modalIconContainer" |
|
|
|
class="w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4"> |
|
|
|
<i id="modalIcon" class="text-2xl"></i> |
|
|
|
<div class="text-center"> |
|
|
|
<div class="w-16 h-16 rounded-full bg-success/20 flex items-center justify-center mx-auto mb-4"> |
|
|
|
<i class="fa fa-check-circle text-success text-3xl"></i> |
|
|
|
</div> |
|
|
|
<h3 id="modalTitle" class="text-xl font-bold"></h3> |
|
|
|
<p id="modalMessage" class="text-gray-600 mt-3"></p> |
|
|
|
<h3 class="text-xl font-bold mb-2">反馈成功!</h3> |
|
|
|
<p class="text-gray-600 mb-6">感谢您的反馈,我们将持续优化更新</p> |
|
|
|
<button id="closeModalBtn" |
|
|
|
class="px-6 py-2 bg-gradient-to-r from-primary to-secondary text-white rounded-lg hover:shadow-lg transition-all"> |
|
|
|
确定 |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
|
|
|
|
<button id="closeModal" |
|
|
|
class="w-full py-3 rounded-lg bg-primary text-white font-medium hover:bg-primary/90 transition-colors"> |
|
|
|
确定 |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
@ -450,7 +453,264 @@ |
|
|
|
<p class="text-gray-400 text-sm mb-4">Copyright 2026.Capitalmaster Pte Ltd All Rights Reserved.</p> |
|
|
|
</div> |
|
|
|
</footer> |
|
|
|
<script type="text/javascript" src="250121/js/20251016.js"></script> |
|
|
|
|
|
|
|
<script type="module"> |
|
|
|
// 从外部文件导入 registerMemberApi 函数 |
|
|
|
import { registerMemberApi } from './src/api/hkmember.js'; |
|
|
|
|
|
|
|
// DOM 元素 |
|
|
|
const form = document.getElementById('feedbackForm'); |
|
|
|
const submitBtn = document.getElementById('submitBtn'); |
|
|
|
const loadingIndicator = document.getElementById('loadingIndicator'); |
|
|
|
const successModal = document.getElementById('successModal'); |
|
|
|
const closeModalBtn = document.getElementById('closeModalBtn'); |
|
|
|
|
|
|
|
// 字符计数 |
|
|
|
const fcontent = document.getElementById('fcontent'); |
|
|
|
const charCount = document.getElementById('charCount'); |
|
|
|
|
|
|
|
// 错误提示元素 |
|
|
|
const nameError = document.getElementById('nameError'); |
|
|
|
const phoneError = document.getElementById('phoneError'); |
|
|
|
const emailError = document.getElementById('emailError'); |
|
|
|
const feedbackContentError = document.getElementById('feedbackContentError'); |
|
|
|
|
|
|
|
// 隐藏所有错误提示 |
|
|
|
function hideAllErrors() { |
|
|
|
nameError.style.display = 'none'; |
|
|
|
phoneError.style.display = 'none'; |
|
|
|
emailError.style.display = 'none'; |
|
|
|
feedbackContentError.style.display = 'none'; |
|
|
|
} |
|
|
|
|
|
|
|
// 显示错误提示 |
|
|
|
function showError(element, message) { |
|
|
|
if (element) { |
|
|
|
element.textContent = message; |
|
|
|
element.style.display = 'block'; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 显示成功弹窗 |
|
|
|
function showSuccessModal() { |
|
|
|
successModal.classList.add('active'); |
|
|
|
} |
|
|
|
|
|
|
|
// 隐藏成功弹窗 |
|
|
|
function hideSuccessModal() { |
|
|
|
successModal.classList.remove('active'); |
|
|
|
} |
|
|
|
|
|
|
|
// 关闭弹窗事件 |
|
|
|
closeModalBtn.addEventListener('click', hideSuccessModal); |
|
|
|
|
|
|
|
// 点击模态框背景关闭 |
|
|
|
successModal.addEventListener('click', function (e) { |
|
|
|
if (e.target === successModal) { |
|
|
|
hideSuccessModal(); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 邮箱校验 |
|
|
|
function isValidEmail(email) { |
|
|
|
const emailRegex = /^[^\s@]+@([^\s@]+\.)+[^\s@]+$/; |
|
|
|
if (!emailRegex.test(email)) return false; |
|
|
|
if (email.length > 254) return false; |
|
|
|
if (email.includes('..')) return false; |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
// 手机号校验 |
|
|
|
function isValidPhone(phone) { |
|
|
|
if (!phone || phone.trim() === '') return false; |
|
|
|
const digitsOnly = phone.replace(/[^\d]/g, ''); |
|
|
|
if (digitsOnly.length < 4 || digitsOnly.length > 20) return false; |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
// 清理手机号 |
|
|
|
function cleanPhoneNumber(phone) { |
|
|
|
if (!phone) return ''; |
|
|
|
let cleaned = phone.replace(/[^\d]/g, ''); |
|
|
|
cleaned = cleaned.replace(/^(00)/, ''); |
|
|
|
return cleaned; |
|
|
|
} |
|
|
|
|
|
|
|
// 反馈类型映射 |
|
|
|
function getFeedbackTypeValue(typeText) { |
|
|
|
const typeMap = { |
|
|
|
'功能建议': '1', |
|
|
|
'问题反馈': '2', |
|
|
|
'体验优化': '3', |
|
|
|
'其他建议': '4' |
|
|
|
}; |
|
|
|
return typeMap[typeText] || '4'; |
|
|
|
} |
|
|
|
|
|
|
|
// 字符计数 & 实时限制(确保不超过500字,与maxlength配合) |
|
|
|
if (fcontent && charCount) { |
|
|
|
// 初始化显示 |
|
|
|
charCount.textContent = fcontent.value.length; |
|
|
|
|
|
|
|
fcontent.addEventListener('input', function () { |
|
|
|
let len = this.value.length; |
|
|
|
// 双重保险:如果超过500则截断 |
|
|
|
if (len > 500) { |
|
|
|
this.value = this.value.substring(0, 500); |
|
|
|
len = 500; |
|
|
|
} |
|
|
|
charCount.textContent = len; |
|
|
|
|
|
|
|
// 实时移除字数超限的错误提示(如果之前是因为超限报错) |
|
|
|
if (len <= 500 && feedbackContentError && feedbackContentError.style.display === 'block' && feedbackContentError.textContent.includes('最多500字')) { |
|
|
|
// 但避免移除其他类型错误,通过文本内容判断 |
|
|
|
if (feedbackContentError.textContent.includes('最多500字')) { |
|
|
|
feedbackContentError.style.display = 'none'; |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 增加blur时再次校验,保证用户粘贴超长内容时提示 |
|
|
|
fcontent.addEventListener('blur', function () { |
|
|
|
let len = this.value.length; |
|
|
|
if (len > 500) { |
|
|
|
this.value = this.value.substring(0, 500); |
|
|
|
charCount.textContent = 500; |
|
|
|
showError(feedbackContentError, '反馈内容不能超过500字'); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// 移动端菜单切换 |
|
|
|
const mobileMenuBtn = document.getElementById('mobileMenuBtn'); |
|
|
|
if (mobileMenuBtn) { |
|
|
|
mobileMenuBtn.addEventListener('click', function () { |
|
|
|
const menu = document.getElementById('mobileMenu'); |
|
|
|
menu.classList.toggle('hidden'); |
|
|
|
const icon = this.querySelector('i'); |
|
|
|
if (icon.classList.contains('fa-bars')) { |
|
|
|
icon.classList.replace('fa-bars', 'fa-times'); |
|
|
|
} else { |
|
|
|
icon.classList.replace('fa-times', 'fa-bars'); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// 表单提交处理 - 调用API保存数据,成功后显示弹窗,额外校验500字限制 |
|
|
|
form.addEventListener('submit', async function (e) { |
|
|
|
e.preventDefault(); |
|
|
|
|
|
|
|
// 前端校验 |
|
|
|
hideAllErrors(); |
|
|
|
|
|
|
|
const name = document.getElementById('fusername').value.trim(); |
|
|
|
const countryCode = document.getElementById('countryinfo').value; |
|
|
|
const phoneRaw = document.getElementById('umoblie').value.trim(); |
|
|
|
const wechat = document.getElementById('fwechat').value.trim(); |
|
|
|
const email = document.getElementById('femail').value.trim(); |
|
|
|
const feedbackTypeText = document.getElementById('ftype').value; |
|
|
|
let feedbackContent = document.getElementById('fcontent').value.trim(); |
|
|
|
|
|
|
|
let isValid = true; |
|
|
|
|
|
|
|
// 姓名校验 |
|
|
|
if (!name) { |
|
|
|
showError(nameError, '请输入您的姓名'); |
|
|
|
isValid = false; |
|
|
|
} |
|
|
|
|
|
|
|
// 手机号校验 |
|
|
|
if (!phoneRaw || !isValidPhone(phoneRaw)) { |
|
|
|
showError(phoneError, '请输入有效的手机号码'); |
|
|
|
isValid = false; |
|
|
|
} |
|
|
|
|
|
|
|
// 邮箱校验 |
|
|
|
if (!email || !isValidEmail(email)) { |
|
|
|
showError(emailError, '请输入有效的邮箱地址'); |
|
|
|
isValid = false; |
|
|
|
} |
|
|
|
|
|
|
|
// 反馈内容校验: 不能为空且长度必须在10~500之间 |
|
|
|
if (!feedbackContent) { |
|
|
|
showError(feedbackContentError, '请输入反馈内容(至少10个字符,最多500字)'); |
|
|
|
isValid = false; |
|
|
|
} else { |
|
|
|
// 重新获取实际内容(防止中间有特殊空格导致长度偏差) |
|
|
|
const rawLen = feedbackContent.length; |
|
|
|
if (rawLen < 10) { |
|
|
|
showError(feedbackContentError, '反馈内容至少需要10个字符,请详细描述'); |
|
|
|
isValid = false; |
|
|
|
} else if (rawLen > 500) { |
|
|
|
// 如果因为某些意外情况(例如直接通过开发者工具修改)导致超长,再次截断并提示 |
|
|
|
feedbackContent = feedbackContent.substring(0, 500); |
|
|
|
document.getElementById('fcontent').value = feedbackContent; |
|
|
|
charCount.textContent = 500; |
|
|
|
showError(feedbackContentError, '反馈内容不能超过500字,已自动截断'); |
|
|
|
isValid = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!isValid) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 清理手机号 |
|
|
|
const cleanedPhone = cleanPhoneNumber(phoneRaw); |
|
|
|
|
|
|
|
// 组装请求参数 |
|
|
|
const requestData = { |
|
|
|
name: name, |
|
|
|
code: countryCode, |
|
|
|
tel: cleanedPhone, |
|
|
|
email: email, |
|
|
|
feedback_content: feedbackContent, |
|
|
|
feedback_type: getFeedbackTypeValue(feedbackTypeText) |
|
|
|
}; |
|
|
|
|
|
|
|
// 微信ID有值才传递 |
|
|
|
if (wechat) { |
|
|
|
requestData.weChat = wechat; |
|
|
|
} |
|
|
|
|
|
|
|
// 显示加载状态 |
|
|
|
submitBtn.disabled = true; |
|
|
|
loadingIndicator.classList.remove('hidden'); |
|
|
|
|
|
|
|
try { |
|
|
|
const result = await registerMemberApi(requestData); |
|
|
|
if (result.code === 200) { |
|
|
|
// API调用成功,显示成功弹窗 |
|
|
|
showSuccessModal(); |
|
|
|
// 清空表单 |
|
|
|
form.reset(); |
|
|
|
// 重置字符计数 |
|
|
|
if (charCount) charCount.textContent = '0'; |
|
|
|
// 清空所有隐藏错误显示 |
|
|
|
hideAllErrors(); |
|
|
|
} else { |
|
|
|
alert('提交失败:' + (result.msg || '请稍后重试')); |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('提交出错:', error); |
|
|
|
alert('网络错误或接口异常,请稍后重试'); |
|
|
|
} finally { |
|
|
|
submitBtn.disabled = false; |
|
|
|
loadingIndicator.classList.add('hidden'); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 页面加载动画 |
|
|
|
document.addEventListener('DOMContentLoaded', function () { |
|
|
|
document.querySelectorAll('.fade-in').forEach(el => { |
|
|
|
el.style.opacity = '1'; |
|
|
|
}); |
|
|
|
// 确保字符计数初始正确 |
|
|
|
if (fcontent && charCount) { |
|
|
|
charCount.textContent = fcontent.value.length; |
|
|
|
} |
|
|
|
}); |
|
|
|
</script> |
|
|
|
</body> |
|
|
|
|
|
|
|
</html> |