Files
bid-doctor/apps/web/src/router.ts
YANG JIANKUAN 6aaf8e768b feat(web): 用户端骨架——登录、工作台、新建项目、解析进度、读标清单
- packages/api-client:从 openapi.yaml 生成类型;cookie + CSRF / Bearer 两种鉴权、
  分片上传、fetch 读事件流(API2)
- apps/web:Vue 3 + Vite + TanStack Query,样式只来自 tokens.css / components.css(AR10);
  扣点说明放在「开始解析」旁边(红线 9);接口地址、路由方式运行时可配(架构 §5.2)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 18:48:10 +08:00

56 lines
2.0 KiB
TypeScript
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.

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 } };
}
});