158 lines
7.6 KiB
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>
|