76f266645d
含 Phase 1.1 IM seq 排序、断线重连、多端已读同步与微信式语音转文字 UI。 排除 node_modules、构建产物、安装包与 .env 密钥。 Co-authored-by: Cursor <cursoragent@cursor.com>
33 lines
1.1 KiB
TypeScript
33 lines
1.1 KiB
TypeScript
const ADMIN = ['admin', 'owner'];
|
|
|
|
export function canHr(roles: string[]) {
|
|
return [...ADMIN, 'hr', 'biz_director'].some((r) => roles.includes(r));
|
|
}
|
|
|
|
export function canConfirmPay(roles: string[]) {
|
|
return [...ADMIN, 'hr', 'biz_director'].some((r) => roles.includes(r));
|
|
}
|
|
|
|
export function canApproveFin(roles: string[]) {
|
|
return [...ADMIN, 'finance', 'biz_director'].some((r) => roles.includes(r));
|
|
}
|
|
|
|
const ACTIONS = new Set(['view', 'create', 'edit', 'delete', 'approve']);
|
|
|
|
/** 菜单下的具体操作。还没配操作项时,有该菜单就视为能做。 */
|
|
export function canDo(
|
|
permissions: string[],
|
|
roles: string[],
|
|
menuCode: string,
|
|
action: 'view' | 'create' | 'edit' | 'delete' | 'approve',
|
|
) {
|
|
if (ADMIN.some((r) => roles.includes(r))) return true;
|
|
if (permissions.includes(`${menuCode}:${action}`)) return true;
|
|
const hasActions = permissions.some((p) => {
|
|
const tail = p.slice(menuCode.length + 1);
|
|
return p.startsWith(`${menuCode}:`) && ACTIONS.has(tail);
|
|
});
|
|
if (hasActions) return false;
|
|
return permissions.includes(menuCode) || permissions.some((p) => p.startsWith(`${menuCode}:`));
|
|
}
|