Browse Source

图片和菜单

yangrongze
hanyuqing 4 months ago
parent
commit
0fdc892425
  1. BIN
      vue/src/assets/右侧白色.png
  2. BIN
      vue/src/assets/图标1.png
  3. BIN
      vue/src/assets/图标2.png
  4. BIN
      vue/src/assets/图标3.png
  5. BIN
      vue/src/assets/图标4.png
  6. BIN
      vue/src/assets/左二框.png
  7. BIN
      vue/src/assets/左侧栏.png
  8. BIN
      vue/src/assets/打开.png
  9. BIN
      vue/src/assets/搜索.png
  10. BIN
      vue/src/assets/搜索框.png
  11. BIN
      vue/src/assets/收缩.png
  12. BIN
      vue/src/assets/组 10.png
  13. BIN
      vue/src/assets/退出.png
  14. BIN
      vue/src/assets/选中.png
  15. BIN
      vue/src/assets/鼠标滑过状态.png
  16. 676
      vue/src/components/Menu.vue

BIN
vue/src/assets/右侧白色.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

BIN
vue/src/assets/图标1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

BIN
vue/src/assets/图标2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
vue/src/assets/图标3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

BIN
vue/src/assets/图标4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 903 B

BIN
vue/src/assets/左二框.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
vue/src/assets/左侧栏.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

BIN
vue/src/assets/打开.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 B

BIN
vue/src/assets/搜索.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 678 B

BIN
vue/src/assets/搜索框.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
vue/src/assets/收缩.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 B

BIN
vue/src/assets/组 10.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
vue/src/assets/退出.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 B

BIN
vue/src/assets/选中.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 760 B

BIN
vue/src/assets/鼠标滑过状态.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

676
vue/src/components/Menu.vue

