tab, component, popup 변경

This commit is contained in:
2025-08-22 14:01:30 +09:00
parent fd6fe43498
commit f801e876d2
22 changed files with 625 additions and 145 deletions

View File

@@ -1,52 +1,95 @@
<script setup lang="ts">
import AppHeader from "../components/AppHeader.vue";
import { ref, computed, watch, onMounted, onBeforeUnmount } from "vue";
import { useRouter, useRoute } from "vue-router";
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 route = useRoute();
const activeMenu = ref("home");
const showSubmenuBar = ref(false);
const tabsStore = useTabsStore();
// HOME 메뉴가 선택되었을 때 최상단 경로로 이동
// 메뉴 클릭 시 홈 이동
watch(activeMenu, (newValue) => {
if (newValue === "home") {
router.push("/");
}
});
watch(route, () => {
showSubmenuBar.value = false;
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" },
];
} 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 [{
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 [];
});
@@ -55,29 +98,19 @@ function onMenuClick(menu: string) {
showSubmenuBar.value = true;
}
// 서브메뉴 클릭 시 탭 추가
function onSubMenuClick(sub: { key: string; label: string; to: string, componentName:string }) {
tabsStore.addTab(sub);
router.push(sub.to);
// 서브메뉴 클릭 → 현재 활성 탭 내용만 변경
function onSubMenuClick(sub: { key: string; label: string; to: string; componentName: string }) {
tabsStore.updateActiveTab(sub);
// const activeKey = tabsStore.activeTab;
// router.push(`/${activeKey}${sub.to}`);
}
function handleClickOutsideSubmenuBar(event: MouseEvent) {
const submenu = document.querySelector(".submenu-bar");
if (
submenu &&
!submenu.contains(event.target as Node) &&
!(event.target as HTMLElement).classList.contains("menu-btn")
) {
showSubmenuBar.value = false;
}
// ✅ 새 탭 추가 버튼
function addNewTab() {
tabsStore.addTab();
// router.push(`/${key}/`);
}
onMounted(() => {
window.addEventListener("click", handleClickOutsideSubmenuBar);
});
onBeforeUnmount(() => {
window.removeEventListener("click", handleClickOutsideSubmenuBar);
});
</script>
<template>
@@ -85,46 +118,41 @@ onBeforeUnmount(() => {
<AppHeader v-model="activeMenu" @update:model-value="onMenuClick" />
<!-- 서브메뉴 -->
<nav
v-if="subMenus && subMenus.length && showSubmenuBar"
class="submenu-bar"
@click.stop
>
<nav v-if="subMenus && subMenus.length && showSubmenuBar" class="submenu-bar" @click.stop>
<button
v-for="sub in subMenus"
:key="sub.key"
class="submenu-btn"
:class="{ active: $route.path === sub.to }"
@click="onSubMenuClick({...sub, componentName : sub.key})"
@click="onSubMenuClick({ ...sub, componentName: sub.key })"
>
{{ sub.label }}
</button>
</nav>
<!-- 동적 -->
<div v-if="tabsStore.tabs.length" class="tab-bar">
<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); router.push(tab.to)"
@click="tabsStore.setActiveTab(tab.key);"
>
{{ tab.label }}
<span class="close-btn" @click.stop="tabsStore.removeTab(tab.key)">×</span>
<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>
<footer class="footer">
<p>&copy; 2024 Nuxt.js App</p>
</footer>
</div>
</template>
<style scoped>
.layout {
min-height: 100vh;