Files
sk_fems_ui/layouts/default.vue
2025-07-12 15:13:46 +09:00

806 lines
21 KiB
Vue

<template>
<v-app :class="`${isDarkMode ? 'dark-mode' : 'light-mode'}`">
<!-- <v-app :class="'light-mode'"> -->
<fullscreen :fullscreen.sync="fullscreen">
<v-navigation-drawer
ref="navigationdrawer"
:value="drawer"
:mini-variant="miniVariant"
:clipped="clipped"
:absolute="true"
mini-variant-width="60"
fixed
app
>
<div class="d-flex align-center justify-space-between py-4 px-3">
<router-link class="home" :to="myHome.root">
<div class="lnb-logo">
<img v-if="isDarkMode" src="@/assets/images/logo_dm.png" />
<img v-else src="@/assets/images/logo_lm.png" />
</div>
<!-- <div class="lnb-logo">FEMS</div>-->
</router-link>
<v-app-bar-nav-icon
ref="appbarnavicon"
id="appbarnavicon"
@click.stop="miniVariant = !miniVariant"
@click="updateTreeview"
:style="{
backgroundColor: 'transparent',
color: isDarkMode ? '#fff' : '#111',
}"
/>
<!-- <router-view :key="$route.fullPath"/> -->
</div>
<!--
v-model="treeValue"
return-object
@input="treeModel"
@update:active="clkTab"
-->
<AdminMenu
:miniVariant="miniVariant"
:userNm="this.userInfo.userNm"
:comId="this.userInfo.comId"
/>
<component
ref="changePswdPop"
:is="'ChangePswdPop'"
v-show="false"
:comId="this.userInfo.comId"
/>
<v-treeview
ref="treeview"
:active.sync="activeTree"
active-class="v-treeview-node--active"
:items="treevieItems"
activatable
hoverable
color="#3896ff"
open-on-click
@update:open="openNode"
>
<template slot="label" slot-scope="{ item }">
<button
:class="{ 'justify-center': miniVariant }"
@mouseover="doMouseOver"
>
<v-icon
v-if="item.lvl === 1 && menuIconKeys.includes(item.menuId)"
v-text="menuIconById[item.menuId]"
:class="{ 'mr-2': !miniVariant }"
size="20"
></v-icon>
<v-icon
v-else-if="
item.lvl === 1 && !menuIconKeys.includes(item.menuId)
"
:class="{ 'mr-2': !miniVariant }"
size="20"
>mdi-package-variant-closed</v-icon
>
<v-icon
v-else-if="item.lvl === 2"
:class="{ 'mr-2': !miniVariant }"
size="10"
>
mdi-checkbox-blank
</v-icon>
<v-icon
v-else-if="
item.lvl >= 3 && item.childeVo.length === 0 && item.url
"
:class="miniVariant === false ? 'mr-2' : ''"
size="9"
>
$depth3rdBulletDark
</v-icon>
<span v-if="item.url"
>{{ item.menuNm }}
<!-- <span v-if="item.bookmark" class="material-icons" style="font-size: 17px; vertical-align: middle;" @click="addBookMark(item.menuId, item.url, item.bookmark)">star</span>
<span v-else-if="!item.bookmark" class="material-icons" style="font-size: 17px; vertical-align: middle;" @click="addBookMark(item.menuId, item.url, item.bookmark)">star_border</span> -->
</span>
<span v-else-if="!item.url">{{ item.menuNm }}</span>
<v-icon
v-if="item.lvl >= 1 && item.childeVo.length > 0 && !item.url"
>
mdi-chevron-down
</v-icon>
</button>
</template>
</v-treeview>
<!-- <template #append>
<p
class="text-caption"
:style="{ letterSpacing: '-0.2px !important' }"
>
&copy; 2022. SK C&C all rights reserved.
</p>
</template> -->
</v-navigation-drawer>
<v-main>
<v-container fluid>
<router-tab
ref="routerTab"
:tabs="treevieItems"
:keep-last-tab="false"
:contextmenu="false"
>
<template slot-scope="{ title, closable, to }">
<span>{{ title }}</span>
<v-icon
size="18"
class="ml-2"
v-if="closable"
@click.stop="onCloseTab(to)"
>mdi-close-circle</v-icon
>
</template>
<template #end>
<!--<ThemeSwitch />-->
<v-menu offset-y>
<template v-slot:activator="{ on, attrs }">
<v-btn
:ripple="false"
tile
class="btn-close"
v-bind="attrs"
v-on="on"
>
<span class="body-2">닫기</span>
<v-icon size="20">mdi-chevron-down</v-icon>
</v-btn>
</template>
<v-list
class="py-2 btn-close-menu-list"
:style="{
backgroundColor: isDarkMode ? '#144985' : '#3f4d7d',
}"
>
<v-list-item class="px-2">
<v-list-item-title @click="delAllTabsData()" class="body-2"
>전체 닫기</v-list-item-title
>
</v-list-item>
<v-list-item class="px-2">
<v-list-item-title
@click="deleteSblingsTab()"
class="body-2"
>나머지 닫기</v-list-item-title
>
</v-list-item>
</v-list>
</v-menu>
<v-menu offset-y>
<template v-slot:activator="{ on, attrs }">
<v-btn
:ripple="false"
tile
class="btn-close"
v-bind="attrs"
v-on="on"
style="width:100px;"
>
<span class="body-2">즐겨찾기</span>
<v-icon size="20">mdi-chevron-down</v-icon>
</v-btn>
</template>
<v-list
v-if="myMenuList.length > 0"
class="py-2 btn-close-menu-list"
:style="{
backgroundColor: isDarkMode ? '#144985' : '#3f4d7d',
}"
>
<v-list-item
v-for="item in myMenuList"
:key="item.menuId"
class="px-2"
style="cursor:pointer;"
>
<v-list-item-title
@click="moveToMyMenu(item.url, item.menuId, item.prgmId)"
class="body-2"
>{{ item.menuNm }}</v-list-item-title
>
</v-list-item>
</v-list>
</v-menu>
<v-btn
icon
tile
:ripple="false"
@click="removeBookMark()"
v-if="bookmarkBtn == 1"
>
<span
class="material-icons"
style="font-size: 17px; vertical-align: middle;"
>star</span
>
</v-btn>
<v-btn
icon
tile
:ripple="false"
@click="addBookMark()"
v-if="bookmarkBtn == 0"
>
<span
class="material-icons"
style="font-size: 17px; vertical-align: middle;"
>star_border</span
>
</v-btn>
<v-btn
id="refresh"
icon
tile
:ripple="false"
@click="refreshTab()"
>
<v-icon>mdi-refresh</v-icon>
</v-btn>
<v-btn icon tile :ripple="false" @click="setDrawer()">
<v-icon>mdi-crop-free</v-icon>
</v-btn>
<!-- <v-btn icon tile :ripple="false" @click="toggle()">
<v-icon v-if="!fullscreen">mdi-arrow-expand-all</v-icon>
<v-icon v-else>mdi-arrow-collapse-all</v-icon>
</v-btn> -->
</template>
</router-tab>
</v-container>
<div v-if="loadingStackCnt > 0" class="loading-container">
<div class="loading">
<Fade-loader />
</div>
</div>
</v-main>
<!-- <v-footer
:absolute="!fixed"
app
:class="
drawer
? miniVariant
? 'drawerFooter miniFooter'
: 'drawerFooter'
: 'full-size'
"
>
<span>&copy; 2022. SK C&C all rights reserved.</span>
</v-footer> -->
</fullscreen>
</v-app>
</template>
<script>
import { mapState, mapActions, mapMutations } from 'vuex'; // , mapActions
import ThemeSwitch from '@/components/common/ThemeSwitch';
import AdminMenu from '@/components/common/AdminMenu';
import FadeLoader from 'vue-spinner/src/FadeLoader.vue';
import ChangePswdPop from '~/components/common/modal/ChangePswdPop';
export default {
components: {
ThemeSwitch,
AdminMenu,
FadeLoader,
ChangePswdPop,
},
data() {
return {
fullscreen: false,
activeTree: [],
clipped: false,
fixed: false,
miniVariant: false,
// activeTabIdx: "",
routerTabInstance: null,
// programIdObj: null,
myPrgmId: null,
treeValue: [],
menuIconById: {
// MNU0003: 'mdi-chart-line',
// MNU0004: 'mdi-alarm-light',
// MNU0005: 'mdi-pencil-box-outline',
// MNU0006: 'mdi-cog-outline',
MNU0002: 'mdi-monitor',
MNU0091: 'mdi-chart-box',
MNU0102: 'mdi-human-male-board-poll',
MNU0103: 'mdi-file-chart-outline',
MNU0104: 'mdi-chart-sankey-variant',
MNU0106: 'mdi-database-edit-outline',
MNU0105: 'mdi-chart-bell-curve',
MNU0006: 'mdi-bulletin-board',
MNU0007: 'mdi-cog',
},
isLoading: false,
loadingStackCnt: 0,
bookmarkBtn: 0,
myMenuList: [],
prgmIdList: [],
initPageData: {},
obj: {},
newObj: {},
};
},
computed: {
...mapState({
myHome: 'myHome',
myHomeTabItems: 'myHomeTabItems',
indexRoot: 'indexRoot',
treevieItems: 'treevieItems',
menuData: 'menuData',
menuLink: state => state.modules.menu,
activeMenuId: state => state.activeMenuInfo.menuId,
isDarkMode: 'isDarkMode',
drawer: state => state.drawer,
userInfo: state => state.userInfo,
pageData: 'pageData',
}),
activeTabs() {
if (this.routerTabInstance) {
return this.routerTabInstance.activeTab;
} else {
return this.myHome.root;
}
},
menuIconKeys() {
return Object.keys(this.menuIconById);
},
},
watch: {
activeTabs: {
// 탭 클릭시 좌측 treeview 싱크 맞추가
deep: true,
handler(value) {
if (value) {
const prgmId = value.prgmId;
let thisPrgmId = this.$route.query.prgmId;
var tmp = 0;
for (var i = 0; i < this.myMenuList.length; i++) {
if (this.myMenuList[i].prgmId == thisPrgmId) {
tmp = 1;
}
}
this.bookmarkBtn = tmp;
//if (thisPrgmId && this.myPrgmId && this.myPrgmId != thisPrgmId) {
this.myPrgmId = prgmId;
this.activeTree.pop(); // 기존 황성화 트리 값 삭제
this.activeTree.push(thisPrgmId); // 인덱스가 아닐 경우 새로 넣어줌
// this.$set(this.activeTree, 0, prgmId); // treeview activetree 새로 셋팅 <= 위 pop() 과 push() 로 대체
//}
}
},
},
activeTree: {
deep: true,
handler(newVal, oldVal) {
var _this = this;
const nv = newVal[0];
const ov = oldVal[0];
if (nv !== ov) {
if (!nv) {
// 중복클릭 시 발생 상황 기존 값을 다시 넣어줌
this.activeTree.push(ov);
} else {
this.myPrgmId = nv;
if (this.menuData[nv].url) {
const menuUrl = this.menuData[nv].url;
const menuId = this.menuData[nv].menuId;
const isCommMenu = menuUrl.indexOf('comm/');
const isEmsMenu = menuUrl.indexOf('ems/');
const isCmmsMenu = menuUrl.indexOf('cmms/');
// console.log('activeTree...');
if (isCommMenu > -1 || isEmsMenu > -1 || isCmmsMenu > -1) {
// console.log('activeTree if stmt1');
// console.log('this.isLoading : ', this.isLoading);
// if(this.isLoading == true){
// console.log('if isLoading stmt1');
// return;
// }
this.$router.push({
path: `${this.menuData[nv].url}?prgmId=${nv}`,
});
// this.$router.beforeEach((to, from, next) => {
// if(_this.isLoading == true){
// next(false);
// }
// if (!to.matched.length) {
// next(false);
// } else {
// next();
// }
// });
var tmp = 0;
for (var i = 0; i < this.myMenuList.length; i++) {
if (this.myMenuList[i].menuId == menuId) {
tmp = 1;
}
}
this.bookmarkBtn = tmp;
} else {
// console.log('activeTree if stmt2');
// console.log('this.isLoading : ', this.isLoading);
// if(this.isLoading == true){
// console.log('if isLoading stmt2');
// return;
// }
this.$refs.routerTab.openIframe(
encodeURI(
`http://localhost:9999${this.menuData[nv].url}?prgmId=${nv}`,
),
this.menuData[nv].menuNm,
);
}
this.$axios.get(`${this.menuData[nv].url}?$menuId=${menuId}`);
} else alert('지정된 페이지 경로가 없습니다.');
}
}
},
},
menuData: {
deep: true,
handler(newVal, oldVal) {},
},
pageData: {
deep: true,
handler(newVal, oldVal) {
localStorage.setItem('pageData', JSON.stringify(this.pageData));
//console.log("localPageData", this.pageData);
},
},
// menuLink: {
// deep: true,
// handler() {
// let prgmIdList = Object.keys(this.menuData);
// let initPageData = {};
// prgmIdList.forEach(item => {
// let newObj = {
// [item] : {}
// };
// initPageData = Object.assign(initPageData, newObj)
// });
// }
// }
},
created() {},
beforeUnmount() {
//window.removeEventListener('beforeunload', this.unLoadEvent);
},
async mounted() {
//window.addEventListener('beforeunload', this.unLoadEvent);
const _this = this;
await this.getMenu({});
await this.initPageDataFunc();
await this.selectMyMenuFunc();
this.routerTabInstance = this.$refs.routerTab;
if (this.$route.fullPath == '/') {
this.routerTabInstance.reset();
this.$router.replace(this.myHome.root);
} else if (this.$route.fullPath != this.myHome.root) {
this.$refs.routerTab.items.unshift(this.myHomeTabItems);
} else {
this.refreshTab();
}
this.$router.beforeEach((to, from, next) => {
_this.isLoading = true;
// console.log('$router.beforeEach...');
// console.log('state : ', _this.$store.state)
// console.log('activeActionCnt : ', _this.$store.state.activeActionCnt)
// console.log('_this.isLoading[beforeEach] : ', _this.isLoading);
// console.log('_this.loadingStackCnt : ', _this.loadingStackCnt);
// if(_this.loadingStackCnt > 0 && _this.isLoading && _this.$store.state.activeActionCnt > 0){
if(_this.loadingStackCnt > 0 && _this.isLoading){
next(false);
// return;
}else if (!to.matched.length){
next(false);
}else{
next();
}
});
this.$router.afterEach((to, from, failure) => {
});
// 요청 인터셉터
this.$axios.interceptors.request.use(
function(config) {
//alert(1)
_this.isLoading = true;
if(config.url.search('Page')<0){
_this.loadingStackCnt++;
}
return config;
},
function(error) {
// 에라 나면 로딩 끄기
//alert(2)
_this.isLoading = false;
// if(error.url.search('Page')<0){
// _this.loadingStackCnt--;
// }
return Promise.reject(error);
},
);
// 응답 인터셉터
this.$axios.interceptors.response.use(
function(response) {
_this.isLoading = false;
if(response.config.url.search('Page')<0){
_this.loadingStackCnt--;
}
//alert(3)
return response;
},
function(error) {
// 응답 에러 시에도 로딩 끄기
//alert(4 )
_this.isLoading = false;
// if(error.url.search('Page')<0){
// _this.loadingStackCnt--;
// }
return Promise.reject(error);
},
);
},
methods: {
...mapMutations({
setDrawer: 'setDrawer', // 사이드메뉴 접고 펼치기
setPageDataInit: 'setPageDataInit',
}),
...mapActions({
getMenu: 'modules/menu/getMenu', // 트리메뉴 가져오기
chkOpenTabList: 'chkOpenTabList', // 트리메뉴 클릭 시 해당 pprgmId push
postUpdateApi: 'modules/list/postUpdateApi',
postApiReturn: 'modules/list/postApiReturn',
}),
// // tabActive(id) {},
// clkTab(itemArr) {
// console.log(itemArr[0]);
// if (!itemArr[0].to) return;
// this.$router.push({
// path: itemArr[0].to
// });
// },
toggle() {
this.fullscreen = !this.fullscreen;
},
refreshTab() {
// console.log("현재 탭 새로고침");
//this.routerTabInstance.refresh();
this.$nuxt.refresh();
this.routerTabInstance.refresh();
},
delAllTabsData() {
// console.log("탭 전체 닫기");
// for (let i = this.routerTabInstance.items.length - 1; i > -1; --i) {
// const diffTo = this.routerTabInstance.items[i].to;
// if (diffTo != this.myHome.root) {
// this.routerTabInstance.items.splice(i, 1);
// }
// }
//if(this.$router.currentRoute.fullPath != this.myHome.root){
if (this.routerTabInstance.items.length > 0) {
this.routerTabInstance.reset();
}
this.$router.replace(this.myHome.root);
//}
},
deleteSblingsTab() {
// console.log("탭 나머지 닫기");
// for (let i = this.routerTabInstance.items.length - 1; i > -1; --i) {
// const activeTo = this.routerTabInstance.activeTab.to;
// const diffTo = this.routerTabInstance.items[i].to;
// if (activeTo != diffTo && diffTo != this.myHome.root) {
// this.routerTabInstance.items.splice(i, 1);
// }
// }
if (this.routerTabInstance.items.length > 1) {
for (let i = this.routerTabInstance.items.length - 1; i > -1; --i) {
const activeTo = this.routerTabInstance.activeTab.to;
const diffTo = this.routerTabInstance.items[i].to;
if (activeTo != diffTo && diffTo != this.myHome.root) {
this.routerTabInstance.close(diffTo);
}
}
}
},
tabScrollMove(dir) {
const scrollTab = this.routerTabInstance.$refs.scroll;
const scrollWidth =
scrollTab.scrollData.scrollWidth - scrollTab.scrollData.clientWidth;
const scrollLeft = scrollTab.scrollData.scrollLeft;
const xAxis = this.calcScroll(scrollLeft, scrollWidth, dir);
scrollTab.scrollTo(xAxis, 0);
},
updateTreeview() {
if (this.miniVariant) {
// sidebar 접혀져 있을 때
this.$refs.treeview.updateAll();
} else {
// sidebar 펼쳐져 있을 때
}
},
// 열려있는 노드의 key 값 리턴(선택된 값이 아님)
openNode(node) {
//console.log('onOpen');
if (this.miniVariant) {
// sidebar 접혀져 있을 때
if (event.currentTarget.id !== this.$refs.appbarnavicon.$refs.link.id) {
this.$refs.appbarnavicon.click(event);
}
} else {
// sidebar 펼쳐져 있을 때
}
},
doMouseOver: function(event) {
//console.log(event);
},
calcScroll(sl, sw, dir) {
const deScrW = 60;
let returnSl = 0;
switch (dir) {
case 'prev':
returnSl = sl - deScrW <= 0 ? 0 : sl - deScrW;
break;
case 'next':
returnSl = sl + deScrW >= sw ? sw : sl + deScrW;
break;
default:
break;
}
return returnSl;
},
initPageDataFunc() {
const _this = this;
this.prgmIdList = Object.keys(this.menuData);
this.initPageData = {};
this.prgmIdList.forEach(item => {
_this.obj = {};
if (_this.pageData[item]) {
_this.obj = _this.pageData[item];
}
_this.newObj = {};
_this.newObj = {
[item]: _this.obj,
};
_this.initPageData = Object.assign(
{},
_this.initPageData,
_this.newObj,
);
});
localStorage.setItem('pageData', JSON.stringify(this.initPageData));
this.setPageDataInit(this.initPageData);
},
onCloseTab(to) {
const findIndex = this.$tabs.items.findIndex(v => v.to === to);
const { to: next } = this.$tabs.items[findIndex - 1];
this.$tabs.close(to, null);
if (this.$router.currentRoute.fullPath != next) {
this.$router.replace(next);
}
},
async addBookMark() {
var params = {
menuId: this.activeMenuId,
};
await this.postUpdateApi({
apiKey: 'saveBookmark',
sendParam: {
datas: {
bookmarkDt: [params],
},
params: {},
},
});
const res = await this.postApiReturn({
apiKey: 'selectMyMenu',
resKey: 'menuData',
sendParam: {},
});
this.myMenuList = res;
this.bookmarkBtn = 1;
},
async removeBookMark() {
var params = {
menuId: this.activeMenuId,
};
await this.postUpdateApi({
apiKey: 'deleteBookmark',
sendParam: {
datas: {
bookmarkDt: [params],
},
params: {},
},
});
const res = await this.postApiReturn({
apiKey: 'selectMyMenu',
resKey: 'menuData',
sendParam: {},
});
this.myMenuList = res;
this.bookmarkBtn = 0;
},
moveToMyMenu(url, menuId, prgmId) {
// console.log('moveToMyMenu...');
// if(this.isLoading == true){
// console.log('if isLoading stmt3');
// return;
// }
this.$router.push({
path: url + '?prgmId=' + prgmId,
});
},
async selectMyMenuFunc() {
const headers = {
headers: {
'X-Fems-MenuId': 'MNU0001',
},
};
const params = { params: {} };
const res = await this.$axios.post(
'/comm/base/MenuMngCtr/selectMyMenu',
params,
headers,
);
this.myMenuList = res.data.dataset.menuData;
},
// unLoadEvent: function (event) {
// //if (this.isLeaveSite) return;
// //this.delAllTabsData();
// this.$router.push({
// path: this.myHome.root
// });
// console.log("event", event)
// event.preventDefault();
// event.returnValue = '';
// },
// treeModel(obj) {
// console.log(">>> treeModel::obj = ", obj);
// this.treeValue[0] = obj;
// this.$refs.treeview.updateAll();
// // console.log(this.$refs.treeview);
// // this.$refs.treeview.activeCache = obj.id;
// }
},
};
</script>
<style lang="scss">
.loading {
z-index: 99;
position: fixed;
top: 50%;
left: 50%;
width: 100%;
height: 100%;
transform: translate(-50%, -50%);
background-color: rgba(0, 0, 0, 0.4);
//box-shadow: rgba(68, 67, 67, 0.9) 0 0 0 9999px;
}
.v-spinner {
top: 50%;
left: 50%;
}
</style>