PHP 前后端一体:首页咨询师列表、预约表单、管理后台、二维码准入与邮件通知;敏感配置与提交数据通过 .gitignore 排除。 Co-authored-by: Cursor <cursoragent@cursor.com>
175 lines
5.3 KiB
JavaScript
175 lines
5.3 KiB
JavaScript
let selectedDoctor = null;
|
|
|
|
function getQueryDoctorId() {
|
|
return new URLSearchParams(window.location.search).get("doctorId");
|
|
}
|
|
|
|
function escapeHtml(str) {
|
|
const div = document.createElement("div");
|
|
div.textContent = str;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
function validatePhone(phone) {
|
|
return /^1[3-9]\d{9}$/.test(phone);
|
|
}
|
|
|
|
function getSelectedGender() {
|
|
const checked = document.querySelector('input[name="gender"]:checked');
|
|
return checked ? checked.value : "";
|
|
}
|
|
|
|
function renderDoctorBanner(doctor) {
|
|
const banner = document.getElementById("doctor-banner");
|
|
if (!doctor) {
|
|
banner.style.display = "none";
|
|
return;
|
|
}
|
|
selectedDoctor = doctor;
|
|
banner.style.display = "flex";
|
|
banner.innerHTML = `
|
|
<div class="doctor-banner__avatar-wrap">
|
|
<div class="doctor-banner__avatar-ring">
|
|
<img class="doctor-banner__avatar" src="${escapeHtml(assetUrl(doctor.avatar))}" alt="${escapeHtml(doctor.name)}" onerror="this.src='${assetUrl('assets/avatars/song.jpg')}'">
|
|
</div>
|
|
<span class="doctor-banner__verified" aria-hidden="true">
|
|
<svg viewBox="0 0 12 10" width="10" height="8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M1 5.2L4.2 8.4L11 1.2" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
</svg>
|
|
</span>
|
|
</div>
|
|
<div class="doctor-banner__info">
|
|
<div class="doctor-banner__name">${escapeHtml(doctor.name)} <span class="doctor-banner__tag">${escapeHtml(doctor.role || "")}</span></div>
|
|
<div class="doctor-banner__hospital">${escapeHtml(doctor.hospital || "")}</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
function updateCharCount() {
|
|
const textarea = document.getElementById("description");
|
|
const count = document.getElementById("char-count");
|
|
count.textContent = `(${textarea.value.length}/200字)`;
|
|
}
|
|
|
|
function showSuccess() {
|
|
const overlay = document.createElement("div");
|
|
overlay.className = "success-overlay";
|
|
overlay.innerHTML = `
|
|
<div class="success-overlay__icon">✅</div>
|
|
<h2 class="success-overlay__title">提交成功</h2>
|
|
<p class="success-overlay__desc">我们已收到您的预约信息<br>工作人员将在2小时内与您联系确认</p>
|
|
<button type="button" class="btn btn--primary" id="success-back">返回首页</button>
|
|
`;
|
|
document.body.appendChild(overlay);
|
|
document.getElementById("success-back").addEventListener("click", () => {
|
|
window.location.href = "index.php";
|
|
});
|
|
}
|
|
|
|
function markError(el) {
|
|
el.classList.add("is-error");
|
|
}
|
|
|
|
function clearErrors() {
|
|
document.querySelectorAll(".is-error").forEach((el) => el.classList.remove("is-error"));
|
|
}
|
|
|
|
function setupSubmitHandler() {
|
|
const textarea = document.getElementById("description");
|
|
const btn = document.getElementById("submit-btn");
|
|
|
|
btn.addEventListener("click", async () => {
|
|
clearErrors();
|
|
|
|
const nickname = document.getElementById("nickname").value.trim();
|
|
const gender = getSelectedGender();
|
|
const contact = document.getElementById("contact").value.trim();
|
|
const description = textarea.value.trim();
|
|
|
|
if (!nickname) {
|
|
markError(document.getElementById("nickname"));
|
|
showToast("请填写昵称");
|
|
return;
|
|
}
|
|
if (!gender) {
|
|
showToast("请选择性别");
|
|
return;
|
|
}
|
|
if (!contact) {
|
|
markError(document.getElementById("contact"));
|
|
showToast("请填写联系电话");
|
|
return;
|
|
}
|
|
if (!validatePhone(contact)) {
|
|
markError(document.getElementById("contact"));
|
|
showToast("请输入正确的11位手机号码");
|
|
return;
|
|
}
|
|
if (!description) {
|
|
markError(textarea);
|
|
showToast("请填写需求简述");
|
|
return;
|
|
}
|
|
|
|
btn.disabled = true;
|
|
btn.textContent = "提交中…";
|
|
|
|
try {
|
|
const result = await apiPost("submit.php", {
|
|
doctorId: selectedDoctor?.id || "",
|
|
doctorName: selectedDoctor?.name || "",
|
|
nickname,
|
|
gender,
|
|
contact,
|
|
description,
|
|
}, false, 60000);
|
|
showSuccess();
|
|
} catch (e) {
|
|
showToast(e.message || "提交失败");
|
|
btn.disabled = false;
|
|
btn.textContent = "提交";
|
|
}
|
|
});
|
|
}
|
|
|
|
async function initConsult() {
|
|
setupSubmitHandler();
|
|
|
|
const textarea = document.getElementById("description");
|
|
textarea.addEventListener("input", () => {
|
|
if (textarea.value.length > 200) {
|
|
textarea.value = textarea.value.slice(0, 200);
|
|
}
|
|
updateCharCount();
|
|
});
|
|
updateCharCount();
|
|
|
|
document.getElementById("back-btn").addEventListener("click", () => {
|
|
window.location.href = "index.php";
|
|
});
|
|
|
|
const allowed = await initAccessGuard();
|
|
if (!allowed) return;
|
|
|
|
try {
|
|
const config = await loadAppConfig();
|
|
document.title = (config.siteTitle || "心理咨询") + " - 预约";
|
|
document.querySelector(".header__title").textContent = config.siteTitle || "心理咨询";
|
|
|
|
const phone = config.confirmPhone || "13122315169";
|
|
document.getElementById("confirm-phone").textContent = phone;
|
|
document.getElementById("service-hotline").textContent = config.servicePhone || phone;
|
|
|
|
const doctors = await loadDoctors();
|
|
const doctorId = getQueryDoctorId();
|
|
if (doctorId) {
|
|
renderDoctorBanner(getDoctorById(doctors, doctorId));
|
|
}
|
|
} catch (e) {
|
|
console.error(e);
|
|
showToast(e.message || "页面数据加载失败,仍可尝试提交");
|
|
}
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", initConsult);
|