어드민 메뉴 관리, 파티션 관리 추가

This commit is contained in:
Jeon
2023-07-20 10:23:08 +09:00
parent 1b0576a0a6
commit d26b7e28d2
23 changed files with 1858 additions and 4 deletions

View File

@@ -1914,6 +1914,32 @@ textarea:focus{
padding-top: 8px;
}
.contents .search_check input[type="checkbox"] {
display: none;
}
.contents .search_check input[type="checkbox"] + div > label:first-child {
width: 20px;
height: 30px;
display: block;
background: url(../images/icon-chk-n-square.png) no-repeat center/100% auto;
margin-right: 10px;
}
.contents .search_check input[type="checkbox"]:checked + div > label:first-child {
background: url(../images/icon-chk-square.png) no-repeat center/100% auto;
margin-right: 10px;
}
.contents .search_check .label_group {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
@keyframes spScaleAlpha {
0% {
opacity: 1;

View File

@@ -0,0 +1,292 @@
<template>
<!-- <div class="wrap bg-wrap"> -->
<div>
<div class="dimmed modal20" @click="ModalClose();"></div>
<div class="popup-wrap modal20">
<!-- 메뉴 등록 -->
<div class="popup modal20 popup_form">
<div class="pop-head">
<h3 class="pop-tit" v-if="popType == 'reg'">메뉴 등록</h3>
<h3 class="pop-tit" v-else>메뉴 수정</h3>
</div>
<table>
<tbody>
<tr>
<th>메뉴명</th>
<td>
<input type="text" placeholder="메뉴명 입력" v-model.trim="menuNm" ref="_menuNm">
</td>
</tr>
<tr>
<th>상위메뉴</th>
<td>
<div v:class="select_box">
<select name="" v-model="prntsMenuNo" ref="_prntsMenuNo" v-if="popType == 'reg'">
<option value="">선택</option>
<option v-for="(option, i) in menuCate" v-bind:value="option.menuNo" v-bind:key="i">
{{ option.menuNm }}
</option>
</select>
<select name="" v-model="prntsMenuNo" ref="_prntsMenuNo" disabled v-else>
<option value="">선택</option>
<option v-for="(option, i) in menuCate" v-bind:value="option.menuNo" v-bind:key="i">
{{ option.menuNm }}
</option>
</select>
</div>
</td>
</tr>
<tr>
<th>URL</th>
<td><input type="text" v-model.trim="menuUrl" ref="_menuUrl"></td>
</tr>
<tr v-if="popType == 'modi'">
<th>순번</th>
<td>
<select name="" v-model="menuOdrg" ref="_menuOdrg">
<option value="">선택</option>
<option v-for="i in maxMenuOdrg" v-bind:value="(i)" v-bind:key="i">
{{ (i) }}
</option>
</select>
</td>
</tr>
<tr>
<th class="center">상태</th>
<td>
<input type="radio" name="useYn" value="Y" id="popup_radio1" v-model="useYn" ref="_useYn">
<label for="popup_radio1">사용</label>
<input type="radio" name="useYn" value="N" id="popup_radio2" v-model="useYn">
<label for="popup_radio2">정지</label>
</td>
</tr>
<tr>
<th class="center">그룹</th>
<td><input type="text" placeholder="숫자만 입력" v-model.trim="autchkGrpno" @keypress="onlyNum" @input="onlyNum" maxlength="2"></td>
</tr>
</tbody>
</table>
<div class="popup-btn2">
<button class="btn-pcolor" @click="addMenu" v-if="popType == 'reg'">저장</button>
<button class="btn-pcolor" @click="modiMenu" v-else>수정</button>
<button class="btn-default" @click="ModalClose();">취소</button>
</div>
</div>
</div>
<common-modal ref="commmonSysModal"></common-modal>
</div>
</template>
<script>
import api from '@/service/api';
import sysMgtApi from "../service/sysMgtApi.js";
import commonModal from "../components/commonModal";
import {utils_mixin, chkPattern2} from '../service/mixins';
export default {
name: "menuPop",
mixins: [utils_mixin, chkPattern2],
data() {
return {
row: {},
menuNo: '',
menuNm: '',
menuUrl: '',
prntsMenuNo: '',
menuOdrg: '',
useYn: '',
autchkGrpno: '',
props: {},
menuCate: [],
maxMenuOdrg: 0,
popType: ''
}
},
components: {
commonModal
},
created() {
this.formReset();
},
methods: {
async ModalOpen(param) {
this.formReset();
this.popType = param.popType;
this.row.menuNo = param.menuNo;
var dimmed = document.getElementsByClassName('modal20');
for (var i = 0; i < dimmed.length; i++) {
dimmed[i].style.display = 'block';
}
try {
const response = await sysMgtApi.menuCate(this.row);
const result = response.data;
if (result != null && result.retCode == '0000') {
this.menuCate = result.data.list;
}
} catch(err){
this.row.title = '상위 메뉴 목록 조회 실패';
this.row.msg1 = err;
this.$parent.$refs.alertSysModalOpen.alertSysModalOpen(this.row);
return false;
}
if(this.popType == 'modi'){
this.getMenuDetail();
}
},
ModalClose() {
var dimmed = document.getElementsByClassName('modal20');
for (var i = 0; i < dimmed.length; i++) {
dimmed[i].style.display = 'none';
}
},
async getMenuDetail() {
try {
const response = await sysMgtApi.getMenuDetail(this.row);
const result = response.data;
if (result != null && result.retCode == '0000') {
this.maxMenuOdrg = result.data.data.maxMenuOdrg;
this.menuNm = result.data.data.menuNm;
this.menuNo = result.data.data.menuNo;
this.menuOdrg = result.data.data.menuOdrg;
this.prntsMenuNo = result.data.data.prntsMenuNo;
this.menuUrl = result.data.data.menuUrl;
this.useYn = result.data.data.useYn;
this.autchkGrpno = result.data.data.autchkGrpno;
}
} catch(err){
this.row.title = '상위 메뉴 목록 조회 실패';
this.row.msg1 = err;
this.$parent.$refs.alertSysModalOpen.alertSysModalOpen(this.row);
return false;
}
},
formReset() {
Object.assign(this.$data, this.$options.data());
},
doValidate() {
if (this.isNull(this.menuNm)) {
this.row.title = '메뉴 관리';
this.row.msg1 = '메뉴명을 입력해 주세요.';
this.$refs.commmonSysModal.alertSysModalOpen(this.row);
this.row.focusTaget = '1';
return false;
}
if (this.isNull(this.prntsMenuNo)) {
this.row.title = '메뉴 관리';
this.row.msg1 = '상위 메뉴를 선택해 주세요.';
this.$refs.commmonSysModal.alertSysModalOpen(this.row);
this.row.focusTaget = '2';
return false;
}
if (this.isNull(this.menuUrl)) {
this.row.title = '메뉴 관리';
this.row.msg1 = 'URL을 입력해 주세요.';
this.$refs.commmonSysModal.alertSysModalOpen(this.row);
this.row.focusTaget = '3';
return false;
}
if (this.popType == "modi" && this.isNull(this.menuOdrg)) {
this.row.title = '메뉴 관리';
this.row.msg1 = '순번를 선택해 주세요.';
this.$refs.commmonSysModal.alertSysModalOpen(this.row);
this.row.focusTaget = '4';
return false;
}
if (this.isNull(this.useYn)) {
this.row.title = '메뉴 관리';
this.row.msg1 = '사용 여부를 선택해 주세요.';
this.$refs.commmonSysModal.alertSysModalOpen(this.row);
this.row.focusTaget = '5';
return false;
}
return true;
},
async addMenu() {
if(this.doValidate()){
this.row.menuNm = this.menuNm;
this.row.prntsMenuNo = this.prntsMenuNo;
this.row.menuUrl = this.menuUrl;
this.row.useYn = this.useYn;
this.row.autchkGrpno = this.autchkGrpno;
try {
const response = await sysMgtApi.insertMenu(this.row);
const result = response.data;
if (result != null && result.retCode == '0000') {
this.ModalClose();
this.$parent.getMenuList();
}
} catch(err){
this.row.title = '메뉴 저장 실패';
this.row.msg1 = err;
this.$parent.$refs.alertSysModalOpen.alertSysModalOpen(this.row);
return false;
}
}
},
async modiMenu() {
if(this.doValidate()){
this.row.menuNo = this.menuNo;
this.row.menuNm = this.menuNm;
this.row.menuUrl = this.menuUrl;
this.row.menuOdrg = this.menuOdrg;
this.row.useYn = this.useYn;
this.row.autchkGrpno = this.autchkGrpno;
try {
const response = await sysMgtApi.updateMenu(this.row);
const result = response.data;
if (result != null && result.retCode == '0000') {
this.ModalClose();
this.$parent.getMenuList();
}
} catch(err){
this.row.title = '메뉴 저장 실패';
this.row.msg1 = err;
this.$parent.$refs.alertSysModalOpen.alertSysModalOpen(this.row);
return false;
}
}
},
checkFocus () {
if (this.row.focusTaget === '1') {
this.$refs._menuNm.focus();
} else if (this.row.focusTaget === '2') {
this.$refs._prntsMenuNo.focus();
}else if(this.row.focusTaget === '3'){
this.$refs._menuUrl.focus();
}else if(this.row.focusTaget === '4'){
this.$refs._menuOdrg.focus();
}else if(this.row.focusTaget === '5'){
this.$refs._useYn.focus();
}
}
}
}
</script>

View File

@@ -6,6 +6,8 @@ import BatchList from '../views/BatchList'
import BatchDetail from '../views/BatchDetail'
import NotiList from '../views/NotiList'
import WorkState from '../views/WorkState'
import PartitionList from '../views/PartitionList'
import MenuList from '../views/MenuList'
export default [
{
@@ -56,6 +58,18 @@ export default [
component: WorkState,
name: 'workState',
meta: { public: false }
},
{
path: '/sysMgt/partition',
component: PartitionList,
name: 'partitionList',
meta: { public: false }
},
{
path: '/sysMgt/menuList',
component: MenuList,
name: 'menuList',
meta: { public: false }
}
]

View File

@@ -97,6 +97,37 @@ const athMenuList = (params) => {
return httpClient.post('/api/v1/bo/sysMgt/selectAuthMemuListForAddAuth', params, { withCredentials: false })
}
const partitionCate = (params) => {
return httpClient.post('/api/v1/bo/sysMgt/partitionCate', params, { withCredentials: false })
}
const deletePartition = (params) => {
return httpClient.post('/api/v1/bo/sysMgt/deletePartition', params, { withCredentials: false })
}
const menuList = (params) => {
return httpClient.post('/api/v1/bo/sysMgt/menuList', params, { withCredentials: false })
}
const menuCate = (params) => {
return httpClient.post('/api/v1/bo/sysMgt/menuCate', params, { withCredentials: false })
}
const getMenuDetail = (params) => {
return httpClient.post('/api/v1/bo/sysMgt/menuDetail', params, { withCredentials: false })
}
const insertMenu = (params) => {
return httpClient.post('/api/v1/bo/sysMgt/insertMenu', params, { withCredentials: false })
}
const updateMenu = (params) => {
return httpClient.post('/api/v1/bo/sysMgt/updateMenu', params, { withCredentials: false })
}
const deleteMenu = (params) => {
return httpClient.post('/api/v1/bo/sysMgt/deleteMenu', params, { withCredentials: false })
}
export default {
insertAdmin,
@@ -119,5 +150,13 @@ export default {
notiList,
setWorkState,
svcCheckList,
athMenuList
athMenuList,
partitionCate,
deletePartition,
menuList,
menuCate,
getMenuDetail,
insertMenu,
updateMenu,
deleteMenu
}

View File

@@ -0,0 +1,195 @@
<template>
<div class="contents">
<div class="contents_wrap">
<div class="top_wrap">
<h3 class="title">메뉴 관리</h3>
<p class="breadcrumb">운영 관리 &gt; 메뉴 관리</p>
</div>
<div class="search_wrap">
<div class="select_box">
<label for="right" class="label">상위 메뉴 </label>
<select name="" id="right" v-model="params.searchText" @change="getMenuList">
<option value="">전체</option>
<option v-for="(option, i) in menuCate" v-bind:value="option.menuNo" v-bind:key="i">
{{ option.menuNm }}
</option>
</select>
</div>
</div>
<div class="info">
<div class="count">
<span>{{ totalCnt }}</span
>
</div>
<div class="button_group">
<button type="button" class="button blue add" @click="menuRegPopOpen">메뉴 추가</button>
</div>
</div>
<div class="table">
<table>
<colgroup>
<col width="10%" />
<col width="15%" />
<col width="15%" />
<col width="5%" />
<col width="5%" />
<col width="17%" />
<col width="5%" />
<col width="13%" />
<col width="15%" />
</colgroup>
<thead>
<tr>
<th>메뉴번호</th>
<th>메뉴명</th>
<th>상위 메뉴명</th>
<th>상태</th>
<th>그룹</th>
<th>URL</th>
<th>메뉴순번</th>
<th>등록일</th>
<th></th>
</tr>
</thead>
<tbody>
<tr v-for="(option, i) in list" v-bind:key="i">
<td>{{ option.menuNo }}</td>
<td>{{ option.menuNm }}</td>
<td>{{ option.prntsMenuNm }}</td>
<td>{{ option.useYn }}</td>
<td>{{ option.autchkGrpno }}</td>
<td>{{ option.menuUrl }}</td>
<td>{{ option.menuOdrg }}</td>
<td>{{ option.regDt }}</td>
<td class="two_btn_group">
<button type="button" class="button grey" @click="menuModiPopOpen(option.menuNo)">수정</button>
<button type="button" class="button white delete" @click="menuDelete(option.menuNo)">삭제</button>
</td>
</tr>
</tbody>
</table>
</div>
<menu-pop ref="menuModal"></menu-pop>
<common-modal ref="commmonModal"></common-modal>
</div>
</div>
</template>
<script>
import sysMgtApi from '../service/sysMgtApi.js';
import commonModal from '@/components/modal/commonModal';
import MenuPop from '../components/MenuPop';
export default {
name: 'menuList',
data() {
return {
row: {},
list: [],
menuCate: [],
totalCnt: '',
popParam:{},
params: {
searchText: '',
},
};
},
components: {
commonModal,
MenuPop
},
created() {},
destroyed() {},
mounted() {
this.setMenuCate();
this.getMenuList();
},
methods: {
async getMenuList() {
try {
const response = await sysMgtApi.menuList(this.params);
const result = response.data;
if (result != null && result.retCode == '0000') {
this.list = result.data.list;
this.totalCnt = result.data.list.length;
} else {
this.row.title = '메뉴 관리';
this.row.msg1 = '조회정보가 없습니다.';
this.$refs.commmonModal.alertModalOpen(this.row);
}
} catch (err) {
this.row.title = '메뉴 관리';
this.row.msg1 = '실패 하였습니다.'
this.$refs.commmonModal.alertModalOpen(this.row);
}
},
async setMenuCate() {
try {
const response = await sysMgtApi.menuCate(this.params);
const result = response.data;
if (result != null && result.retCode == '0000') {
this.menuCate = result.data.list;
}
} catch(err){
this.row.title = '상위 메뉴 목록 조회 실패';
this.row.msg1 = err;
this.$parent.$refs.commmonModal.alertModalOpen(this.row);
return false;
}
},
menuRegPopOpen: function () {
this.popParam.popType = 'reg';
this.$refs.menuModal.ModalOpen(this.popParam);
},
menuModiPopOpen: function (menuNo) {
this.popParam.popType = 'modi';
this.popParam.menuNo = menuNo;
this.$refs.menuModal.ModalOpen(this.popParam);
},
ModalOpen: function (target) {},
menuDelete(target) {
const obj = this.list.filter(e => { if(e.menuNo == target) return true; else return false});
if(obj.length < 1) {
this.row = {};
this.row.title = '메뉴 관리';
this.row.msg1 = '삭제 대상이 없습니다.';
this.$refs.commmonModal.alertModalOpen(this.row);
}else{
this.row.menuNo = target;
this.row.title = '메뉴 관리';
this.row.msg1 = obj[0].menuNm + ' 메뉴를 삭제 하시겠습니까?';
this.$refs.commmonModal.confirmModalOpen2(this.row);
}
},
async deleteMenu() {
try {
let response = await sysMgtApi.deleteMenu(this.row);
const result = response.data;
if (result != null && result.retCode == '0000') {
this.getMenuList();
return;
} else {
this.row = {};
this.row.title = '메뉴 관리';
this.row.msg1 = '실패 하였습니다.';
this.$refs.commmonModal.alertModalOpen(this.row);
}
} catch (err) {
this.row = {};
this.row.title = '메뉴 관리';
this.row.msg1 = '실패 하였습니다.';
this.$refs.commmonModal.alertModalOpen(this.row);
}
},
confirmCalbackFnc(props) {
if (props.result) {
this.deleteMenu();
}
},
},
};
</script>

View File

@@ -0,0 +1,219 @@
<template>
<div class="contents">
<div class="contents_wrap">
<div class="top_wrap">
<h3 class="title">파티션 관리</h3>
<p class="breadcrumb">운영 관리 &gt; 파티션 관리</p>
</div>
<div class="search_wrap">
<div class="select_box">
<label for="right" class="label">테이블 </label>
<select name="" id="right" v-model="searchText" @change="search">
<option value="">전체</option>
<option v-for="(option, i) in partitionCate" v-bind:value="option.tableName" v-bind:key="i">
{{ option.tableName }}
</option>
</select>
</div>
<div class="search_check">
<input type="checkbox" id="right_check" value="Y" v-model="deleteListView" @change="search"/>
<div class="label_group">
<label for="right_check"></label>
<label for="right_check">삭제 대상 목록</label>
</div>
</div>
</div>
<div class="info">
<div class="count">
<span>{{ totalItems.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') }}</span
>
<div class="select_box NumberSe">
<select name="" id="perpage" v-model="perPageCnt" @change="changePerPage()">
<option v-for="option in options" v-bind:value="option.value" v-bind:key="option.value">
{{ option.text }}
</option>
</select>
</div>
</div>
<div class="title" v-if="deleteListView">
3년 경과 삭제 대상 파티션 목록(주의 삭제 복구 불가능)
</div>
<div class="button_group">
<button type="button" class="button white delete del" @click="rowDelete()" v-if="deleteListView">삭제</button>
</div>
</div>
<div class="table">
<custom-grid
ref="table"
:totalItems="'totalItems'"
:url="grid.url"
:pagePerRows="grid.pagePerRows"
:initialRequest="grid.initialRequest"
:pagination="grid.pagination"
:isCheckbox="grid.isCheckbox"
:columns="grid.columns"
:noDataStr="grid.noDataStr"
:addCls="grid.addCls"
:header="grid.headder"
></custom-grid>
</div>
<common-modal ref="commmonModal"></common-modal>
</div>
</div>
</template>
<script>
import customGrid from '@/components/CustomGrid';
import commonModal from '@/components/modal/commonModal';
import sysMgtApi from '../service/sysMgtApi.js';
export default {
name: 'partitionList',
data() {
return {
isFocused: false,
row: {},
totalItems: 0,
// 테이블 리스트 데이터
perPageCnt: 50,
options: [
{ text: '20', value: 20 },
{ text: '50', value: 50 },
{ text: '100', value: 100 },
],
partitionCate: [],
searchText: '',
deleteListView:false,
grid: {
url: '/api/v1/bo/sysMgt/partitionList',
pagePerRows: 50,
pagination: true,
isCheckbox: true, // true:첫번째 컬럼 앞에 체크박스 생성 / false:체크박스 제거
initialRequest: false,
addCls: 'box_OFvis',
columns: [
{ name: 'no', header: 'No', align: 'center', width: '6%' },
{ name: 'tableName', header: '테이블명', align: 'center', width: '25%' },
{ name: 'partitionName', header: '파티션명', align: 'center', width: '30%' },
{ name: 'partitionExp', header: '분할비교대상', align: 'center', width: '15%' },
{ name: 'partitionDesc', header: '분할비교대값', align: 'center', width: '20%' },
{ name: 'partitionOrdPos', header: '분할순번', align: 'center', width: '10%' },
],
noDataStr: '검색 결과가 없습니다.',
params: {
searchText: '',
},
excelHeader: [],
},
};
},
components: {
customGrid: customGrid,
commonModal
},
created() {
},
destroyed() {},
mounted() {
this.setPartitionCate();
let page = 1;
// 페이지 정보 및 검색 조건
const getCondition = this.$store.getters['searchcondition/getSearchCondition'];
// store에 저장된 페이지 정보 및 검색 조건을 불러오기
let isKeep = false;
/*
if (getCondition) {
this.grid.pagePerRows = getCondition.perPage;
this.grid.params = getCondition.params;
page = getCondition.page;
isKeep = true;
}
*/
this.grid.pagePerRows = 50;
page = 1;
this.search(isKeep);
},
methods: {
search: function (isKeep) {
this.grid.params.searchText = this.searchText;
this.grid.params.deleteListView = this.deleteListView;
this.$refs.table.search(this.grid.params, isKeep);
this.sendStoreData();
},
sendStoreData: function () {
const getP = this.$refs.table.getPagination();
this.$store.commit('searchcondition/updateSearchCondition', {
page: getP._currentPage,
perPage: this.perPageCnt,
params: this.grid.params,
});
const getCondition = this.$store.getters['searchcondition/getSearchCondition'];
},
async setPartitionCate() {
try {
const response = await sysMgtApi.partitionCate(this.params);
const result = response.data;
if (result != null && result.retCode == '0000') {
this.partitionCate = result.data.list;
}
} catch(err){
this.row.title = '파티션 목록 조회 실패';
this.row.msg1 = err;
this.$parent.$refs.commmonModal.alertModalOpen(this.row);
return false;
}
},
rowDelete() {
var chkList = this.$refs.table.checkedElementDatas();
if (chkList.length == 0) {
this.row.title = '파티션 관리';
this.row.msg1 = '삭제대상을 체크 해주세요.';
this.$refs.commmonModal.alertModalOpen(this.row);
return false;
}else{
const param = chkList.map((row) => ({ partitionName: row.partitionName, tableName: row.tableName }));
this.row.list = param;
this.row.title = '파티션 관리';
this.row.msg1 = '삭제 하시겠습니까?';
this.$refs.commmonModal.confirmModalOpen2(this.row);
}
},
async deleteRow() {
try {
let response = await sysMgtApi.deletePartition(this.row);
const result = response.data;
if (result != null && result.retCode == '0000') {
this.$refs.table.reloadData();
return;
}
this.row.title = '파티션 관리';
this.row.msg1 = '실패 하였습니다.';
this.$refs.commmonModal.alertModalOpen(this.row);
} catch (err) {
this.row.title = '파티션 관리';
this.row.msg1 = '실패 하였습니다.';
this.$refs.commmonModal.alertModalOpen(this.row);
}
},
confirmCalbackFnc(props) {
if (props.result) {
this.deleteRow();
}
},
changePerPage: function () {
// 페이지당 조회할 개수
this.grid.pagePerRows = this.perPageCnt;
}
}
};
</script>

View File

@@ -177,6 +177,8 @@ router.beforeEach((to, from, next) => {
nextUrl == '/sysMgt/authAdd' ||
nextUrl == '/sysMgt/authModify' ||
nextUrl == '/sysMgt/authModify' ||
nextUrl == '/sysMgt/partition' ||
nextUrl == '/sysMgt/menuList' ||
nextUrl.indexOf('/sysMgt/batchDetail') > -1
) {
for (var i = 0; i < menuUrls.length; i++) {