Files
psychological-counseling/debug.php
litianming 08ce60344d Initial commit: 心理咨询预约系统
PHP 前后端一体:首页咨询师列表、预约表单、管理后台、二维码准入与邮件通知;敏感配置与提交数据通过 .gitignore 排除。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 10:17:09 +08:00

160 lines
6.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
require __DIR__ . '/api/bootstrap.php';
sendHtmlNoCacheHeaders();
$v = getAssetVersion();
?><!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>系统调试 - 心理咨询</title>
<link rel="stylesheet" href="<?= asset('css/base.css') ?>">
<link rel="stylesheet" href="<?= asset('css/admin.css') ?>">
<style>
.debug-page { padding: 16px; max-width: 640px; margin: 0 auto; }
.debug-card { background: #fff; border-radius: 12px; padding: 16px; margin-bottom: 16px; box-shadow: 0 2px 8px rgba(0,0,0,.06); }
.debug-card h2 { font-size: 16px; margin-bottom: 12px; }
.debug-row { font-size: 14px; margin-bottom: 8px; line-height: 1.6; word-break: break-all; }
.debug-row.ok { color: #40916c; }
.debug-row.fail { color: #e54d4d; }
.debug-actions { display: flex; flex-direction: column; gap: 8px; }
.debug-log { background: #1e1e1e; color: #d4d4d4; padding: 12px; border-radius: 8px; font-size: 12px; white-space: pre-wrap; word-break: break-all; max-height: 320px; overflow: auto; }
.debug-note { font-size: 13px; color: #666; line-height: 1.7; }
</style>
</head>
<body>
<div class="page debug-page">
<h1 class="admin-header__title">系统调试</h1>
<p class="debug-note">访问地址须带访问令牌,例如:<br><code id="sample-url"></code></p>
<div class="debug-card">
<h2>环境检测</h2>
<div id="env-result">加载中…</div>
</div>
<div class="debug-card">
<h2>操作</h2>
<div class="debug-actions">
<button type="button" class="btn btn--primary btn--block" id="btn-refresh">刷新检测</button>
<button type="button" class="btn btn--primary btn--block" id="btn-test-submit">测试提交(写入一条记录)</button>
<button type="button" class="btn btn--ghost btn--block" id="btn-test-mail">测试邮件(发送全部历史记录)</button>
<a href="consult.php" class="btn btn--ghost btn--block" style="text-align:center;line-height:48px">打开预约页</a>
<a href="admin.php" class="btn btn--ghost btn--block" style="text-align:center;line-height:48px">管理后台</a>
</div>
</div>
<div class="debug-card">
<h2>日志</h2>
<pre class="debug-log" id="debug-log">等待操作…</pre>
</div>
</div>
<script src="<?= asset('js/api.js') ?>"></script>
<script>
function getAccessToken() {
return new URLSearchParams(window.location.search).get("access") || "";
}
function diagUrl(action) {
const token = getAccessToken();
const base = new URL("api/diagnostics.php", window.location.href);
if (action) base.searchParams.set("action", action);
if (token) base.searchParams.set("access", token);
return base.href;
}
function log(msg) {
const el = document.getElementById("debug-log");
const time = new Date().toLocaleString("zh-CN", { hour12: false });
el.textContent = `[${time}] ${msg}\n\n` + el.textContent;
}
function row(label, ok, detail) {
return `<div class="debug-row ${ok ? "ok" : "fail"}">${ok ? "✓" : "✗"} ${label}${detail ? "" + detail : ""}</div>`;
}
async function loadDiagnostics() {
const token = getAccessToken();
const envEl = document.getElementById("env-result");
document.getElementById("sample-url").textContent =
window.location.origin + window.location.pathname.replace(/debug\.php$/, "debug.php") + "?access=你的accessToken";
if (!token) {
envEl.innerHTML = row("访问令牌", false, "URL 缺少 ?access= 参数");
return;
}
envEl.innerHTML = "检测中…";
try {
const res = await fetch(diagUrl(), { credentials: "same-origin" });
const text = await res.text();
let data;
try { data = JSON.parse(text); } catch {
envEl.innerHTML = row("接口响应", false, `非 JSONHTTP ${res.status}`);
log("GET diagnostics 失败:\n" + text.slice(0, 800));
return;
}
if (!res.ok) throw new Error(data.message || "检测失败");
const ext = data.extensions || {};
envEl.innerHTML = [
row("PHP 版本", true, data.phpVersion),
row("资源版本", true, data.assetVersion || "-"),
row("json 扩展", !!ext.json),
row("openssl 扩展", !!ext.openssl),
row("data 目录可写", !!data.dataDir?.ok, data.dataDir?.message),
row("提交记录数", true, String(data.submissions?.count ?? 0)),
row("邮件通知", !!data.mail?.enabled, data.mail?.enabled ? `${data.mail.recipientCount} 个收件人` : "未启用"),
row("submit 接口", true, new URL("api/submit.php", window.location.href).href),
].join("");
log("环境检测成功:\n" + JSON.stringify(data, null, 2));
} catch (e) {
envEl.innerHTML = row("环境检测", false, e.message);
log("环境检测异常: " + e.message);
}
}
async function postAction(action) {
const token = getAccessToken();
if (!token) {
alert("请先在 URL 中添加 ?access=访问令牌");
return;
}
log(`开始 ${action}…`);
try {
const res = await fetch(diagUrl(action), {
method: "POST",
headers: { "Content-Type": "application/json" },
body: "{}",
credentials: "same-origin",
});
const text = await res.text();
let data;
try { data = JSON.parse(text); } catch {
log(`${action} 失败HTTP ${res.status},非 JSON:\n` + text.slice(0, 800));
alert("请求失败,详见日志");
return;
}
if (!res.ok) throw new Error(data.message || `HTTP ${res.status}`);
log(`${action} 成功:\n` + JSON.stringify(data, null, 2));
alert(data.message || "操作成功");
await loadDiagnostics();
} catch (e) {
log(`${action} 异常: ` + e.message);
alert(e.message);
}
}
document.getElementById("btn-refresh").addEventListener("click", loadDiagnostics);
document.getElementById("btn-test-submit").addEventListener("click", () => postAction("submit"));
document.getElementById("btn-test-mail").addEventListener("click", () => postAction("mail"));
loadDiagnostics();
</script>
</body>
</html>