ab4f0d93ed
1、合并列表与详情读取权限,统一使用 subjects:read、project_members:read、monitoring_issues:read 等业务读取 key。 2、增加历史读取权限 key 的兼容映射,确保存量项目权限覆盖值不会丢失。 3、同步前端权限工具、路由权限与权限管理页面,避免继续引用已合并的旧权限 key。 4、补充项目角色启停保护与抽屉未保存变更守卫,防止停用 PM 或仍有关联成员的角色。
174 lines
7.4 KiB
TypeScript
174 lines
7.4 KiB
TypeScript
import { computed } from "vue";
|
|
import { useAuthStore } from "../store/auth";
|
|
import { useStudyStore } from "../store/study";
|
|
import { TEXT } from "../locales";
|
|
import { getProjectRole, isSystemAdmin } from "./roles";
|
|
import { isApiPermissionAllowed } from "./apiPermissionValue";
|
|
|
|
const PERMISSIONS: Record<string, string[]> = {
|
|
"subject.create": ["ADMIN"],
|
|
"subject.enroll": ["ADMIN"],
|
|
"subject.complete": ["ADMIN"],
|
|
"subject.drop": ["ADMIN"],
|
|
"subject.delete": ["ADMIN"],
|
|
"ae.create": ["ADMIN"],
|
|
"ae.close": ["ADMIN"],
|
|
"faq.edit": ["ADMIN"],
|
|
"faq.update": ["ADMIN"],
|
|
"faq.delete": ["ADMIN"],
|
|
"faq.create": ["ADMIN"],
|
|
"faq.reply": ["ADMIN"],
|
|
"faq.reply.delete": ["ADMIN"],
|
|
"faq.category.read": ["ADMIN"],
|
|
"faq.category.create": ["ADMIN"],
|
|
"faq.category.update": ["ADMIN"],
|
|
"faq.category.delete": ["ADMIN"],
|
|
"precautions.create": ["ADMIN"],
|
|
"precautions.update": ["ADMIN"],
|
|
"precautions.delete": ["ADMIN"],
|
|
"startup.initiation.create": ["ADMIN"],
|
|
"startup.initiation.update": ["ADMIN"],
|
|
"startup.initiation.delete": ["ADMIN"],
|
|
"startup.ethics.create": ["ADMIN"],
|
|
"startup.ethics.update": ["ADMIN"],
|
|
"startup.ethics.delete": ["ADMIN"],
|
|
"startup.auth.create": ["ADMIN"],
|
|
"startup.auth.update": ["ADMIN"],
|
|
"startup.auth.delete": ["ADMIN"],
|
|
"project.milestones.update": ["ADMIN"],
|
|
"project.members.list": ["ADMIN"],
|
|
"project.members.candidates": ["ADMIN"],
|
|
"project.members.create": ["ADMIN"],
|
|
"project.members.update": ["ADMIN"],
|
|
"project.members.delete": ["ADMIN"],
|
|
"site.manage": ["ADMIN"],
|
|
"site.cra.bind": ["ADMIN"],
|
|
"fees.contract.create": ["ADMIN"],
|
|
"fees.contract.update": ["ADMIN"],
|
|
"fees.contract.delete": ["ADMIN"],
|
|
"documents.read": ["ADMIN"],
|
|
"documents.create": ["ADMIN"],
|
|
"documents.update": ["ADMIN"],
|
|
"documents.delete": ["ADMIN"],
|
|
};
|
|
|
|
const REASONS: Record<string, string> = {
|
|
"subject.enroll": TEXT.modules.permissions.subjectEnroll,
|
|
"subject.complete": TEXT.modules.permissions.subjectComplete,
|
|
"subject.drop": TEXT.modules.permissions.subjectDrop,
|
|
"ae.close": TEXT.modules.permissions.aeClose,
|
|
"faq.edit": TEXT.modules.permissions.faqEdit,
|
|
"faq.update": TEXT.modules.permissions.faqEdit,
|
|
"faq.delete": TEXT.modules.permissions.faqEdit,
|
|
"faq.create": TEXT.modules.permissions.faqCreate,
|
|
"faq.reply": TEXT.modules.permissions.faqReply,
|
|
"faq.reply.delete": TEXT.modules.permissions.faqReply,
|
|
"faq.category.read": TEXT.modules.permissions.default,
|
|
"faq.category.create": TEXT.modules.permissions.faqEdit,
|
|
"faq.category.update": TEXT.modules.permissions.faqEdit,
|
|
"faq.category.delete": TEXT.modules.permissions.faqEdit,
|
|
"precautions.create": TEXT.modules.permissions.default,
|
|
"precautions.update": TEXT.modules.permissions.default,
|
|
"precautions.delete": TEXT.modules.permissions.default,
|
|
"startup.initiation.create": TEXT.modules.permissions.default,
|
|
"startup.initiation.update": TEXT.modules.permissions.default,
|
|
"startup.initiation.delete": TEXT.modules.permissions.default,
|
|
"startup.ethics.create": TEXT.modules.permissions.default,
|
|
"startup.ethics.update": TEXT.modules.permissions.default,
|
|
"startup.ethics.delete": TEXT.modules.permissions.default,
|
|
"startup.auth.create": TEXT.modules.permissions.default,
|
|
"startup.auth.update": TEXT.modules.permissions.default,
|
|
"startup.auth.delete": TEXT.modules.permissions.default,
|
|
"project.milestones.update": TEXT.modules.permissions.default,
|
|
"project.members.list": TEXT.modules.permissions.projectMembersManage,
|
|
"project.members.candidates": TEXT.modules.permissions.projectMembersManage,
|
|
"project.members.create": TEXT.modules.permissions.projectMembersManage,
|
|
"project.members.update": TEXT.modules.permissions.projectMembersManage,
|
|
"project.members.delete": TEXT.modules.permissions.projectMembersManage,
|
|
"site.manage": TEXT.modules.permissions.siteManage,
|
|
"site.cra.bind": TEXT.modules.permissions.siteCraBind,
|
|
"fees.contract.create": TEXT.modules.permissions.feeContractsWrite,
|
|
"fees.contract.update": TEXT.modules.permissions.feeContractsWrite,
|
|
"fees.contract.delete": TEXT.modules.permissions.feeContractsWrite,
|
|
"documents.read": TEXT.modules.permissions.default,
|
|
"documents.create": TEXT.modules.permissions.default,
|
|
"documents.update": TEXT.modules.permissions.default,
|
|
"documents.delete": TEXT.modules.permissions.default,
|
|
};
|
|
|
|
export const usePermission = () => {
|
|
const auth = useAuthStore();
|
|
const study = useStudyStore();
|
|
|
|
const systemAdmin = computed(() => isSystemAdmin(auth.user));
|
|
const projectRole = computed(() => getProjectRole(study.currentStudy, study.currentStudyRole));
|
|
const projectPermissions = computed(() => study.currentPermissions);
|
|
|
|
const can = (action: string): boolean => {
|
|
if (systemAdmin.value) return true;
|
|
if (!projectRole.value) return false;
|
|
const permissionMap: Record<string, string> = {
|
|
"subject.create": "subjects:create",
|
|
"subject.enroll": "subjects:update",
|
|
"subject.complete": "subjects:update",
|
|
"subject.drop": "subjects:update",
|
|
"subject.delete": "subjects:delete",
|
|
"ae.create": "subject_aes:create",
|
|
"ae.close": "subject_aes:update",
|
|
"project.overview.read": "project_overview:read",
|
|
"faq.edit": "faq:update",
|
|
"faq.update": "faq:update",
|
|
"faq.delete": "faq:delete",
|
|
"faq.create": "faq:create",
|
|
"faq.reply": "faq_reply:create",
|
|
"faq.reply.delete": "faq_reply:delete",
|
|
"faq.category.read": "faq_category:read",
|
|
"faq.category.create": "faq_category:create",
|
|
"faq.category.update": "faq_category:update",
|
|
"faq.category.delete": "faq_category:delete",
|
|
"precautions.read": "precautions:read",
|
|
"precautions.create": "precautions:create",
|
|
"precautions.update": "precautions:update",
|
|
"precautions.delete": "precautions:delete",
|
|
"startup.initiation.create": "startup_initiation:create",
|
|
"startup.initiation.update": "startup_initiation:update",
|
|
"startup.initiation.delete": "startup_initiation:delete",
|
|
"startup.ethics.create": "startup_ethics:create",
|
|
"startup.ethics.update": "startup_ethics:update",
|
|
"startup.ethics.delete": "startup_ethics:delete",
|
|
"startup.auth.create": "startup_auth:create",
|
|
"startup.auth.update": "startup_auth:update",
|
|
"startup.auth.delete": "startup_auth:delete",
|
|
"project.milestones.update": "project_milestones:update",
|
|
"project.members.list": "project_members:read",
|
|
"project.members.candidates": "project_members:read",
|
|
"project.members.create": "project_members:create",
|
|
"project.members.update": "project_members:update",
|
|
"project.members.delete": "project_members:delete",
|
|
"site.manage": "sites:update",
|
|
"site.cra.bind": "sites:update",
|
|
"fees.contract.create": "fees_contracts:create",
|
|
"fees.contract.update": "fees_contracts:update",
|
|
"fees.contract.delete": "fees_contracts:delete",
|
|
"documents.read": "documents:read",
|
|
"documents.create": "documents:create",
|
|
"documents.update": "documents:update",
|
|
"documents.delete": "documents:delete",
|
|
"audit.export.read": "audit_logs:read",
|
|
};
|
|
const operationKey = permissionMap[action];
|
|
if (!operationKey) return false;
|
|
return isApiPermissionAllowed(projectPermissions.value?.[projectRole.value]?.[operationKey]);
|
|
};
|
|
|
|
const reason = (action: string): string => {
|
|
if (systemAdmin.value) return "";
|
|
return REASONS[action] || TEXT.modules.permissions.default;
|
|
};
|
|
|
|
return {
|
|
can,
|
|
reason,
|
|
};
|
|
};
|