@ -1,428 +1,450 @@
<template> <template>
<div class="sidebar-container" :class="{ 'collapsed': isCollapsed }"> <div class="admin-layout">
<!-- 折叠按钮 --> <aside class="sidebar" :class="{ 'is-collapsed': isCollapsed }">
<button @click="toggleCollapse" class="collapse-btn"> <div class="sidebar-header">
<span class="collapse-icon">{{ isCollapsed ? '▶' : '◀' }}</span> <div class="header-content">
</button> <div class="header-icon-wrap">
<img src="@/assets/logo.png" class="logo-img"/>
<!-- 系统标题区域 --> </div>
<div class="sidebar-header"> <div v-if="!isCollapsed" class="header-text-wrap">
<h1 class="sidebar-title" v-show="!isCollapsed" @click="goToIndex"> <div class="title-line">面向疾病预测的知识图谱</div>
面向疾病预测的知识图谱应用系统 <div class="title-line">应用系统</div>
</h1> </div>
<h1 class="sidebar-title-collapsed" v-show="isCollapsed" @click="goToIndex"> </div>
医疗知识图谱 </div>
</h1>
</div> <nav class="menu-nav">
<div
<!-- 菜单列表 --> v-for="(item, index) in menuItems"
<nav class="sidebar-nav"> :key="index"
<ul> class="menu-item"
<li :class="{ 'is-active': activeIndex === index }"
v-for="(item, index) in menuItems" @click="handleMenuClick(index)"
:key="index"
class="menu-item"
> >
<a <div class="highlight-box">
@click.prevent="handleMenuClick(index)" <div class="menu-content-fixed">
class="menu-link" <div class="menu-icon-wrapper">
:class="{ 'active': activeIndex === index }" <img :src="item.icon" class="menu-icon-img"/>
:title="isCollapsed ? item.name : ''" </div>
> <span v-if="!isCollapsed" class="menu-text">{{ item.name }}</span>
<span class="menu-icon">{{ item.icon }}</span> </div>
<span v-show="!isCollapsed">{{ item.name }}</span> <img v-if="activeIndex === index && !isCollapsed" src="@/assets/右侧白色.png" class="active-tag"/>
</a> </div>
</li> </div>
</ul>
</nav> <div v-if="!isCollapsed" class="collapse-handle" @click="isCollapsed = true">
<img src="@/assets/收缩.png" class="collapse-icon-img"/>
<!-- 底部用户信息和退出登录区域 -->
<div class="sidebar-footer">
<div class="user-info">
<div class="user-avatar">
<span class="avatar-text"></span>
</div> </div>
<div class="user-details" v-show="!isCollapsed"> </nav>
<p class="user-name">管理员</p>
<p class="user-email">admin@example.com</p> <div class="sidebar-footer">
<div v-if="!isCollapsed" class="user-block">
<div class="avatar">用户</div>
<div class="info">
<div class="name">用户名字</div>
<div class="id">8866990099</div>
</div>
<div class="exit-wrap">
<img src="@/assets/退出.png" class="exit-icon" @click="handleLogout" alt="退出"/>
</div>
</div> </div>
<div class="action-buttons" v-show="!isCollapsed"> <div v-else class="expand-handle-circle" @click="isCollapsed = false">
<button @click="handleProfile" class="profile-btn-inline" title="个人主页"> <img src="@/assets/打开.png" class="expand-icon-img-circle"/>
个人主页
</button>
<button @click="handleLogout" class="logout-btn-inline" title="退出登录">
退出登录
</button>
</div> </div>
</div> </div>
</div> </aside>
<main class="main-body">
<header class="top-nav">
<div class="search-container">
<input type="text" placeholder="搜索......"/>
<img src="@/assets/搜索.png" class="search-btn"/>
</div>
<div class="legend-box">
<span v-for="c in ['#ffcc66','#4d79ff','#8cd98c','#ff8100','#6d31ce']" :key="c" class="leg-item">
<i :style="{background: c}"></i> 指定1
</span>
</div>
</header>
<section class="main-content">
<div class="disease-container">
<div class="disease-header">
<div class="d-title"><img src="@/assets/组 10.png" class="d-icon"/><span>疾病信息</span></div>
<div class="d-count">12</div>
</div>
<div class="disease-body">
<div class="checkbox-list">
<label v-for="i in ['选项一','选项二','选项三']" :key="i">
<input type="checkbox"/><span class="label-text">{{ i }}</span>
</label>
</div>
</div>
</div>
<div class="graph-viewport">
<div class="empty-hint">知识图谱可视化区域</div>
</div>
</section>
</main>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, defineProps, defineEmits } from 'vue'; import {ref} from 'vue';
import { useRouter } from 'vue-router'; import {useRouter} from 'vue-router';
import i1 from '@/assets/图标1.png';
import i2 from '@/assets/图标2.png';
import i3 from '@/assets/图标3.png';
import i4 from '@/assets/图标4.png';
const router = useRouter(); const router = useRouter();
const activeIndex = ref(0);
//
const props = defineProps({
//
initialActive: {
type: Number,
default: 0
}
});
//
const emit = defineEmits(['menu-click']);
//
const menuItems = ref([
{
name: '医疗知识图谱',
path: '/kg-display',
icon: '🏥',
},
{
name: '知识图谱构建',
path: '/kg-construction',
icon: '🔧'
},
{
name: '知识图谱问答',
path: '/kg-qa',
icon: '💬'
},
{
name: '知识图谱数据',
path: '/kg-data',
icon: '📊'
}
]);
//
const activeIndex = ref(props.initialActive);
//
const isCollapsed = ref(false); const isCollapsed = ref(false);
// const menuItems = [
const toggleCollapse = () => { {name: '医疗知识图谱', path: '/kg-display', icon: i1},
isCollapsed.value = !isCollapsed.value; {name: '知识图谱构建', path: '/kg-construction', icon: i2},
}; {name: '知识图谱问答', path: '/kg-qa', icon: i3},
{name: '知识图谱数据', path: '/kg-data', icon: i4}
// ];
const handleMenuClick = (index) => {
activeIndex.value = index;
emit('menu-click', menuItems.value[index]);
const item = menuItems.value[index];
if (item.path) {
router.push(item.path); // 👈
}
};
//
const handleProfile = () => {
// 使Vue Router
router.push('/profile');
};
// 退 const handleMenuClick = (i) => {
const handleLogout = () => { activeIndex.value = i;
// 使Vue Router router.push(menuItems[i].path);
router.push('/login');
};
//
const goToIndex = () => {
router.push('/index');
}; };
const handleLogout = () => console.log('logout');
</script> </script>
<style scoped> <style scoped>
.sidebar-container { .admin-layout {
width: 240px; display: flex;
width: 100vw;
height: 100vh; height: 100vh;
background-color: #1e40af; background: #fff;
color: white; overflow: hidden;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
-webkit-font-smoothing: antialiased;
}
/* --- 侧边栏 --- */
.sidebar {
width: 200px;
height: 100%;
background: #0a2463;
flex-shrink: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: relative; position: relative;
transition: width 0.3s ease; transition: width 0.3s;
z-index: 100;
} }
.sidebar-container.collapsed { .sidebar.is-collapsed {
width: 60px; width: 64px;
} }
.collapse-btn { .sidebar-header {
position: absolute; padding: 30px 0 20px 0;
top: 50%; border-bottom: 1px solid rgba(255, 255, 255, 0.08);
right: -15px;
width: 30px;
height: 30px;
background-color: #1e40af;
border: 2px solid white;
border-radius: 50%;
color: white;
cursor: pointer;
display: flex; display: flex;
align-items: center;
justify-content: center; justify-content: center;
z-index: 100;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
transform: translateY(-50%);
} }
.collapse-btn:hover { .header-content {
background-color: #1e3a8a; display: flex;
align-items: center;
gap: 10px;
width: fit-content;
} }
.collapse-icon { .header-icon-wrap {
font-size: 14px; width: 32px;
line-height: 1; height: 32px;
background: #165dff;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
overflow: hidden;
} }
.sidebar-header { .logo-img {
padding: 1.25rem; width: 22px;
border-bottom: 1px solid #1e3a8a; height: 22px;
object-fit: contain;
} }
.sidebar-title { .header-text-wrap {
font-size: 1.25rem; display: flex;
font-weight: bold; flex-direction: column;
letter-spacing: -0.025em; text-align: left;
transition: opacity 0.3s ease;
cursor: pointer;
} }
.sidebar-title:hover { .title-line {
color: #93c5fd; color: #fff;
font-size: 12px;
font-weight: 600;
line-height: 1.25;
white-space: nowrap;
} }
.sidebar-title-collapsed { /* --- 菜单导航 --- */
font-size: 0.75rem; .menu-nav {
font-weight: bold; flex: 1;
text-align: center; padding-top: 10px;
margin: 0; position: relative;
padding: 0.5rem 0; }
writing-mode: vertical-rl;
text-orientation: mixed; .menu-item {
height: 42px;
display: flex;
align-items: center;
cursor: pointer; cursor: pointer;
padding: 0 8px;
margin-bottom: 2px;
} }
.sidebar-title-collapsed:hover { .highlight-box {
color: #93c5fd; width: calc(100% - 16px);
margin: 0 auto;
height: 36px;
border-radius: 6px;
display: flex;
align-items: center;
position: relative;
transition: all 0.2s;
padding-left: 8px;
} }
.sidebar-nav { .menu-item.is-active .highlight-box {
flex: 1; background: #165dff !important;
overflow-y: auto;
padding: 1rem 0;
} }
.sidebar-nav ul { .menu-item:hover .highlight-box {
padding-left: 0; background: rgba(255, 255, 255, 0.08);
margin: 0;
} }
.menu-item { .menu-content-fixed {
margin-bottom: 0.25rem; display: flex;
list-style-type: none; align-items: center;
white-space: nowrap;
overflow: hidden;
width: 100%;
} }
.menu-link { .menu-icon-wrapper {
width: 20px;
height: 20px;
background: transparent;
border-radius: 4px;
display: flex; display: flex;
align-items: center; align-items: center;
padding: 0.75rem 1.25rem; justify-content: center;
color: white; flex-shrink: 0;
text-decoration: none;
transition: background-color 0.2s;
font-size: 1.1rem;
} }
.menu-link:hover { .menu-icon-img {
background-color: #1e3a8a; width: 14px;
height: auto;
object-fit: contain;
} }
.menu-link.active { .menu-item:hover .menu-icon-wrapper {
background-color: #1e3a8a; background: rgba(255, 255, 255, 0.25) !important;
border-left: 4px solid #60a5fa;
} }
.menu-icon { .menu-item.is-active .menu-icon-wrapper {
margin-right: 0.75rem; background: #457dff !important;
color: #93c5fd;
font-size: 1.4rem;
transition: margin 0.3s ease;
} }
.sidebar-container.collapsed .menu-icon { .menu-text {
margin-right: 0; color: rgba(255, 255, 255, 0.9);
justify-content: center; font-size: 14px;
display: flex; margin-left: 10px;
font-weight: 400;
}
.active-tag {
position: absolute;
right: 8px;
height: 18px;
}
.collapse-handle {
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
} }
.menu-link:hover .menu-icon { .collapse-icon-img {
color: white; width: 14px;
} }
/* --- 用户区域 (重点修改) --- */
.sidebar-footer { .sidebar-footer {
padding: 1rem; padding: 12px 0 20px 0;
border-top: 1px solid #1e3a8a; border-top: 1px solid rgba(255, 255, 255, 0.1);
} }
.user-info { .user-block {
display: flex; display: flex;
align-items: center; align-items: center;
position: relative; padding: 0 12px;
justify-content: center;
padding: 0.5rem 0;
} }
.sidebar-container.collapsed .user-info { .avatar {
flex-direction: column; width: 42px;
height: 42px;
background: rgba(255, 255, 255, 0.15);
border-radius: 50%;
font-size: 12px;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
} }
.action-buttons { .info {
position: absolute; margin-left: 12px;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
opacity: 0; justify-content: center;
transition: opacity 0.3s ease, bottom 0.3s ease;
background-color: white;
border-radius: 8px;
padding: 8px 0;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
margin-bottom: 10px;
min-width: 120px;
} }
.user-info:hover .action-buttons { .info .name {
opacity: 1; font-size: 12px;
bottom: 100%; color: #fff;
line-height: 1;
} }
.user-avatar { .info .id {
width: 2rem; font-size: 9px;
height: 2rem; color: rgba(255, 255, 255, 0.35);
border-radius: 50%; line-height: 1;
background-color: #274eb8; margin-top: 8px; /* 通过增加上边距让id向下移动 */
}
.exit-wrap {
margin-left: auto;
display: flex; display: flex;
align-items: center; align-items: center;
}
.exit-icon {
width: 16px;
cursor: pointer;
opacity: 0.8;
}
.expand-handle-circle {
display: flex;
justify-content: center; justify-content: center;
margin-right: 0.75rem; padding-bottom: 20px;
cursor: pointer;
} }
.avatar-text { .expand-icon-img-circle {
font-size: 0.875rem; width: 32px;
height: 32px;
} }
.user-details { /* --- 主体区域 --- */
.main-body {
flex: 1; flex: 1;
display: flex;
flex-direction: column;
background: #fff;
} }
.user-name { .top-nav {
font-size: 0.875rem; height: 75px;
font-weight: 500; padding: 0 30px;
margin: 0; display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #f0f0f0;
} }
.user-email { .search-container {
font-size: 0.75rem; width: 260px;
color: #93c5fd; height: 36px;
margin: 0; background: #f5f7fa;
border-radius: 18px;
display: flex;
align-items: center;
padding: 0 15px;
} }
/* 退出登录按钮样式 */ .search-container input {
.profile-btn-inline, .logout-btn-inline {
background: transparent;
border: none; border: none;
color: #333; outline: none;
cursor: pointer; background: transparent;
padding: 10px 16px;
transition: all 0.2s;
display: block;
width: 100%; width: 100%;
text-align: left; font-size: 13px;
font-size: 14px; }
.search-btn {
width: 16px;
}
.legend-box {
display: flex;
gap: 20px;
}
.leg-item {
display: flex;
align-items: center;
font-size: 13px;
}
.leg-item i {
width: 24px;
height: 8px;
border-radius: 4px;
margin-right: 8px;
} }
.profile-btn-inline:hover, .logout-btn-inline:hover { .main-content {
background-color: #f5f7fa; flex: 1;
color: #1e40af; padding: 20px 30px;
} display: flex;
gap: 20px;
.profile-icon, .logout-icon { }
font-size: 1.2rem;
} .disease-container {
width: 360px;
/* 响应式调整 */ border: 1px solid #f0f0f0;
@media (max-width: 768px) { border-radius: 12px;
.sidebar-container { overflow: hidden;
width: 70px; }
}
.disease-header {
.sidebar-container.collapsed { height: 50px;
width: 60px; background: #2265f4;
} color: #fff;
display: flex;
.collapse-btn { align-items: center;
right: -10px; justify-content: space-between;
width: 25px; padding: 0 15px;
height: 25px; }
}
.d-icon {
.sidebar-title, width: 18px;
.sidebar-title-collapsed, margin-right: 8px;
.menu-link span:not(.menu-icon), }
.user-details {
display: none; .graph-viewport {
} flex: 1;
border: 1px dashed #e2e8f0;
.menu-link { border-radius: 12px;
justify-content: center; display: flex;
padding: 0.5rem; align-items: center;
} justify-content: center;
color: #ccc;
.menu-icon {
margin-right: 0;
font-size: 1.2rem;
}
.menu-link.active {
border-left-width: 2px;
}
.action-buttons {
position: static;
opacity: 1;
transform: none;
background-color: transparent;
padding: 0;
box-shadow: none;
margin-top: 0.5rem;
flex-direction: row;
justify-content: center;
min-width: auto;
}
.user-info:hover .action-buttons {
bottom: auto;
}
.profile-btn-inline, .logout-btn-inline {
padding: 6px 8px;
font-size: 12px;
margin: 0 2px;
display: inline-block;
width: auto;
}
} }
</style> </style>
Loading…
Cancel
Save