feat(client): 初始化前端壳与鉴权守卫(P1-5)

- 技术栈:React 18 + TypeScript + Vite + Tailwind

- API 层:ApiError + 401 自动刷新 + single-flight 重试

- 鉴权:内存 Access Token + Cookie Refresh + 启动 bootstrap

- RBAC:权限映射 + RequireAuth/RequirePermission 路由守卫

- 布局:OA 工作台壳层 + 侧边栏 + 5 个占位页面

- 样式:复用 hyb-web 视觉 token(单向同步)

- 文档:新增 client README,补充 server 联调说明
这个提交包含在:
2026-02-07 16:43:57 +08:00
父节点 f527633716
当前提交 c290e03fef
共修改 35 个文件,包含 4127 行新增和 0 行删除
+47
查看文件
@@ -0,0 +1,47 @@
import { apiRequestData } from "../api/http";
import type { LoginRequest, LoginResponse, MeResponse } from "../api/types";
import { getDeviceFingerprint } from "./deviceFingerprint";
const JSON_HEADERS = {
"content-type": "application/json",
};
export async function loginWithPassword(payload: LoginRequest) {
return apiRequestData<LoginResponse>("/api/auth/login", {
method: "POST",
auth: false,
retryOn401: false,
headers: {
...JSON_HEADERS,
"x-device-fingerprint": getDeviceFingerprint(),
},
body: JSON.stringify(payload),
});
}
export async function refreshSession() {
return apiRequestData<LoginResponse>("/api/auth/refresh", {
method: "POST",
auth: false,
retryOn401: false,
headers: {
"x-device-fingerprint": getDeviceFingerprint(),
},
});
}
export async function logoutSession() {
return apiRequestData<Record<string, never>>("/api/auth/logout", {
method: "POST",
auth: false,
retryOn401: false,
});
}
export async function fetchCurrentEmployee(accessToken: string) {
return apiRequestData<MeResponse>("/api/me", {
auth: true,
retryOn401: false,
accessTokenOverride: accessToken,
});
}