
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
<template>
<div class="content admin-style">
<div class="admin-page-title point-font2 mb30">
<p>메뉴관리</p>
</div>
<div class="full-page">
<div class="flex content">
<div class="gd-3 pl0 content">
<div class="tree-zone content pd15">
<div class="tree">
<div class="content overflow-y">
<draggable
tag="ul"
class="tree-node"
:list="menuList"
:group="{ name: 'menu' }"
item-key="id"
handle=".handle"
ghost-class="ghost"
>
<template #item="{ element }">
<Hierachy
:tasks="element"
:icon="iconPath"
:selectedNode="selectedMenuId"
@changeSelected="fnViewDetail"
/>
</template>
</draggable>
</div>
</div>
<div class="btn-zone pt15" v-if="pageAuth.mdfcnAuthrtYn == 'Y'">
<div class="flex">
<div class="gd-6 pl0">
<button class="large-btn blue-border-btn" @click="fnTopAdd">
TOP+
</button>
</div>
<div class="gd-6 pr0">
<button class="large-btn blue-border-btn" @click="fnSubAdd">
SUB+
</button>
</div>
</div>
<div class="pt15">
<button class="large-btn blue-border-btn" @click="fnListUpdate">
메뉴 저장
</button>
</div>
</div>
</div>
</div>
<div class="gd-9 pr0 content overflow-y">
<div class="content">
<table class="form-table">
<colgroup>
<col width="50%" />
<col width="50%" />
</colgroup>
<tr>
<td>
<div class="gd-12 pl0 pr0">
<p class="form-title mb10">상위 메뉴명 </p>
<input
type="text"
class="full-input"
v-model="viewMenu.upMenuNm"
disabled
/>
</div>
</td>
<td>
<div class="gd-12 pl0 pr0">
<label for="menuName" class="form-title point-font2 mb10">
메뉴명
</label>
<input
type="text"
id="menuName"
class="full-input"
ref="menuNm"
v-model="viewMenu.menuNm"
:disabled="!editMode"
/>
</div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="gd-12 pl0 pr0">
<p class="form-title mb10">메뉴 설명</p>
<textarea
style="min-height: 3rem"
v-model="viewMenu.menuCn"
:disabled="!editMode"
></textarea>
</div>
</td>
</tr>
<tr>
<td>
<div class="gd-12 pl0 pr0">
<p class="form-title mb10">메뉴 타입</p>
<div class="flex">
<div class="gd-3 pd0">
<select
class="full-select"
ref="menuType"
v-model="viewMenu.menuTypeCd"
:disabled="!editMode"
>
<option value="">선택</option>
<option
v-for="(code, index) in codeList"
:key="index"
:value="code.cdId"
>
{{ code.cdNm }}
</option>
</select>
</div>
<div
class="gd-9 pr0"
v-show="
viewMenu.menuTypeCd == 'bbs' ||
viewMenu.menuTypeCd == 'conts'
"
>
<select
class="full-select"
ref="menuTypeCtgry"
v-model="viewMenu.menuTypeArtclId"
:disabled="!editMode"
>
<option value="">선택</option>
<option
v-for="(ctgry, index) of ctgryList"
:key="index"
:value="ctgry.id"
>
{{ ctgry.name }}
</option>
</select>
</div>
<div
class="gd-10 pl0 pr0s"
v-show="viewMenu.menuTypeCd == 'link'"
>
<input
type="text"
class="full-input"
ref="linkUrl"
v-model="viewMenu.linkUrlAddr"
:disabled="!editMode"
/>
</div>
</div>
</div>
</td>
<td>
<div class="gd-12 pl0 pr0">
<label class="form-title mb10">
메뉴 사용자
</label>
<div class="flex align-center no-gutters">
<div class="gd-4">
<input
type="radio"
name="menuUser"
id="menuUserAdm"
class="mr5"
v-model="viewMenu.menuUserCode"
value="A"
:disabled="!editMode"
/>
<label for="menuUserAdm">관리자용</label>
</div>
<div class="gd-4">
<input
type="radio"
name="menuUser"
id="menuUserUser"
class="mr5"
v-model="viewMenu.menuUserCode"
value="U"
:disabled="!editMode"
/>
<label for="menuUserUser">사용자용</label>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td>
<div class="gd-12 pl0 pr0">
<label class="form-title mb10">
링크유형
</label>
<div class="flex align-center no-gutters">
<div class="gd-4">
<input
type="radio"
name="linkType"
id="linkTypeY"
class="mr5"
v-model="viewMenu.linkTypeNm"
value="0"
:disabled="!editMode"
/>
<label for="linkTypeY">현재창</label>
</div>
<div class="gd-4">
<input
type="radio"
name="linkType"
id="linkTypeN"
class="mr5"
v-model="viewMenu.linkTypeNm"
value="1"
:disabled="!editMode"
/>
<label for="linkTypeN">새창</label>
</div>
</div>
</div>
</td>
<td>
<div class="gd-12 pl0 pr0">
<label class="form-title mb10">
메뉴 노출 여부
</label>
<div class="flex align-center no-gutters">
<div class="gd-4">
<input
type="radio"
name="menuExpsrYn"
id="menuExpsrY"
class="mr5"
v-model="viewMenu.menuExpsrYn"
value="Y"
:disabled="!editMode"
/>
<label for="menuExpsrY">사용</label>
</div>
<div class="gd-4">
<input
type="radio"
name="menuExpsrYn"
id="menuExpsrN"
class="mr5"
v-model="viewMenu.menuExpsrYn"
value="N"
:disabled="!editMode"
/>
<label for="menuExpsrN">미사용</label>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td>
<div class="gd-12 pl0 pr0s">
<p class="form-title mb10">등록자</p>
<input
type="text"
class="full-input"
v-model="viewMenu.frstRegNm"
disabled
/>
</div>
</td>
<td>
<div class="gd-12 pl0 pr0">
<p class="form-title mb10">등록일</p>
<input
type="text"
class="full-input"
v-model="viewMenu.frstRegDt"
disabled
/>
</div>
</td>
</tr>
<tr>
<td>
<div class="gd-12 pl0 pr0">
<p class="form-title mb10">수정자</p>
<input
type="text"
class="full-input"
v-model="viewMenu.lastMdfcnNm"
disabled
/>
</div>
</td>
<td>
<div class="gd-12 pl0 pr0">
<p class="form-title mb10">수정일</p>
<input
type="text"
class="full-input"
v-model="viewMenu.lastMdfcnDt"
disabled
/>
</div>
</td>
</tr>
</table>
<div class="flex justify-end pt15">
<div class="gd-1 pr0">
<button
:class="{
'large-btn': true,
'gray-btn': !editMode,
'red-border-btn': editMode,
}"
:disabled="isFormDisabled"
@click="fnDelete"
v-if="pageAuth.delAuthrtYn == 'Y'"
>
삭제
</button>
</div>
<div class="gd-1 pr0" v-if="
selectedMenuId != null &&
editMode == true &&
pageAuth.mdfcnAuthrtYn == 'Y'
">
<button
class="large-btn blue-btn"
@click="fnInsert"
:disabled="!editMode">
수정
</button>
</div>
<div class="gd-1 pr0" v-else-if="editMode == true && pageAuth.wrAuthrtYn == 'Y'">
<button
class="large-btn blue-btn"
@click="fnInsert"
:disabled="!editMode"
>
등록
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import draggable from "vuedraggable";
import Hierachy from "../../../../component/hierachy/HierachyDraggable.vue";
import { mdiFormatListBulleted } from "@mdi/js";
// Api
import {
menuFindAll,
menuSave,
menuFindByMenu,
menuUpdate,
menuDelete,
updateListProc,
} from "../../../../../resources/api/menu";
import { findAllByExpsr } from "../../../../../resources/api/contsType";
import { findAllByMenuMng } from "../../../../../resources/api/bbsMng";
export default {
data() {
return {
// 페이지 권한 객체
pageAuth: JSON.parse(localStorage.getItem("vuex")).pageAuth,
// 글 작성 모드
// false - 없음 (기본)
// true - 등록/수정
editMode: false,
iconPath: mdiFormatListBulleted,
menuList: [], // 메뉴 목록
newMenu: {}, // 신규 메뉴
viewMenu: {
menuTypeCd: "",
menuTypeArtclId: "",
}, // 사용자에게 보여질 메뉴 목록
selectedMenuId: null, // 선택된 메뉴
codeList: [], // 메뉴 타입 목록
ctgryList: [], // 메뉴 타입 항목
bbsList: [], // 메뉴 타입 게시판 목록
contsTypeList: [], // 메뉴 타입 콘텐츠 목록
};
},
created() {
this.fnViewList();
this.axiosBbsList(); // 메뉴 타입 게시판 목록 조회
this.axiosContsTypeList(); // 메뉴 타입 콘텐츠 목록 조회
// pageId 확인
if (this.pageId != null) {
this.editMode = "true";
}
},
methods: {
// 등록
fnInsert() {
// 유효성검사
if (this.valiadtion() == false) {
return;
}
const data = this.viewMenu;
if (
this.viewMenu["menuTypeCd"] == "bbs" ||
this.viewMenu["menuTypeCd"] == "conts"
) {
this.viewMenu["linkUrlAddr"] == null;
} else if (this.viewMenu["menuTypeCd"] == "link") {
this.viewMenu["menuTypeArtclId"] == null;
}
if (this.selectedMenuId == null) {
this.axiosInsert(data);
} else {
this.axiosUpdate(data);
}
},
// 조회(목록)
fnViewList() {
this.axiosViewList();
},
// 조회(상세)
fnViewDetail(menuId) {
this.selectedMenuId = menuId;
const data = {
menuId: menuId,
};
this.axiosViewDetail(data);
},
// 삭제
fnDelete() {
if (Object.keys(this.viewMenu).length === 0) {
alert("삭제 대상을 선택해주세요.");
return false;
}
const isDelete = confirm(
"메뉴를 삭제하시겠습니까?\n삭제 시 하위부서 항목도 제거됩니다."
);
if (isDelete) {
const data = { menuId: this.selectedMenuId };
this.axiosDelete(data);
}
},
// 최상위 신규 객체 생성
fnTopAdd() {
this.editMode = true;
this.viewMenu = JSON.parse(JSON.stringify(this.newMenu));
this.selectedMenuId = this.viewMenu.deptId;
},
// 하위 신규 객체 생성
fnSubAdd() {
if (this.viewMenu.menuId == null) {
alert("상위 메뉴를 지정해주세요.");
return;
}
this.editMode = true;
const upMenuId = this.viewMenu.menuId;
const upMenuNm = this.viewMenu.menuNm;
this.viewMenu = JSON.parse(JSON.stringify(this.newMenu));
this.viewMenu.upMenuId = upMenuId;
this.viewMenu.upMenuNm = upMenuNm;
this.selectedMenuId = null;
},
// 메뉴관리 유효성 검사
valiadtion() {
// 메뉴명 입력 여부
if (this.viewMenu["menuNm"] == null || this.viewMenu["menuNm"] == "") {
alert("메뉴명을 입력하세요.");
this.$refs.menuNm.focus();
return false;
}
// 메뉴 타입 입력 여부
if (
this.viewMenu["menuTypeCd"] != null &&
this.viewMenu["menuTypeCd"] != ""
) {
if (
this.viewMenu["menuTypeCd"] == "bbs" ||
this.viewMenu["menuTypeCd"] == "conts"
) {
if (
this.viewMenu["menuTypeArtclId"] == null ||
this.viewMenu["menuTypeArtclId"] == ""
) {
alert("메뉴 타입 항목을 선택하세요.");
this.$refs.menuTypeCtgry.focus();
return false;
}
} else if (this.viewMenu["menuTypeCd"] == "link") {
if (
this.viewMenu["linkUrlAddr"] == null ||
this.viewMenu["linkUrlAddr"] == ""
) {
alert("링크 주소를 입력하세요.");
this.$refs.linkUrl.focus();
return false;
}
}
}
// 링크 유형
if (
this.viewMenu["linkTypeNm"] == null ||
this.viewMenu["linkTypeNm"] == ""
) {
alert("링크 유형을 선택하세요.");
return false;
}
// 메뉴 노출 여부
if (
this.viewMenu["menuExpsrYn"] == null ||
this.viewMenu["menuExpsrYn"] == ""
) {
alert("메뉴 노출 여부를 선택하세요.");
return false;
}
},
// axios: 등록
async axiosInsert(data) {
if(confirm(this.$getCmmnMessage('cnf003'))){
try {
this.$setLoading(true);
const res = await menuSave(data);
if (res.status == 200) {
alert(res.data.message);
this.fnViewList(); // 목록 새로고침
}
} catch (error) {
const errorData = error.response.data;
if (errorData.message != null && errorData.message != "") {
alert(error.response.data.message);
} else {
alert(this.$getCmmnMessage('err005'));
}
} finally {
this.$setLoading(false);
}
}
},
// axios: 조회(목록)
async axiosViewList() {
try {
this.$setLoading(true);
const res = await menuFindAll();
if (res.status == 200) {
this.menuList = res.data.data.hierachyList; // 메뉴 목록
this.codeList = res.data.data.codeList; // 메뉴 타입 목록
this.newMenu = res.data.data.newMenu; // 메뉴 빈 객체
this.newMenu.useYn = "Y";
this.newMenu.linkTypeNm = "0"; // 링크 유형
// this.newMenu.dgstfnExmnUseYn = "Y"; // 만족도 조사 사용 여부
this.newMenu.menuExpsrYn = "Y"; // 메뉴 노출 여부
this.newMenu.menuTypeCd = "";
this.newMenu.menuTypeArtclId = "";
this.newMenu.linkUrlAddr = "";
}
} catch (error) {
const errorData = error.response.data;
if (errorData.message != null && errorData.message != "") {
alert(error.response.data.message);
} else {
alert(this.$getCmmnMessage('err005'));
}
}finally{
this.$setLoading(false);
}
},
// axios: 조회(상세)
async axiosViewDetail(data) {
if (this.selectedMenuId == null) return;
try {
const res = await menuFindByMenu(data);
if (res.status == 200) {
this.editMode = true;
this.viewMenu = res.data.data; // 메뉴 정보
this.selectedMenuId = this.viewMenu.menuId;
if (this.viewMenu.menuTypeCd == null) {
this.viewMenu.menuTypeCd = "";
}
if (this.viewMenu.menuTypeCd == "bbs") {
this.ctgryList = this.bbsList;
} else if (this.viewMenu.menuTypeCd == "conts") {
this.ctgryList = this.contsTypeList;
}
}
} catch (error) {
const errorData = error.response.data;
if (errorData.message != null && errorData.message != "") {
alert(error.response.data.message);
} else {
alert(this.$getCmmnMessage('err005'));
}
}
},
// axios: 수정
async axiosUpdate(data) {
if(confirm(this.$getCmmnMessage('cnf004'))){
try {
this.$setLoading(true);
const res = await menuUpdate(data);
if (res.status == 200) {
alert(res.data.message);
this.fnViewList(); // 목록 새로고침
}
} catch (error) {
const errorData = error.response.data;
if (errorData.message != null && errorData.message != "") {
alert(error.response.data.message);
} else {
alert(this.$getCmmnMessage('err005'));
}
} finally{
this.$setLoading(false);
}
}
},
// axios: 삭제
async axiosDelete(data) {
try {
this.$setLoading(true);
const res = await menuDelete(data);
if (res.status == 200) {
this.fnViewList(); // 목록 새로고침
}
} catch (error) {
const errorData = error.response.data;
if (errorData.message != null && errorData.message != "") {
alert(error.response.data.message);
} else {
// alert("에러가 발생했습니다.\n관리자에게 문의해주세요.");
alert(this.$getCmmnMessage('err005'));
}
} finally {
this.$setLoading(false);
}
},
// axios: 조회(목록) - 게시판
async axiosBbsList() {
// 실행
try {
const res = await findAllByMenuMng();
if (res.status == 200) {
let items = [];
for (let item of res.data.data) {
items.push({
id: item["bbsMngId"],
name: item["bbsNm"],
});
}
this.bbsList = items;
}
} catch (error) {
const errorData = error.response.data;
if (errorData.message != null && errorData.message != "") {
alert(error.response.data.message);
} else {
// alert("에러가 발생했습니다.\n관리자에게 문의해주세요.");
alert(this.$getCmmnMessage('err005'));
}
}
},
// axios: 조회(목록) - 콘텐츠
async axiosContsTypeList() {
// 데이터 삽입
const data = { sysPvsnYn: "1" };
// 실행
try {
const res = await findAllByExpsr(data);
if (res.status == 200) {
let items = [];
for (let item of res.data.data) {
items.push({
id: item["contsId"],
name: item["contsKornNm"],
});
}
this.contsTypeList = items;
}
} catch (error) {
const errorData = error.response.data;
if (errorData.message != null && errorData.message != "") {
alert(error.response.data.message);
} else {
// alert("에러가 발생했습니다.\n관리자에게 문의해주세요.");
alert(this.$getCmmnMessage('err005'));
}
}
},
// 드래그앤드롭
// axios: 목록 수정
async fnListUpdate() {
try {
const res = await updateListProc(this.menuList);
alert(res.data.message);
if (res.status == 200) {
this.fnViewList(); // 목록 새로고침
}
} catch (error) {
alert(error.res.data.message);
}
},
},
watch: {
"viewMenu.menuTypeCd"() {
const menuType = this.viewMenu["menuTypeCd"];
// 초기화
this.ctgryList = [];
this.viewMenu["menuTypeArtclId"] == "";
this.viewMenu["linkUrlAddr"] == null;
// 데이터 삽입
if (menuType == "bbs") {
this.ctgryList = this.bbsList;
} else if (menuType == "conts") {
this.ctgryList = this.contsTypeList;
}
},
},
computed: {},
components: {
draggable: draggable,
Hierachy: Hierachy,
},
mounted() {},
};
</script>
<style scoped>
.tree-node {
height: 100%;
}
.ghost {
height: 15px;
color: transparent;
border: 1px dashed var(--blue);
}
.ghost * {
display: none;
}
</style>