Files
bio_frontend/layouts/default.vue
2025-08-22 14:01:30 +09:00

233 lines
5.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import AppHeader from "../components/layout/AppHeader.vue";
import { ref, computed, watch } from "vue";
import { useRouter } from "vue-router";
import { useTabsStore } from "../stores/tab";
const router = useRouter();
const activeMenu = ref("home");
const showSubmenuBar = ref(false);
const tabsStore = useTabsStore();
// 메뉴 클릭 시 홈 이동
watch(activeMenu, (newValue) => {
if (newValue === "home") router.push("/");
});
// 서브메뉴 정의
const subMenus = computed(() => {
if (activeMenu.value === "test") {
return [{
key: "test",
label: "테스트",
to: "/test/test01"
}, {
key: "igv",
label: "ivg",
to: "/test/test02"
}, {
key: "igv2",
label: "ivg2",
to: "/test/igv2"
}, {
key: "pathway",
label: "pathway",
to: "/test/pathway"
}, {
key: "pathway2",
label: "pathway2",
to: "/test/pathway2"
}, {
key: "pathway3",
label: "pathway3",
to: "/test/pathway3"
}, {
key: "pathway4",
label: "pathway4",
to: "/cultureGraph/pathway4"
}, {
key: "pathwayjson",
label: "pathwayjson",
to: "/test/pathwayjson"
}, {
key: "cultureGraph",
label: "배양그래프",
to: "/test/culture-graph"
}, {
key: "cultureGraphMulti",
label: "배양그래프 멀티",
to: "/test/culture-graph-multi"
}, {
key: "cultureGraphTab",
label: "배양그래프 탭",
to: "/test/culture-graph-tab"
}, {
key: "tui-grid",
label: "tui-grid",
to: "/tui"
}, {
key: "리소스",
label: "리소스",
to: "/admin/resource"
}, {
key: "sample",
label: "sample",
to: "/sampleList"
}, ];
} else if (activeMenu.value === "ADMIN") {
return [{
key: "logs",
label: "접속기록",
to: "/admin/logs"
}, {
key: "codes",
label: "공통코드",
to: "/admin/codes"
}, {
key: "programs",
label: "프로그램",
to: "/admin/programs"
}, ];
}
return [];
});
function onMenuClick(menu: string) {
activeMenu.value = menu;
showSubmenuBar.value = true;
}
// ✅ 서브메뉴 클릭 → 현재 활성 탭 내용만 변경
function onSubMenuClick(sub: { key: string; label: string; to: string; componentName: string }) {
tabsStore.updateActiveTab(sub);
// const activeKey = tabsStore.activeTab;
// router.push(`/${activeKey}${sub.to}`);
}
// ✅ 새 탭 추가 버튼
function addNewTab() {
tabsStore.addTab();
// router.push(`/${key}/`);
}
</script>
<template>
<div class="layout">
<AppHeader v-model="activeMenu" @update:model-value="onMenuClick" />
<!-- 서브메뉴 -->
<nav v-if="subMenus && subMenus.length && showSubmenuBar" class="submenu-bar" @click.stop>
<button
v-for="sub in subMenus"
:key="sub.key"
class="submenu-btn"
@click="onSubMenuClick({ ...sub, componentName: sub.key })"
>
{{ sub.label }}
</button>
</nav>
<br><br>
<!-- -->
<div class="tab-bar">
<div
v-for="tab in tabsStore.tabs"
:key="tab.key"
class="tab-item"
:class="{ active: tabsStore.activeTab === tab.key }"
@click="tabsStore.setActiveTab(tab.key);"
>
{{ tab.label }}
<span v-show="tabsStore.activeTab !== tab.key" class="close-btn" @click.stop="tabsStore.removeTab(tab.key)"> × </span>
</div>
<!-- 추가 버튼 -->
<button class="add-tab-btn" @click="addNewTab"></button>
</div>
<main class="main">
<slot />
</main>
</div>
</template>
<style scoped>
.layout {
min-height: 100vh;
display: flex;
flex-direction: column;
position: relative;
}
.main {
flex: 1;
padding: 2rem;
padding-top: 0.5rem;
}
.footer {
background: #f8f9fa;
padding: 1rem;
text-align: center;
border-top: 1px solid #e9ecef;
}
.submenu-bar {
background: #f4f6fa;
border-bottom: 1px solid #e0e7ef;
padding: 0.5rem 2rem;
display: flex;
gap: 1rem;
position: absolute;
top: 80px;
left: 0;
right: 0;
z-index: 10;
}
.submenu-btn {
font-size: 1.05rem;
font-weight: 500;
color: #222;
background: none;
border: none;
padding: 0.5rem 1.2rem;
border-radius: 6px;
transition:
background 0.15s,
color 0.15s;
cursor: pointer;
}
.submenu-btn.active {
background: none;
color: #1976d2;
}
.submenu-btn:hover {
background: #e6f0fa;
color: #1976d2;
}
/* 탭바 스타일 */
.tab-bar {
display: flex;
gap: 6px;
padding: 0.4rem 0.8rem;
background: #fff;
border-bottom: 1px solid #ddd;
}
.tab-item {
padding: 0.3rem 0.8rem;
background: #f2f2f2;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
}
.tab-item.active {
background: #1976d2;
color: white;
}
.close-btn {
margin-left: 6px;
cursor: pointer;
}
</style>