RMO-Front/src/components/DashboardLayout.vue

158 lines
7.6 KiB
Vue

<template>
<div class="dashboard-layout">
<aside :class="['dashboard-sidebar', sidebarOpen ? 'open' : 'closed']">
<div class="sidebar-header">
<RouterLink to="/dashboard" class="sidebar-logo">
<h2>RMO</h2>
<span>工作台</span>
</RouterLink>
<button type="button" class="sidebar-toggle" @click="sidebarOpen = !sidebarOpen" aria-label="切换侧边栏">
{{ sidebarOpen ? '◀' : '▶' }}
</button>
</div>
<nav class="sidebar-nav">
<RouterLink
to="/dashboard"
:class="['nav-item', isDashboardHome ? 'active' : '']"
>
<span class="nav-icon">📊</span>
<span v-show="sidebarOpen" class="nav-text">工作台</span>
</RouterLink>
<template v-if="isPolicyholder">
<RouterLink to="/dashboard/project-quotes" :class="['nav-item', { active: isActiveParent('/dashboard/project-quotes') }]">
<span class="nav-icon">💰</span>
<span v-show="sidebarOpen" class="nav-text">项目报价</span>
</RouterLink>
<RouterLink to="/dashboard/projects" :class="['nav-item', { active: isActiveParent('/dashboard/projects') }]">
<span class="nav-icon">📋</span>
<span v-show="sidebarOpen" class="nav-text">项目列表</span>
</RouterLink>
</template>
<template v-if="isInsurer">
<RouterLink to="/dashboard/inquiries" :class="['nav-item', { active: isActiveParent('/dashboard/inquiries') }]">
<span class="nav-icon">💼</span>
<span v-show="sidebarOpen" class="nav-text">询价列表</span>
</RouterLink>
</template>
<template v-if="isPolicyholder || isInsurer">
<RouterLink to="/dashboard/claims" :class="['nav-item', { active: isActiveParent('/dashboard/claims') }]">
<span class="nav-icon">📝</span>
<span v-show="sidebarOpen" class="nav-text">理赔进度</span>
</RouterLink>
</template>
<div class="nav-group">
<div :class="['nav-item', { active: isActiveParent('/dashboard/tools') }]">
<span class="nav-icon">🛠️</span>
<span v-show="sidebarOpen" class="nav-text">智能工具</span>
</div>
<div v-show="isActiveParent('/dashboard/tools')" class="nav-submenu">
<RouterLink to="/dashboard/tools/premium-calculator" :class="['nav-subitem', { active: route.path === '/dashboard/tools/premium-calculator' }]">保费测算工具</RouterLink>
<RouterLink v-if="isPolicyholder" to="/dashboard/tools/icf-editor" :class="['nav-subitem', { active: route.path === '/dashboard/tools/icf-editor' }]">ICF智能修改</RouterLink>
<RouterLink v-if="isPolicyholder" to="/dashboard/tools/risk-scoring" :class="['nav-subitem', { active: route.path === '/dashboard/tools/risk-scoring' }]">方案风险评分</RouterLink>
<RouterLink to="/dashboard/tools/protocol-risk" :class="['nav-subitem', { active: route.path === '/dashboard/tools/protocol-risk' }]">方案风险评估</RouterLink>
<RouterLink to="/dashboard/tools/drug-safety" :class="['nav-subitem', { active: route.path === '/dashboard/tools/drug-safety' }]">药安查</RouterLink>
</div>
</div>
</nav>
</aside>
<div class="dashboard-main">
<header class="dashboard-header">
<div class="header-left">
<RouterLink to="/" class="header-logo">
<h2>RMO</h2>
<span>生命科学风险管理</span>
</RouterLink>
<nav class="header-nav">
<RouterLink to="/" :class="{ active: route.path === '/' }">首页</RouterLink>
<div class="nav-dropdown" @mouseenter="concernMenuOpen = true" @mouseleave="concernMenuOpen = false">
<RouterLink to="/concern" :class="{ active: isActiveParentMulti(concernPaths) }">风险职责</RouterLink>
<div v-show="concernMenuOpen" class="dropdown-menu">
<RouterLink to="/sponsor">申办者职责</RouterLink>
<RouterLink to="/holder">持有人职责</RouterLink>
<RouterLink to="/participant">受试者专区</RouterLink>
<RouterLink to="/institution">研究中心</RouterLink>
<RouterLink to="/service-provider">CXO职责</RouterLink>
</div>
</div>
<div class="nav-dropdown" @mouseenter="rmoMenuOpen = true" @mouseleave="rmoMenuOpen = false">
<RouterLink to="/rmo-mode" :class="{ active: isActiveParentMulti(rmoPaths) }">临床试验</RouterLink>
<div v-show="rmoMenuOpen" class="dropdown-menu">
<RouterLink to="/rmo-mode/insurance">保险方案</RouterLink>
<RouterLink to="/rmo-mode/guarantee">保证方案</RouterLink>
<RouterLink to="/rmo-mode/insurance-guarantee">保险保证</RouterLink>
</div>
</div>
<RouterLink to="/post-market" :class="{ active: route.path.startsWith('/post-market') }">上市应用</RouterLink>
<RouterLink to="/overseas" :class="{ active: route.path === '/overseas' }">海外风险</RouterLink>
<div class="nav-dropdown" @mouseenter="systemMenuOpen = true" @mouseleave="systemMenuOpen = false">
<RouterLink to="/system-management" :class="{ active: isActiveParentMulti(systemPaths) }">资源中心</RouterLink>
<div v-show="systemMenuOpen" class="dropdown-menu">
<RouterLink to="/system-management/laws">法律法规</RouterLink>
<RouterLink to="/system-management/practice-guide">实践指南</RouterLink>
<RouterLink to="/system-management/training">培训材料</RouterLink>
<RouterLink to="/system-management/faq">常见问题</RouterLink>
</div>
</div>
</nav>
</div>
<div class="header-right">
<div class="user-info">
<span class="user-name">{{ auth.user?.name }}</span>
<span class="user-role">{{ auth.user?.role }}</span>
</div>
<button type="button" class="logout-btn" @click="handleLogout">退出登录</button>
</div>
</header>
<main class="dashboard-content">
<Breadcrumb />
<RouterView />
</main>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import Breadcrumb from './Breadcrumb.vue'
const route = useRoute()
const router = useRouter()
const auth = useAuthStore()
const sidebarOpen = ref(true)
const rmoMenuOpen = ref(false)
const concernMenuOpen = ref(false)
const systemMenuOpen = ref(false)
const concernPaths = ['/concern', '/sponsor', '/holder', '/institution', '/service-provider', '/participant']
const rmoPaths = ['/rmo-mode', '/insurance', '/guarantee', '/insurance-guarantee']
const systemPaths = ['/system-management', '/faq']
const isPolicyholder = computed(() => auth.user?.role === '投保人')
const isInsurer = computed(() => auth.user?.role === '保险人')
const isDashboardHome = computed(() =>
route.path === '/dashboard' &&
!['/dashboard/projects', '/dashboard/project-quotes', '/dashboard/inquiries', '/dashboard/claims', '/dashboard/tools'].some(p => route.path.startsWith(p))
)
function isActiveParent(path: string) {
return route.path.startsWith(path)
}
function isActiveParentMulti(paths: string[]) {
return paths.some(p => route.path.startsWith(p))
}
function handleLogout() {
auth.logout()
router.push('/login')
}
</script>
<style scoped>
@import './DashboardLayout.css';
</style>