41968384b5
1、为后台用户列表增加关键词和状态筛选,后端同步支持过滤与总数统计。 2、创建用户时要求填写初始密码,并补充前端校验和自动填充隔离。 3、优化项目管理列表角色展示、项目详情抽屉脏数据保护和审计详情抽屉关闭体验。 4、清理旧费用附件关联、统一测试模型注册,并更新迁移端点和注册筛选测试。
96 lines
4.8 KiB
TypeScript
96 lines
4.8 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { readFileSync } from "node:fs";
|
|
import { resolve } from "node:path";
|
|
|
|
const readProjects = () => readFileSync(resolve(__dirname, "./Projects.vue"), "utf8");
|
|
const readRouter = () => readFileSync(resolve(__dirname, "../../router/index.ts"), "utf8");
|
|
const readLayout = () => readFileSync(resolve(__dirname, "../../components/Layout.vue"), "utf8");
|
|
|
|
describe("project management access", () => {
|
|
it("shows project management to all signed-in users while keeping system operations admin-only", () => {
|
|
const projects = readProjects();
|
|
const layout = readLayout();
|
|
const router = readRouter();
|
|
|
|
expect(layout).toContain('v-if="auth.user"');
|
|
expect(layout).toContain('index="/admin/projects"');
|
|
expect(router).toContain('name: "AdminProjects"');
|
|
expect(router).toContain("meta: { title: TEXT.menu.projectManagement }");
|
|
expect(projects).toContain('v-if="isAdmin" type="primary"');
|
|
expect(projects).toContain('v-if="isAdmin && !scope.row.is_locked"');
|
|
expect(projects).toContain('v-if="isAdmin" :content="TEXT.common.actions.delete"');
|
|
});
|
|
|
|
it("keeps management backend modules under the project management page instead of sidebar shortcuts", () => {
|
|
const layout = readLayout();
|
|
|
|
expect(layout).not.toContain("canAccessPmAdminBackend");
|
|
expect(layout).not.toContain("canAccessPmAdminModule");
|
|
expect(layout).not.toContain("TEXT.modules.adminProjectMembers.memberLabel");
|
|
expect(layout).toContain('index="/admin/projects"');
|
|
});
|
|
|
|
it("removes the non-admin personal dashboard menu entry", () => {
|
|
const layout = readLayout();
|
|
const removedPath = `/${["work", "bench"].join("")}`;
|
|
const removedMenuKey = ["TEXT.menu.work", "bench"].join("");
|
|
|
|
expect(layout).not.toContain(`index="${removedPath}"`);
|
|
expect(layout).not.toContain(removedMenuKey);
|
|
});
|
|
|
|
it("uses each project permission matrix to show project management actions", () => {
|
|
const source = readProjects();
|
|
|
|
expect(source).toContain("fetchMyApiEndpointPermissions(item.id, { suppressErrorMessage: true })");
|
|
expect(source).toContain("permissionsByProject");
|
|
expect(source).toContain("suppressErrorMessage: true");
|
|
expect(source).toContain("const canProject = (row: Study, module: string, action: \"read\" | \"write\")");
|
|
expect(source).toContain("canProject(scope.row, 'project_members', 'read')");
|
|
expect(source).toContain("canProject(scope.row, 'project_members', 'write')");
|
|
expect(source).toContain("canProject(scope.row, 'sites', 'read')");
|
|
expect(source).toContain("canProject(scope.row, 'audit_export', 'read')");
|
|
});
|
|
|
|
it("shows the current project role only for non-admin project lists", () => {
|
|
const source = readProjects();
|
|
|
|
expect(source).toContain('v-if="!isAdmin" label="我的角色" align="center"');
|
|
expect(source).toContain("roleLabel(scope.row.role_in_study) || '-'");
|
|
expect(source).toContain("const { roleLabel, loadRoleTemplates } = useRoleTemplateMeta();");
|
|
expect(source).toContain("loadRoleTemplates().catch(() => {});");
|
|
});
|
|
|
|
it("keeps project table columns evenly spaced after adding the role column", () => {
|
|
const source = readProjects();
|
|
|
|
expect(source).toContain('class="project-table" style="width: 100%" table-layout="fixed"');
|
|
expect(source).toContain(':label="TEXT.common.fields.projectName"');
|
|
expect(source).toContain(`:label="TEXT.common.fields.protocolNo || '方案号'" show-overflow-tooltip`);
|
|
expect(source).toContain(':label="TEXT.common.fields.status" align="center"');
|
|
expect(source).toContain('label="锁定状态" align="center"');
|
|
expect(source).toContain(':label="TEXT.common.labels.actions" align="center"');
|
|
expect(source).not.toContain('projectColumnWidth');
|
|
expect(source).not.toContain('fixed="right"');
|
|
});
|
|
|
|
it("opens project names in management detail when the user has setup config read permission", () => {
|
|
const source = readProjects();
|
|
|
|
expect(source).toContain("v-if=\"canProject(scope.row, 'setup_config', 'read')\"");
|
|
expect(source).toContain('@click="goProject(scope.row)" class="project-name"');
|
|
expect(source).toContain('@click="enterStudy(scope.row)"');
|
|
expect(source).toContain('if (!canProject(row, "setup_config", "read"))');
|
|
});
|
|
|
|
it("keeps audit export write mappings on the export operation", () => {
|
|
const projects = readProjects();
|
|
const router = readRouter();
|
|
|
|
expect(projects).toContain('audit_export: { read: "audit_logs:read", write: "audit_logs:export" }');
|
|
expect(router).toContain('audit_export: { read: "audit_logs:read", write: "audit_logs:export" }');
|
|
expect(projects).not.toContain('audit_export: { read: "audit_logs:read", write: "audit_logs:read" }');
|
|
expect(router).not.toContain('audit_export: { read: "audit_logs:read", write: "audit_logs:read" }');
|
|
});
|
|
});
|