Files
lucia-frontend/src/components/Navbar.vue
2026-03-06 08:18:36 +08:00

356 lines
12 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.
<template>
<nav id='nav_bar' class="bg-neutral-700">
<div class="mx-auto px-4" :class="[showNavbarBreadcrumb? 'min-h-12': 'h-12']">
<div class="flex justify-between items-center flex-wrap relative" v-show="showNavbarBreadcrumb">
<div id="nav_bar_logged_in" class="flex flex-1 items-center">
<!-- Files -->
<router-link to="/files" class="mr-4" v-if="showIcon" id="backPage">
<span class="material-symbols-outlined text-neutral-10 !leading-loose">
arrow_back
</span>
</router-link>
<div>
<h2 v-if="navViewName !== 'UPLOAD'" class="mr-14 py-3 text-2xl font-black text-neutral-10">{{ navViewName }}</h2>
<h2 v-else class="mr-14 py-3 text-2xl font-black text-neutral-10">FILES</h2>
</div>
<ul class="flex justify-center items-center space-x-4 text-xl font-semibold text-neutral-300 cursor-pointer">
<li @click="onNavItemBtnClick($event, item)"
v-for="(item, index) in navViewData[navViewName]"
:key="index" class="nav-item"
:class="{'active': activePage === item}">
{{ item }}
</li>
</ul>
</div>
<!-- Files Page: Search and Upload -->
<div class="flex justify-end items-center" v-if="navViewName === 'FILES'">
<div id="import_btn" class="btn btn-sm btn-neutral cursor-pointer" @click="uploadModal = true">
Import
<UploadModal :visible="uploadModal" @closeModal="uploadModal = $event"></UploadModal>
</div>
</div>
<!-- Upload, Performance, Compare 無按鈕行為 -->
<div v-else-if="noShowSaveButton"></div>
<!-- Other Page: Save and Download -->
<!-- Save data 跳重新命名沒有 data 跳要不要儲存沒有動都不跳 -->
<div v-else class="space-x-4">
<button class="btn btn-sm" :class="[ disabledSave ? 'btn-disable' : 'btn-neutral']"
:disabled="disabledSave" @click="saveModal">
Save
</button>
</div>
<AcctMenu v-if="showNavbarBreadcrumb"/>
</div>
</div>
</nav>
</template>
<script>
import { storeToRefs, mapState, mapActions, } from 'pinia';
import filesStore from '@/stores/files.js';
import AllMapDataStore from '@/stores/allMapData.js';
import ConformanceStore from '@/stores/conformance.js';
import PageAdminStore from '@/stores/pageAdmin.js';
import MapCompareStore from '@/stores/mapCompareStore';
import IconSearch from '@/components/icons/IconSearch.vue';
import IconSetting from '@/components/icons/IconSetting.vue';
import { saveFilter, savedSuccessfully, saveConformance } from '@/module/alertModal.js';
import UploadModal from './File/UploadModal.vue';
import AcctMenu from './AccountMenu/AcctMenu.vue';
export default {
setup() {
const store = filesStore();
const allMapDataStore = AllMapDataStore();
const conformanceStore = ConformanceStore();
const { logId, tempFilterId, createFilterId, filterName, postRuleData, isUpdataFilter } = storeToRefs(allMapDataStore);
const { conformanceRuleData, conformanceLogId, conformanceFilterId,
conformanceLogTempCheckId, conformanceFilterTempCheckId,
conformanceLogCreateCheckId, conformanceFilterCreateCheckId,
isUpdataConformance, conformanceFileName
} = storeToRefs(conformanceStore);
return {
store, allMapDataStore, logId, tempFilterId, createFilterId,
filterName, postRuleData, isUpdataFilter, conformanceStore, conformanceRuleData,
conformanceLogId, conformanceFilterId, conformanceLogTempCheckId,
conformanceFilterTempCheckId, conformanceLogCreateCheckId,
conformanceFilterCreateCheckId, isUpdataConformance, conformanceFileName,
};
},
components: {
IconSearch,
IconSetting,
UploadModal,
AcctMenu,
},
data() {
return {
mapCompareStore: MapCompareStore(),
showNavbarBreadcrumb: false,
navViewData:
{
// 舉例FILES: ['ALL', 'DISCOVER', 'COMPARE', 'DESIGN', 'SIMULATION'],
FILES: ['ALL', 'DISCOVER', 'COMPARE'],
// 舉例DISCOVER: ['MAP', 'CONFORMANCE', 'PERFORMANCE', 'DATA']
DISCOVER: ['MAP', 'CONFORMANCE', 'PERFORMANCE'],
// 舉例COMPARE: ['PROCESS MAP', 'DASHBOARD']
COMPARE: ['MAP', 'PERFORMANCE'],
'ACCOUNT MANAGEMENT': [],
'MY ACCOUNT': [],
},
navViewName: 'FILES',
uploadModal: false,
};
},
computed: {
disabledSave: function () {
switch (this.$route.name) {
case 'Map':
case 'CheckMap':
// 沒有 filter Id, 沒有暫存 tempFilterId Id 就不能存檔
return !this.tempFilterId;
case 'Conformance':
case 'CheckConformance':
return !(this.conformanceFilterTempCheckId || this.conformanceLogTempCheckId);
}
},
showIcon: function() {
let result = true;
result = !['FILES', 'UPLOAD'].includes(this.navViewName);
return result;
},
noShowSaveButton: function() {
return this.navViewName === 'UPLOAD' || this.navViewName === 'COMPARE' ||
this.navViewName === 'ACCOUNT MANAGEMENT' ||
this.activePage === 'PERFORMANCE';
},
...mapState(PageAdminStore, [
'activePage',
'pendingActivePage',
'activePageComputedByRoute',
'shouldKeepPreviousPage',
]),
},
watch: {
'$route':'getNavViewName',
filterName: function(newVal,) {
this.filterName = newVal;
},
},
mounted() {
this.handleNavItemBtn();
if(this.$route.params.type === 'filter') {
this.createFilterId= this.$route.params.fileId;
}
this.showNavbarBreadcrumb = this.$route.matched[0].name !== ('AuthContainer');
this.getNavViewName();
},
methods: {
/**
* switch navbar item
* @param {event} event 選取 Navbar 選項後傳入的值
*/
onNavItemBtnClick(event) {
let type;
let fileId;
let isCheckPage;
const navItemCandidate = event.target.innerText;
this.setPendingActivePage(navItemCandidate);
switch (this.navViewName) {
case 'FILES':
this.store.filesTag = navItemCandidate;
break;
case 'DISCOVER':
type = this.$route.params.type;
fileId = this.$route.params.fileId;
isCheckPage = this.$route.name.includes('Check');
switch (navItemCandidate) {
case 'MAP':
if(isCheckPage) {
this.$router.push({name: 'CheckMap', params: { type: type, fileId: fileId }});
}
else {
this.$router.push({name: 'Map', params: { type: type, fileId: fileId }});
}
break;
case 'CONFORMANCE':
if(isCheckPage) { // Beware of Swal popup, it might disturb which is the current active page
this.$router.push({name: 'CheckConformance', params: { type: type, fileId: fileId }});
}
else { // Beware of Swal popup, it might disturb which is the current active page
this.$router.push({name: 'Conformance', params: { type: type, fileId: fileId }});
}
break
case 'PERFORMANCE':
if(isCheckPage) {
this.$router.push({name: 'CheckPerformance', params: { type: type, fileId: fileId }});
}
else {
this.$router.push({name: 'Performance', params: { type: type, fileId: fileId }});
}
break;
}
break;
case 'COMPARE':
switch (navItemCandidate) {
case 'MAP':
this.$router.push({name: 'MapCompare', params: this.mapCompareStore.routeParam});
break;
case 'PERFORMANCE':
this.$router.push({name: 'CompareDashboard', params: this.mapCompareStore.routeParam});
break;
default:
break;
}
};
},
/**
* Based on the route.name, decide the navViewName.
* @returns {string} the string of navigation name to return
*/
getNavViewName() {
let name = this.$route.name;
let valueToSet;
if(this.$route.name === 'NotFound404') {
return;
}
// 說明this.$route.matched[1] 表示當前路由匹配的第二個路由記錄
this.navViewName = this.$route.matched[1].name.toUpperCase();
this.store.filesTag = 'ALL';
switch (this.navViewName) {
case 'FILES':
valueToSet = this.navItemCandidate;
break;
case 'DISCOVER':
switch (name) {
case 'Map':
case 'CheckMap':
valueToSet = 'MAP';
break;
case 'Conformance':
case 'CheckConformance':
valueToSet = 'CONFORMANCE';
break;
case 'Performance':
case 'CheckPerformance':
valueToSet = 'PERFORMANCE';
break;
}
break;
case 'COMPARE':
switch(name) {
case 'dummy':
case 'CompareDashboard':
valueToSet = 'DASHBOARD';
break;
default:
break;
}
break;
}
// Frontend is not sure which button will the user press on the modal,
// so here we need to save to a pending state
// 前端無法確定用戶稍後會按下彈窗上的哪個按鈕(取消還是確認、儲存)
// 因此我們需要將其保存到待處理狀態
if(!this.shouldKeepPreviousPage) { // 若使用者不是按下取消按鈕或是點選按鈕時
this.setPendingActivePage(valueToSet);
}
return valueToSet;
},
/**
* Save button' modal
*/
async saveModal() {
// 協助判斷 MAP, CONFORMANCE 儲存有「送出」或「取消」。
// 傳給 Map通知 Sidebar 要關閉。
this.$emitter.emit('saveModal', false);
switch (this.$route.name) {
case 'Map':
await this.handleMapSave();
break;
case 'CheckMap':
await this.handleCheckMapSave();
break;
case 'Conformance':
case 'CheckConformance':
await this.handleConformanceSave();
break;
default:
break;
}
},
/**
* Set nav item button background color in case the variable is an empty string
*/
handleNavItemBtn() {
if(this.activePageComputedByRoute === "") {
this.setActivePageComputedByRoute(this.$route.matched[this.$route.matched.length - 1].name);
}
},
async handleMapSave() {
if (this.createFilterId) {
await this.allMapDataStore.updataFilter();
if (this.isUpdataFilter) {
await savedSuccessfully(this.filterName);
}
} else if (this.logId) {
const isSaved = await saveFilter(this.allMapDataStore.addFilterId);
if (isSaved) {
this.setActivePage('MAP');
await this.$router.push(`/discover/filter/${this.createFilterId}/map`);
}
}
},
async handleCheckMapSave() {
const isSaved = await saveFilter(this.allMapDataStore.addFilterId);
if (isSaved) {
this.setActivePage('MAP');
await this.$router.push(`/discover/filter/${this.createFilterId}/map`);
}
},
async handleConformanceSave() {
if (this.conformanceFilterCreateCheckId || this.conformanceLogCreateCheckId) {
await this.conformanceStore.updataConformance();
if (this.isUpdataConformance) {
await savedSuccessfully(this.conformanceFileName);
}
} else {
const isSaved = await saveConformance(this.conformanceStore.addConformanceCreateCheckId);
if (isSaved) {
if (this.conformanceLogId) {
this.setActivePage('CONFORMANCE');
await this.$router.push(`/discover/conformance/log/${this.conformanceLogCreateCheckId}/conformance`);
} else if (this.conformanceFilterId) {
this.setActivePage('CONFORMANCE');
await this.$router.push(`/discover/conformance/filter/${this.conformanceFilterCreateCheckId}/conformance`);
}
}
}
},
...mapActions(PageAdminStore, [
'setPendingActivePage',
'setPrevioiusPage',
'setActivePage',
'setActivePageComputedByRoute',
'setIsPagePendingBoolean',
],),
},
}
</script>
<style scoped>
#searchFiles::-webkit-search-cancel-button{
appearance: none;
}
</style>