import { ApiError } from "@bid-doctor/api-client"; import { createRouter, createWebHashHistory, createWebHistory } from "vue-router"; import AppShell from "@/components/AppShell.vue"; import { runtimeConfig } from "@/lib/config"; import { qk } from "@/lib/keys"; import { fetchMe } from "@/lib/queries"; import { queryClient } from "@/lib/queryClient"; declare module "vue-router" { interface RouteMeta { /** 不需要登录 */ public?: boolean; } } export const router = createRouter({ // 路由基础路径可配置;桌面外壳用 hash 模式(架构 §5.2 第 6 条) history: runtimeConfig.routerMode === "hash" ? createWebHashHistory() : createWebHistory(runtimeConfig.routerBase), routes: [ { path: "/login", name: "login", component: () => import("@/pages/LoginPage.vue"), meta: { public: true } }, { path: "/", component: AppShell, children: [ { path: "", name: "workbench", component: () => import("@/pages/WorkbenchPage.vue") }, { path: "projects/new", name: "project-new", component: () => import("@/pages/ProjectNewPage.vue") }, { path: "projects/:projectId/parse/:jobId", name: "parse", component: () => import("@/pages/ParsePage.vue"), props: true, }, { path: "projects/:projectId/checklist", name: "checklist", component: () => import("@/pages/ChecklistPage.vue"), props: true, }, ], }, { path: "/:pathMatch(.*)*", redirect: "/" }, ], }); router.beforeEach(async (to) => { if (to.meta.public) return true; try { await queryClient.fetchQuery({ queryKey: qk.me, queryFn: fetchMe, staleTime: 60_000 }); return true; } catch (e) { // 被其他设备挤下线(session_revoked)、过期(session_expired)时,登录页说明原因 const reason = e instanceof ApiError && e.code !== "unauthenticated" ? { reason: e.code } : {}; return { name: "login", query: { ...(to.fullPath === "/" ? {} : { redirect: to.fullPath }), ...reason } }; } });