Scert/frontend/src/App.js

76 lines
2.1 KiB
JavaScript

import { onMounted, ref } from "vue";
export function useAppShell() {
const setupState = ref(null);
const authenticated = ref(null);
const isAdmin = ref(null);
const bootstrapping = ref(true);
const error = ref("");
const routePath = window.location.pathname.replace(/\/+$/, "") || "/";
const standalonePaths = ["/login", "/password-reset", "/reset"];
async function bootstrap() {
bootstrapping.value = true;
error.value = "";
try {
const response = await fetch("/api/v1/setup/status");
const result = await response.json().catch(() => ({}));
if (!response.ok) throw new Error(result.error || "读取初始化状态失败");
setupState.value = result;
if (result.initialized) {
await checkAuth();
} else {
authenticated.value = false;
isAdmin.value = false;
}
} catch (err) {
setupState.value = null;
authenticated.value = null;
isAdmin.value = null;
error.value = err.message || "无法连接核心服务,请先启动 scert serve";
} finally {
bootstrapping.value = false;
}
}
async function checkAuth() {
const response = await fetch("/api/v1/auth/session", {
credentials: "include",
});
if (response.status === 401) {
authenticated.value = false;
isAdmin.value = false;
return;
}
const result = await response.json().catch(() => ({}));
if (!response.ok) throw new Error(result.error || "读取登录状态失败");
authenticated.value = result.authenticated === true;
isAdmin.value = result.is_admin === true || ["super_admin", "admin"].includes(result.role);
}
function handleInitialized() {
setupState.value = { ...setupState.value, initialized: true };
authenticated.value = false;
isAdmin.value = false;
}
onMounted(() => {
if (standalonePaths.includes(routePath)) {
bootstrapping.value = false;
return;
}
bootstrap();
});
return {
setupState,
authenticated,
isAdmin,
bootstrapping,
error,
routePath,
bootstrap,
handleInitialized,
};
}