Initial commit: 心理咨询预约系统

PHP 前后端一体:首页咨询师列表、预约表单、管理后台、二维码准入与邮件通知;敏感配置与提交数据通过 .gitignore 排除。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
litianming
2026-06-04 10:17:09 +08:00
commit 08ce60344d
49 changed files with 3490 additions and 0 deletions

120
js/admin.js Normal file
View File

@@ -0,0 +1,120 @@
let isLoggedIn = false;
function formatTime(iso) {
if (!iso) return "-";
try {
const d = new Date(iso);
return d.toLocaleString("zh-CN", { hour12: false });
} catch {
return iso;
}
}
function renderSubmissionCard(item) {
const card = document.createElement("article");
card.className = "submission-card";
const doctorInfo = item.doctorName ? `${item.doctorName}` : "未指定咨询师";
card.innerHTML = `
<div class="submission-card__time">${formatTime(item.createdAt)}</div>
<div class="submission-card__row"><strong>昵称:</strong>${escapeHtml(item.nickname || "-")}</div>
<div class="submission-card__row"><strong>性别:</strong>${escapeHtml(item.gender || "-")}</div>
<div class="submission-card__row"><strong>联系电话:</strong>${escapeHtml(item.contact || "-")}</div>
<div class="submission-card__row"><strong>咨询师:</strong>${escapeHtml(doctorInfo)}</div>
<p class="submission-card__desc">${escapeHtml(item.description || "(无描述)")}</p>
`;
return card;
}
function escapeHtml(str) {
const div = document.createElement("div");
div.textContent = str;
return div.innerHTML;
}
function showLogin() {
document.getElementById("login-section").style.display = "block";
document.getElementById("dashboard-section").style.display = "none";
isLoggedIn = false;
}
function showDashboard() {
document.getElementById("login-section").style.display = "none";
document.getElementById("dashboard-section").style.display = "block";
isLoggedIn = true;
}
async function loadSubmissions() {
const listEl = document.getElementById("submission-list");
listEl.innerHTML = "<p>加载中…</p>";
try {
const res = await apiGet("submissions.php", true);
const items = res.data || [];
document.getElementById("submission-count").textContent = items.length;
if (items.length === 0) {
listEl.innerHTML = '<p class="admin-empty">暂无提交记录</p>';
return;
}
listEl.innerHTML = "";
items.forEach((item) => listEl.appendChild(renderSubmissionCard(item)));
} catch (e) {
if (e.message && e.message.includes("未登录")) {
showLogin();
return;
}
listEl.innerHTML = '<p class="admin-empty">加载失败</p>';
showToast(e.message || "加载失败");
}
}
async function tryAutoLogin() {
try {
const res = await apiGet("check.php", true);
if (res.loggedIn) {
showDashboard();
await loadSubmissions();
return true;
}
} catch (_) {}
return false;
}
function downloadExport(format) {
window.location.href = `${API_BASE}/export.php?format=${format}`;
}
async function initAdmin() {
document.getElementById("login-form").addEventListener("submit", async (e) => {
e.preventDefault();
const user = document.getElementById("admin-user").value.trim();
const password = document.getElementById("admin-password").value;
try {
await apiPost("login.php", { user, password }, true);
showToast("登录成功");
showDashboard();
await loadSubmissions();
} catch (err) {
showToast(err.message || "登录失败");
}
});
document.getElementById("logout-btn").addEventListener("click", async () => {
try {
await apiPost("logout.php", {}, true);
} catch (_) {}
showLogin();
showToast("已退出");
});
document.getElementById("export-json").addEventListener("click", () => downloadExport("json"));
document.getElementById("export-csv").addEventListener("click", () => downloadExport("csv"));
document.getElementById("refresh-btn").addEventListener("click", loadSubmissions);
const ok = await tryAutoLogin();
if (!ok) showLogin();
}
document.addEventListener("DOMContentLoaded", initAdmin);