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 联调说明
这个提交包含在:
@@ -0,0 +1,28 @@
|
||||
const DEVICE_FINGERPRINT_KEY = "hyb_oa_device_fingerprint";
|
||||
|
||||
function fallbackFingerprint() {
|
||||
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
||||
}
|
||||
|
||||
function generateFingerprint() {
|
||||
if (typeof crypto !== "undefined" && "randomUUID" in crypto) {
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
|
||||
return fallbackFingerprint();
|
||||
}
|
||||
|
||||
export function getDeviceFingerprint() {
|
||||
if (typeof window === "undefined") {
|
||||
return "server-render";
|
||||
}
|
||||
|
||||
const existing = window.localStorage.getItem(DEVICE_FINGERPRINT_KEY);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
const next = generateFingerprint();
|
||||
window.localStorage.setItem(DEVICE_FINGERPRINT_KEY, next);
|
||||
return next;
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户