
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
04-04
04-04
File name
Commit message
Commit date
04-04
04-04
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
<template>
<div class="content-zone sch-full">
<div class="content">
<div class="setting-box h_100">
<div class="node-zone">
<div class="tree">
<draggable tag="ul" class="tree-node" :list="menuList" :group="{ name: 'menu' }" item-key="id"
handle=".handle" ghost-class="ghost">
<template #item="{ element, index }">
<Hierachy :tasks="element" :icon="iconPath" :selectedNode="selectedMenuId" :isLastNode="element.childList && index === element.childList.length - 1"
@changeSelected="fnViewDetail" />
</template>
</draggable>
</div>
<div class="btn-zone" v-if="pageAuth.mdfcnAuthrt == 'Y'">
<button class="btn top sm secondary" @click="fnTopAdd">
TOP+
</button>
<button class="btn top sm secondary" @click="fnSubAdd">
SUB+
</button>
<button class="btn save sm" @click="fnListUpdate">
메뉴 저장
</button>
</div>
</div>
<div class="setting-zone">
<div class="form-box">
<div class="form-box-title">
<p>메뉴 정보</p>
</div>
<div class="form-content">
<div>
<label class="form-title">상위 메뉴명 </label>
<input type="text" class="form-control sm" v-model="viewMenu.upMenuNm" disabled />
</div>
<div>
<label class="form-title">메뉴명</label>
<input type="text" class="form-control sm" ref="menuNm" v-model="viewMenu.menuNm"
:disabled="!editMode" />
</div>
<div class="grid-column">
<label class="form-title">메뉴 설명</label>
<textarea v-model="viewMenu.menuExpln" :disabled="!editMode" class="form-control lg area"></textarea>
</div>
<div class="grid-column">
<label class="form-title">메뉴 타입</label>
<div class="input-group">
<select class="form-select sm" ref="menuType" v-model="viewMenu.menuType" :disabled="!editMode">
<option value="">선택</option>
<option v-for="(code, index) in codeList" :key="index" :value="code.cd">
{{ code.cdNm }}
</option>
</select>
<template v-if="viewMenu.menuType == 'bbs' ||
viewMenu.menuType == 'conts'
">
<select class="form-select sm" ref="menuTypeCtgry" v-model="viewMenu.menuTypeCtgry"
:disabled="!editMode">
<option value="">선택</option>
<option v-for="(ctgry, index) of ctgryList" :key="index" :value="ctgry.id">
{{ ctgry.name }}
</option>
</select>
</template>
<template v-if="viewMenu.menuType == 'link'">
<input type="text" class="form-control sm" ref="linkUrl" v-model="viewMenu.linkUrl"
:disabled="!editMode" :style="{ width: inputWidth + 'px' }"/>
</template>
</div>
</div>
<div>
<label class="form-title">메뉴 사용자</label>
<div class="check-area">
<div class="form-check">
<input type="radio" name="menuUser" id="menuUserAdm" v-model="viewMenu.menuUser"
value="A" :disabled="!editMode" />
<label for="menuUserAdm">관리자용</label>
</div>
<div class="form-check">
<input type="radio" name="menuUser" id="menuUserUser" v-model="viewMenu.menuUser"
value="U" :disabled="!editMode" />
<label for="menuUserUser">사용자용</label>
</div>
</div>
</div>
<div>
<label class="form-title">링크유형 </label>
<div class="check-area">
<div class="form-check">
<input type="radio" name="linkType" id="linkTypeY" v-model="viewMenu.linkType"
value="0" :disabled="!editMode" />
<label for="linkTypeY">현재창</label>
</div>
<div class="form-check">
<input type="radio" name="linkType" id="linkTypeN" v-model="viewMenu.linkType"
value="1" :disabled="!editMode" />
<label for="linkTypeN">새창</label>
</div>
</div>
</div>
<div class="gd-12 pr0">
<label for="" class="form-title">만족도 조사 사용 여부 </label>
<div class="check-area">
<div class="form-check">
<input type="radio" name="dgstfnExmnUseYn" id="dgstfnExmnUseY"
v-model="viewMenu.dgstfnExmnUseYn" value="Y" :disabled="!editMode" />
<label for="dgstfnExmnUseY">사용</label>
</div>
<div class="form-check">
<input type="radio" name="dgstfnExmnUseYn" id="dgstfnExmnUseN"
v-model="viewMenu.dgstfnExmnUseYn" value="N" :disabled="!editMode" />
<label for="dgstfnExmnUseN">미사용</label>
</div>
</div>
</div>
<div>
<label class="form-title">메뉴 노출 여부</label>
<div class="check-area">
<div class="form-check">
<input type="radio" name="menuExpsrYn" id="menuExpsrY"
v-model="viewMenu.menuExpsrYn" value="Y" :disabled="!editMode" />
<label for="menuExpsrY">사용</label>
</div>
<div class="form-check">
<input type="radio" name="menuExpsrYn" id="menuExpsrN"
v-model="viewMenu.menuExpsrYn" value="N" :disabled="!editMode" />
<label for="menuExpsrN">미사용</label>
</div>
</div>
</div>
<div>
<label class="form-title">등록자</label>
<input type="text" class="form-control sm" v-model="viewMenu.rgtrNm" disabled />
</div>
<div>
<label class="form-title">등록일</label>
<input type="text" class="form-control sm" v-model="viewMenu.regDt" disabled />
</div>
<div>
<label class="form-title">수정자</label>
<input type="text" class="form-control sm" v-model="viewMenu.mdfrNm" disabled />
</div>
<div>
<label class="form-title">수정일</label>
<input type="text" class="form-control sm" v-model="viewMenu.mdfcnDt" disabled />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="btn-wrap">
<button class="btn sm main" @click="fnInsert" :disabled="!editMode" v-if="
selectedMenuId != null &&
editMode == true &&
pageAuth.mdfcnAuthrt == 'Y'
">
수정
</button>
<button class="btn sm main" @click="fnInsert" :disabled="!editMode"
v-else-if="editMode == true && pageAuth.regAuthrt == 'Y'">
등록
</button>
<button :class="{
'btn sm red': true,
// 'red-border-btn': editMode,
}" :disabled="isFormDisabled" @click="fnDelete" v-if="pageAuth.delAuthrt == 'Y'">
삭제
</button>
</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: {
menuType: "",
menuTypeCtgry: "",
}, // 사용자에게 보여질 메뉴 목록
selectedMenuId: null, // 선택된 메뉴
codeList: [], // 메뉴 타입 목록
ctgryList: [], // 메뉴 타입 항목
bbsList: [], // 메뉴 타입 게시판 목록
contsTypeList: [], // 메뉴 타입 콘텐츠 목록
inputWidth: 0,
};
},
created() {
this.fnViewList();
this.axiosBbsList(); // 메뉴 타입 게시판 목록 조회
this.axiosContsTypeList(); // 메뉴 타입 콘텐츠 목록 조회
// pageId 확인
if (this.pageId != null) {
this.editMode = "true";
}
},
methods: {
// 등록
fnInsert() {
// 유효성검사
if (this.valiadtion() == false) {
return;
}
let data = this.viewMenu;
if (data["menuType"] == "") {
data.menuType = "";
data.menuTypeCtgry = "";
data.linkUrl = "";
} else if (data["menuType"] == "bbs" || data["menuType"] == "conts") {
data["linkUrl"] == null;
} else if (data["menuType"] == "link") {
data["menuTypeCtgry"] == 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;
}
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["menuType"] != null &&
this.viewMenu["menuType"] != ""
) {
if (
this.viewMenu["menuType"] == "bbs" ||
this.viewMenu["menuType"] == "conts"
) {
if (
this.viewMenu["menuTypeCtgry"] == null ||
this.viewMenu["menuTypeCtgry"] == ""
) {
alert("메뉴 타입 항목을 선택하세요.");
this.$refs.menuTypeCtgry.focus();
return false;
}
} else if (this.viewMenu["menuType"] == "link") {
if (
this.viewMenu["linkUrl"] == null ||
this.viewMenu["linkUrl"] == ""
) {
alert("링크 주소를 입력하세요.");
this.$refs.linkUrl.focus();
return false;
}
}
}
// 링크 유형
if (
this.viewMenu["linkType"] == null ||
this.viewMenu["linkType"] == ""
) {
alert("링크 유형을 선택하세요.");
return false;
}
// 만족도 조사 사용여부
if (
this.viewMenu["dgstfnExmnUseYn"] == null ||
this.viewMenu["dgstfnExmnUseYn"] == ""
) {
alert("만족도 조사 사용여부를 선택하세요.");
return false;
}
// 메뉴 노출 여부
if (
this.viewMenu["menuExpsrYn"] == null ||
this.viewMenu["menuExpsrYn"] == ""
) {
alert("메뉴 노출 여부를 선택하세요.");
return false;
}
},
// axios: 등록
async axiosInsert(data) {
try {
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("에러가 발생했습니다.\n관리자에게 문의해주세요.");
}
}
},
// axios: 조회(목록)
async axiosViewList() {
try {
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.linkType = "0"; // 링크 유형
this.newMenu.dgstfnExmnUseYn = "Y"; // 만족도 조사 사용 여부
this.newMenu.menuExpsrYn = "Y"; // 메뉴 노출 여부
this.newMenu.menuType = "";
this.newMenu.menuTypeCtgry = "";
this.newMenu.linkUrl = "";
this.newMenu.menuUser = "A"
}
} catch (error) {
const errorData = error.response.data;
if (errorData.message != null && errorData.message != "") {
alert(error.response.data.message);
} else {
alert("에러가 발생했습니다.\n관리자에게 문의해주세요.");
}
}
},
// 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.menuType == null) {
this.viewMenu.menuType = "";
}
if (this.viewMenu.menuType == "bbs") {
this.ctgryList = this.bbsList;
} else if (this.viewMenu.menuType == "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("에러가 발생했습니다.\n관리자에게 문의해주세요.");
}
}
},
// axios: 수정
async axiosUpdate(data) {
try {
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("에러가 발생했습니다.\n관리자에게 문의해주세요.");
}
}
},
// axios: 삭제
async axiosDelete(data) {
try {
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관리자에게 문의해주세요.");
}
}
},
// 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관리자에게 문의해주세요.");
}
}
},
// 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관리자에게 문의해주세요.");
}
}
},
// 드래그앤드롭
// 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);
}
},
updateInputWidth() {
this.$nextTick(() => {
const containerEl = this.$el; // 부모 컨테이너 전체 너비
const selectEl = this.$refs.menuType; // select 요소
if (containerEl && selectEl) {
const containerWidth = containerEl.clientWidth; // 부모 요소의 전체 너비 (100%)
const selectWidth = selectEl.offsetWidth; // select 요소의 실제 너비
const gap = 10; // 선택적으로 간격 조정
this.inputWidth = containerWidth - selectWidth - gap; // 전체에서 select 너비를 뺀 값 적용
}
});
},
},
watch: {
"viewMenu.menuType"() {
const menuType = this.viewMenu["menuType"];
// 초기화
this.ctgryList = [];
this.viewMenu["menuTypeCtgry"] == "";
this.viewMenu["linkUrl"] == null;
// 데이터 삽입
if (menuType == "bbs") {
this.ctgryList = this.bbsList;
} else if (menuType == "conts") {
this.ctgryList = this.contsTypeList;
}
},
},
computed: {},
components: {
draggable: draggable,
Hierachy: Hierachy,
},
mounted() {
this.updateInputWidth();
window.addEventListener("resize", this.updateInputWidth);
},
beforeUnmount() {
window.removeEventListener("resize", this.updateInputWidth);
},
};
</script>
<!-- <style scoped>
.tree-node {
height: 100%;
}
.ghost {
height: 15px;
color: transparent;
border: 1px dashed var(--blue);
}
.ghost * {
display: none;
}
</style> -->