import { computed, ref } from "vue"; import { fetchPermissionTemplates, type PermissionTemplate } from "@/api/projectPermissions"; import { compareProjectPermissionRoles } from "@/utils/projectPermissionRoles"; const FALLBACK_ROLE_META: Record = { ADMIN: { label: "管理员", icon: "🛡️", desc: "系统管理员" }, PM: { label: "PM", icon: "👑", desc: "项目负责人,统筹项目全局,协调进度、资源与关键决策。" }, CRA: { label: "CRA", icon: "📋", desc: "负责各中心临床监查执行,跟进现场质量、数据和问题闭环。" }, PV: { label: "PV", icon: "🔍", desc: "负责药物警戒相关工作,跟踪安全性事件并支持风险评估。" }, QA: { label: "QA", icon: "🏥", desc: "负责医学审核与稽查,关注质量风险、合规性和医学一致性。" }, CTA: { label: "CTA", icon: "📦", desc: "负责合同、药品及相关项目事务管理,保障执行支持与物资协同。" }, }; const templates = ref([]); const loading = ref(false); let pendingLoad: Promise | null = null; export const useRoleTemplateMeta = () => { const templateByRole = computed(() => { const result: Record = {}; for (const template of templates.value) { if (template.category) result[template.category] = template; } return result; }); const roleLabel = (role?: string | null) => { if (!role) return ""; return templateByRole.value[role]?.name || FALLBACK_ROLE_META[role]?.label || role; }; const roleDescription = (role?: string | null) => { if (!role) return ""; return templateByRole.value[role]?.description || FALLBACK_ROLE_META[role]?.desc || "自定义项目角色"; }; const roleIcon = (role?: string | null) => { if (!role) return "🔧"; return FALLBACK_ROLE_META[role]?.icon || "🔧"; }; const roleOptionsFor = (roles: string[]) => roles.map((role) => ({ value: role, key: role, label: roleLabel(role), icon: roleIcon(role), desc: roleDescription(role), })); const roleOrder = computed(() => { const result: Record = {}; templates.value.forEach((template, index) => { if (template.category && result[template.category] === undefined) { result[template.category] = index; } }); return result; }); const compareRolesByTemplateOrder = (a: string, b: string) => { if (a === "PM" || b === "PM") return compareProjectPermissionRoles(a, b); const order = roleOrder.value; const aOrder = order[a] ?? Number.MAX_SAFE_INTEGER; const bOrder = order[b] ?? Number.MAX_SAFE_INTEGER; if (aOrder !== bOrder) return aOrder - bOrder; return a.localeCompare(b); }; const loadRoleTemplates = async () => { if (pendingLoad) return pendingLoad; loading.value = true; pendingLoad = fetchPermissionTemplates() .then((res) => { templates.value = res.data; }) .finally(() => { loading.value = false; pendingLoad = null; }); return pendingLoad; }; return { templates, loading, templateByRole, roleLabel, roleDescription, roleIcon, roleOptionsFor, compareRolesByTemplateOrder, loadRoleTemplates, }; };