130 lines
3.4 KiB
JavaScript
130 lines
3.4 KiB
JavaScript
const HAIYI_BASE_PATH = window.location.pathname === "/haiyi" || window.location.pathname.startsWith("/haiyi/") ? "/haiyi" : "";
|
|
|
|
function appPath(path) {
|
|
const normalized = typeof path === "string" && path.startsWith("/") ? path : `/${path || ""}`;
|
|
return `${HAIYI_BASE_PATH}${normalized}` || "/";
|
|
}
|
|
|
|
function loginRedirectPath() {
|
|
return `/login?next=${encodeURIComponent(`${window.location.pathname}${window.location.search}`)}`;
|
|
}
|
|
|
|
async function readJsonResponse(response) {
|
|
const text = await response.text();
|
|
if (!text) {
|
|
return {};
|
|
}
|
|
try {
|
|
return JSON.parse(text);
|
|
} catch (error) {
|
|
throw new Error(text);
|
|
}
|
|
}
|
|
|
|
window.addEventListener("DOMContentLoaded", async () => {
|
|
const bootIndicator = document.getElementById("boot-indicator");
|
|
const root = document.getElementById("haiyi-root");
|
|
const errorNode = document.getElementById("haiyi-error");
|
|
const usernameNode = document.getElementById("haiyi-username");
|
|
const healthNode = document.getElementById("haiyi-health");
|
|
const refreshButton = document.getElementById("haiyi-refresh");
|
|
const logoutButton = document.getElementById("haiyi-logout");
|
|
|
|
const showPage = () => {
|
|
if (bootIndicator) {
|
|
bootIndicator.hidden = true;
|
|
}
|
|
if (root) {
|
|
root.hidden = false;
|
|
}
|
|
};
|
|
|
|
const setError = (message) => {
|
|
if (!errorNode) {
|
|
return;
|
|
}
|
|
errorNode.textContent = message || "";
|
|
errorNode.hidden = !message;
|
|
};
|
|
|
|
const loadSession = async () => {
|
|
const response = await fetch(appPath("/api/auth/session"), {
|
|
cache: "no-store",
|
|
credentials: "same-origin",
|
|
});
|
|
const payload = await readJsonResponse(response);
|
|
|
|
if (response.status === 401) {
|
|
window.location.replace(loginRedirectPath());
|
|
return false;
|
|
}
|
|
|
|
if (!response.ok) {
|
|
throw new Error(payload.error || `HTTP ${response.status}`);
|
|
}
|
|
|
|
if (usernameNode) {
|
|
usernameNode.textContent = payload.username || "";
|
|
usernameNode.hidden = !payload.username;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
const loadHealth = async () => {
|
|
const response = await fetch(appPath("/api/health"), {
|
|
cache: "no-store",
|
|
credentials: "same-origin",
|
|
});
|
|
const payload = await readJsonResponse(response);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(payload.error || `HTTP ${response.status}`);
|
|
}
|
|
|
|
if (healthNode) {
|
|
healthNode.textContent = payload.status === "ok" ? "在线" : "异常";
|
|
healthNode.className = payload.status === "ok" ? "badge ok" : "badge bad";
|
|
}
|
|
};
|
|
|
|
try {
|
|
const ok = await loadSession();
|
|
if (!ok) {
|
|
return;
|
|
}
|
|
await loadHealth();
|
|
} catch (error) {
|
|
setError(error instanceof Error ? error.message : String(error));
|
|
} finally {
|
|
showPage();
|
|
}
|
|
|
|
if (refreshButton instanceof HTMLButtonElement) {
|
|
refreshButton.addEventListener("click", async () => {
|
|
refreshButton.disabled = true;
|
|
setError("");
|
|
try {
|
|
await loadHealth();
|
|
} catch (error) {
|
|
setError(error instanceof Error ? error.message : String(error));
|
|
} finally {
|
|
refreshButton.disabled = false;
|
|
}
|
|
});
|
|
}
|
|
|
|
if (logoutButton instanceof HTMLButtonElement) {
|
|
logoutButton.addEventListener("click", async () => {
|
|
logoutButton.disabled = true;
|
|
try {
|
|
await fetch(appPath("/api/auth/logout"), {
|
|
method: "POST",
|
|
credentials: "same-origin",
|
|
});
|
|
} finally {
|
|
window.location.replace("/login");
|
|
}
|
|
});
|
|
}
|
|
});
|