统一项目角色与接口权限配置
This commit is contained in:
@@ -1,21 +1,46 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
import { useRoleTemplateMeta } from "./useRoleTemplateMeta";
|
||||
|
||||
vi.mock("@/api/projectPermissions", () => ({
|
||||
fetchPermissionTemplates: vi.fn().mockResolvedValue({
|
||||
data: [
|
||||
{ category: "PM", name: "PM" },
|
||||
{ category: "CRA", name: "CRA" },
|
||||
{ category: "CTA", name: "CTA" },
|
||||
{ category: "QA", name: "QA" },
|
||||
{ category: "PV", name: "PV" },
|
||||
],
|
||||
}),
|
||||
}));
|
||||
|
||||
const readSource = () => readFileSync(resolve(__dirname, "./useRoleTemplateMeta.ts"), "utf8");
|
||||
|
||||
describe("useRoleTemplateMeta fallback copy", () => {
|
||||
it("uses polished preset role labels and descriptions without introducing QA role key", () => {
|
||||
it("uses QA and CTA as first-class preset role keys", () => {
|
||||
const source = readSource();
|
||||
|
||||
expect(source).toContain('PM: { label: "PM"');
|
||||
expect(source).toContain("项目负责人,统筹项目全局,协调进度、资源与关键决策。");
|
||||
expect(source).toContain("负责各中心临床监查执行,跟进现场质量、数据和问题闭环。");
|
||||
expect(source).toContain("负责合同、药品及相关项目事务管理,保障执行支持与物资协同。");
|
||||
expect(source).toContain('MEDICAL_REVIEW: { label: "QA"');
|
||||
expect(source).toContain('QA: { label: "QA"');
|
||||
expect(source).toContain("负责医学审核与稽查,关注质量风险、合规性和医学一致性。");
|
||||
expect(source).toContain('IMP: { label: "CTA"');
|
||||
expect(source).toContain('CTA: { label: "CTA"');
|
||||
expect(source).toContain("负责药物警戒相关工作,跟踪安全性事件并支持风险评估。");
|
||||
expect(source).not.toContain("QA: {");
|
||||
});
|
||||
|
||||
it("sorts roles by the role template list order", async () => {
|
||||
const { compareRolesByTemplateOrder, loadRoleTemplates } = useRoleTemplateMeta();
|
||||
await loadRoleTemplates();
|
||||
|
||||
expect(["CRA", "PV", "QA", "PM", "CTA"].sort(compareRolesByTemplateOrder)).toEqual([
|
||||
"PM",
|
||||
"CRA",
|
||||
"CTA",
|
||||
"QA",
|
||||
"PV",
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,8 +6,8 @@ const FALLBACK_ROLE_META: Record<string, { label: string; icon: string; desc: st
|
||||
PM: { label: "PM", icon: "👑", desc: "项目负责人,统筹项目全局,协调进度、资源与关键决策。" },
|
||||
CRA: { label: "CRA", icon: "📋", desc: "负责各中心临床监查执行,跟进现场质量、数据和问题闭环。" },
|
||||
PV: { label: "PV", icon: "🔍", desc: "负责药物警戒相关工作,跟踪安全性事件并支持风险评估。" },
|
||||
MEDICAL_REVIEW: { label: "QA", icon: "🏥", desc: "负责医学审核与稽查,关注质量风险、合规性和医学一致性。" },
|
||||
IMP: { label: "CTA", icon: "📦", desc: "负责合同、药品及相关项目事务管理,保障执行支持与物资协同。" },
|
||||
QA: { label: "QA", icon: "🏥", desc: "负责医学审核与稽查,关注质量风险、合规性和医学一致性。" },
|
||||
CTA: { label: "CTA", icon: "📦", desc: "负责合同、药品及相关项目事务管理,保障执行支持与物资协同。" },
|
||||
};
|
||||
|
||||
const templates = ref<PermissionTemplate[]>([]);
|
||||
@@ -47,6 +47,24 @@ export const useRoleTemplateMeta = () => {
|
||||
desc: roleDescription(role),
|
||||
}));
|
||||
|
||||
const roleOrder = computed(() => {
|
||||
const result: Record<string, number> = {};
|
||||
templates.value.forEach((template, index) => {
|
||||
if (template.category && result[template.category] === undefined) {
|
||||
result[template.category] = index;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
});
|
||||
|
||||
const compareRolesByTemplateOrder = (a: string, b: string) => {
|
||||
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;
|
||||
@@ -69,6 +87,7 @@ export const useRoleTemplateMeta = () => {
|
||||
roleDescription,
|
||||
roleIcon,
|
||||
roleOptionsFor,
|
||||
compareRolesByTemplateOrder,
|
||||
loadRoleTemplates,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user