feat(admin): 完善审计访问上下文与后台布局
This commit is contained in:
@@ -59,7 +59,7 @@
|
||||
</el-sub-menu>
|
||||
</el-menu-item-group>
|
||||
|
||||
<el-menu-item-group v-if="study.currentStudy && hasAnyProjectModuleAccess" class="menu-group">
|
||||
<el-menu-item-group v-if="hasProjectContext && hasAnyProjectModuleAccess" class="menu-group">
|
||||
<template #title>
|
||||
<span class="menu-divider">{{ TEXT.menu.currentProject }}</span>
|
||||
</template>
|
||||
@@ -204,7 +204,7 @@
|
||||
</div>
|
||||
|
||||
<div class="header-right">
|
||||
<button v-if="study.currentStudy" class="workbench-return-button" type="button" @click="openWorkbenchEntry">
|
||||
<button v-if="hasProjectContext" class="workbench-return-button" type="button" @click="openWorkbenchEntry">
|
||||
<el-icon><Suitcase /></el-icon>
|
||||
<span>工作台</span>
|
||||
</button>
|
||||
@@ -468,6 +468,8 @@ const headerReminderStats = ref({
|
||||
const headerClockNow = ref(new Date());
|
||||
let headerClockTimer: number | undefined;
|
||||
let desktopMenuUnlisten: (() => void) | undefined;
|
||||
const isAdminContext = computed(() => route.path.startsWith("/admin"));
|
||||
const hasProjectContext = computed(() => Boolean(study.currentStudy) && !isAdminContext.value);
|
||||
|
||||
/* 动态设置 body 上的侧边栏宽度 CSS 变量,用于全局弹窗定位偏移 */
|
||||
const hasSidebar = computed(() => isAdmin.value || !!study.currentStudy);
|
||||
@@ -489,10 +491,9 @@ const userDisplayInitial = computed(() => {
|
||||
return source.charAt(0).toUpperCase();
|
||||
});
|
||||
|
||||
const isAdminContext = computed(() => route.path.startsWith("/admin"));
|
||||
const showAdminNavigation = computed(() => Boolean(auth.user) && (!study.currentStudy || isAdminContext.value));
|
||||
const canReadRiskIssueAes = computed(() => !isAdminContext.value && canAccessProjectPath("/risk-issues/sae"));
|
||||
const canReadMonitoringIssues = computed(() => !isAdminContext.value && canAccessProjectPath("/risk-issues/monitoring-visits"));
|
||||
const showAdminNavigation = computed(() => Boolean(auth.user) && !hasProjectContext.value);
|
||||
const canReadRiskIssueAes = computed(() => hasProjectContext.value && canAccessProjectPath("/risk-issues/sae"));
|
||||
const canReadMonitoringIssues = computed(() => hasProjectContext.value && canAccessProjectPath("/risk-issues/monitoring-visits"));
|
||||
const hasAnyRiskReminderAccess = computed(() => canReadRiskIssueAes.value || canReadMonitoringIssues.value);
|
||||
|
||||
const toHeaderNumber = (value: unknown) => {
|
||||
@@ -518,7 +519,7 @@ const headerClockText = computed(() => formatHeaderDateTime(headerClockNow.value
|
||||
|
||||
const loadHeaderOverviewStats = async () => {
|
||||
const studyId = study.currentStudy?.id;
|
||||
if (!studyId || isAdminContext.value) {
|
||||
if (!studyId || !hasProjectContext.value) {
|
||||
headerOverviewStats.value = null;
|
||||
return;
|
||||
}
|
||||
@@ -541,7 +542,7 @@ const loadHeaderOverviewStats = async () => {
|
||||
|
||||
const loadHeaderReminders = async () => {
|
||||
const studyId = study.currentStudy?.id;
|
||||
if (!studyId || isAdminContext.value || !hasAnyRiskReminderAccess.value) {
|
||||
if (!studyId || !hasProjectContext.value || !hasAnyRiskReminderAccess.value) {
|
||||
headerReminderStats.value = { overdueAes: 0, overdueMonitoringIssues: 0 };
|
||||
return;
|
||||
}
|
||||
@@ -602,7 +603,7 @@ const headerReminderBadgeValue = computed(() =>
|
||||
|
||||
// 顶栏中间区:项目上下文(状态 + 关键进度 + 数据时间)
|
||||
const headerProjectInfo = computed(() => {
|
||||
if (isAdminContext.value || !study.currentStudy) return null;
|
||||
if (!hasProjectContext.value || !study.currentStudy) return null;
|
||||
const s = study.currentStudy;
|
||||
const status = (s.status || "").toUpperCase();
|
||||
const statusLabel = (TEXT.enums.projectStatus as Record<string, string>)[status] || s.status || "";
|
||||
@@ -640,7 +641,7 @@ const headerProjectInfo = computed(() => {
|
||||
});
|
||||
|
||||
const accountProjectRoleLabel = computed(() => {
|
||||
if (isAdminContext.value || !study.currentStudy) return "";
|
||||
if (!hasProjectContext.value || !study.currentStudy) return "";
|
||||
const roleCode = (projectRole.value || "").toUpperCase();
|
||||
return roleCode ? ((TEXT.enums.userRole as Record<string, string>)[roleCode] || projectRole.value) : "";
|
||||
});
|
||||
@@ -673,7 +674,7 @@ const desktopNavigationItems = computed<DesktopNavigationItem[]>(() => {
|
||||
}
|
||||
}
|
||||
|
||||
if (study.currentStudy && hasAnyProjectModuleAccess.value) {
|
||||
if (hasProjectContext.value && hasAnyProjectModuleAccess.value) {
|
||||
const projectItems: DesktopNavigationItem[] = [
|
||||
{ label: TEXT.menu.projectOverview, path: "/project/overview", group: TEXT.menu.currentProject, keywords: ["overview"] },
|
||||
{ label: TEXT.menu.projectMilestones, path: "/project/milestones", group: TEXT.menu.currentProject, keywords: ["milestone"] },
|
||||
@@ -896,7 +897,7 @@ const breadcrumbs = computed(() => {
|
||||
});
|
||||
return items;
|
||||
}
|
||||
} else if (study.currentStudy) {
|
||||
} else if (hasProjectContext.value && study.currentStudy) {
|
||||
// 项目内不提供横向切换项目;需要切换时先回工作台重新选择。
|
||||
items.push({
|
||||
label: (study.currentStudy.name || "").replace(/^示例项目[::]/, ''),
|
||||
|
||||
Reference in New Issue
Block a user