import type { UserPayload } from "@/types/api"; /** * 后端账号取值契约(与 common_const §13 对齐,数据库存值不改动)。 * 前端只做展示映射和菜单显隐,不修改后端权限判断 —— 真正的鉴权仍在服务端。 */ /** sys_user.user_type:建表枚举,沿用 DDL 定义。 */ export const USER_TYPE = { CUSTOMER: "CUSTOMER", EMPLOYEE: "EMPLOYEE", ADMIN: "ADMIN", } as const; /** sys_user.employee_role:中文,与既有数据一致。 */ export const EMPLOYEE_ROLE = { ADMIN: "管理员", ADVISOR: "投顾", RISK: "风控专员", CUSTOMER_MANAGER: "客户经理", } as const; /** 统一工作台上可切换的功能区。 */ export type WorkspaceSection = | "overview" | "todos" | "customers" | "drafts" | "visits" | "risk" | "workorders" | "funds" | "nl2sql" | "admin"; /** * 左侧「工作分区」分组。侧边栏按分区归组展示,而不是平铺所有功能区, * 员工能一眼看出自己手头有几类活。 */ export interface WorkspaceZone { id: string; label: string; sections: WorkspaceSection[]; } export const WORKSPACE_ZONES: WorkspaceZone[] = [ { id: "home", label: "概览", sections: ["overview"] }, { id: "advisor", label: "投顾作业", sections: ["todos", "customers", "drafts", "visits"] }, { id: "risk", label: "风控处置", sections: ["risk", "workorders"] }, { id: "data", label: "数据工具", sections: ["funds", "nl2sql"] }, { id: "system", label: "系统管理", sections: ["admin"] }, ]; /** 管理员:账号类型为 ADMIN,或员工账号且角色为「管理员」。 */ export function isAdmin(user?: UserPayload | null): boolean { if (!user) return false; if (user.user_type === USER_TYPE.ADMIN) return true; return user.user_type === USER_TYPE.EMPLOYEE && user.employee_role === EMPLOYEE_ROLE.ADMIN; } export function isEmployee(user?: UserPayload | null): boolean { return user?.user_type === USER_TYPE.EMPLOYEE; } /** 是否能进入员工后台(管理员视同拥有全部员工权限)。 */ export function isStaff(user?: UserPayload | null): boolean { return isAdmin(user) || isEmployee(user); } /** 员工角色命中即通过;管理员一律放行。 */ function hasEmployeeRole(user: UserPayload | null | undefined, role: string): boolean { if (isAdmin(user)) return true; return isEmployee(user) && user?.employee_role === role; } export function isAdvisor(user?: UserPayload | null): boolean { return hasEmployeeRole(user, EMPLOYEE_ROLE.ADVISOR); } export function isRiskOfficer(user?: UserPayload | null): boolean { return hasEmployeeRole(user, EMPLOYEE_ROLE.RISK); } /** * 各功能区所需权限。 * 不满足时不整页拒绝,而是在该区域内渲染「无权限」提示,员工仍可使用其它有权限的模块。 */ const SECTION_GUARD: Record boolean> = { overview: isStaff, todos: isAdvisor, customers: isAdvisor, drafts: isAdvisor, visits: isAdvisor, risk: isRiskOfficer, workorders: isRiskOfficer, funds: isStaff, nl2sql: isStaff, admin: isAdmin, }; export function canUseSection( user: UserPayload | null | undefined, section: WorkspaceSection ): boolean { return SECTION_GUARD[section]?.(user) ?? false; } export function isWorkspaceSection(value: string | null): value is WorkspaceSection { return !!value && value in SECTION_GUARD; } /** 分区下所有功能区都无权限时整组隐藏,避免侧边栏出现全是灰标的空分区。 */ export function visibleZones(user: UserPayload | null | undefined): WorkspaceZone[] { return WORKSPACE_ZONES.filter((zone) => zone.sections.some((section) => canUseSection(user, section)) ); }